FFmpeg  4.2.2
wcmv.c
Go to the documentation of this file.
1 /*
2  * WinCAM Motion Video decoder
3  *
4  * Copyright (c) 2018 Paul B Mahol
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "libavutil/imgutils.h"
28 
29 #include "avcodec.h"
30 #include "bytestream.h"
31 #include "internal.h"
32 
33 #include <zlib.h>
34 
35 typedef struct WCMVContext {
36  int bpp;
37  z_stream zstream;
39  uint8_t block_data[65536*8];
40 } WCMVContext;
41 
42 static int decode_frame(AVCodecContext *avctx,
43  void *data, int *got_frame,
44  AVPacket *avpkt)
45 {
46  WCMVContext *s = avctx->priv_data;
47  AVFrame *frame = data;
48  int skip, blocks, zret, ret, intra = 0, bpp = s->bpp;
49  GetByteContext gb;
50  uint8_t *dst;
51 
52  ret = inflateReset(&s->zstream);
53  if (ret != Z_OK) {
54  av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
55  return AVERROR_EXTERNAL;
56  }
57 
58  bytestream2_init(&gb, avpkt->data, avpkt->size);
59  blocks = bytestream2_get_le16(&gb);
60  if (!blocks)
61  return avpkt->size;
62 
63  if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
64  return ret;
65 
66  if (blocks > 5) {
67  GetByteContext bgb;
68  int x = 0, size;
69 
70  if (blocks * 8 >= 0xFFFF)
71  size = bytestream2_get_le24(&gb);
72  else if (blocks * 8 >= 0xFF)
73  size = bytestream2_get_le16(&gb);
74  else
75  size = bytestream2_get_byte(&gb);
76 
77  skip = bytestream2_tell(&gb);
78  if (size > avpkt->size - skip)
79  return AVERROR_INVALIDDATA;
80 
81  s->zstream.next_in = avpkt->data + skip;
82  s->zstream.avail_in = size;
83  s->zstream.next_out = s->block_data;
84  s->zstream.avail_out = sizeof(s->block_data);
85 
86  zret = inflate(&s->zstream, Z_FINISH);
87  if (zret != Z_STREAM_END) {
88  av_log(avctx, AV_LOG_ERROR,
89  "Inflate failed with return code: %d.\n", zret);
90  return AVERROR_INVALIDDATA;
91  }
92 
93  ret = inflateReset(&s->zstream);
94  if (ret != Z_OK) {
95  av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
96  return AVERROR_EXTERNAL;
97  }
98 
99  bytestream2_skip(&gb, size);
100  bytestream2_init(&bgb, s->block_data, blocks * 8);
101 
102  for (int i = 0; i < blocks; i++) {
103  int w, h;
104 
105  bytestream2_skip(&bgb, 4);
106  w = bytestream2_get_le16(&bgb);
107  h = bytestream2_get_le16(&bgb);
108  if (x + bpp * (int64_t)w * h > INT_MAX)
109  return AVERROR_INVALIDDATA;
110  x += bpp * w * h;
111  }
112 
113  if (x >= 0xFFFF)
114  bytestream2_skip(&gb, 3);
115  else if (x >= 0xFF)
116  bytestream2_skip(&gb, 2);
117  else
118  bytestream2_skip(&gb, 1);
119 
120  skip = bytestream2_tell(&gb);
121 
122  s->zstream.next_in = avpkt->data + skip;
123  s->zstream.avail_in = avpkt->size - skip;
124 
125  bytestream2_init(&gb, s->block_data, blocks * 8);
126  } else if (blocks) {
127  int x = 0;
128 
129  bytestream2_seek(&gb, 2, SEEK_SET);
130 
131  for (int i = 0; i < blocks; i++) {
132  int w, h;
133 
134  bytestream2_skip(&gb, 4);
135  w = bytestream2_get_le16(&gb);
136  h = bytestream2_get_le16(&gb);
137  if (x + bpp * (int64_t)w * h > INT_MAX)
138  return AVERROR_INVALIDDATA;
139  x += bpp * w * h;
140  }
141 
142  if (x >= 0xFFFF)
143  bytestream2_skip(&gb, 3);
144  else if (x >= 0xFF)
145  bytestream2_skip(&gb, 2);
146  else
147  bytestream2_skip(&gb, 1);
148 
149  skip = bytestream2_tell(&gb);
150 
151  s->zstream.next_in = avpkt->data + skip;
152  s->zstream.avail_in = avpkt->size - skip;
153 
154  bytestream2_seek(&gb, 2, SEEK_SET);
155  }
156 
157  if (bytestream2_get_bytes_left(&gb) < 8LL * blocks)
158  return AVERROR_INVALIDDATA;
159 
160  if (s->prev_frame->data[0]) {
161  ret = av_frame_copy(frame, s->prev_frame);
162  if (ret < 0)
163  return ret;
164  } else {
165  ptrdiff_t linesize[4] = { frame->linesize[0], 0, 0, 0 };
166  av_image_fill_black(frame->data, linesize, avctx->pix_fmt, 0,
167  avctx->width, avctx->height);
168  }
169 
170  for (int block = 0; block < blocks; block++) {
171  int x, y, w, h;
172 
173  x = bytestream2_get_le16(&gb);
174  y = bytestream2_get_le16(&gb);
175  w = bytestream2_get_le16(&gb);
176  h = bytestream2_get_le16(&gb);
177 
178  if (blocks == 1 && x == 0 && y == 0 && w == avctx->width && h == avctx->height)
179  intra = 1;
180 
181  if (x + w > avctx->width || y + h > avctx->height)
182  return AVERROR_INVALIDDATA;
183 
184  if (w > avctx->width || h > avctx->height)
185  return AVERROR_INVALIDDATA;
186 
187  dst = frame->data[0] + (avctx->height - y - 1) * frame->linesize[0] + x * bpp;
188  for (int i = 0; i < h; i++) {
189  s->zstream.next_out = dst;
190  s->zstream.avail_out = w * bpp;
191 
192  zret = inflate(&s->zstream, Z_SYNC_FLUSH);
193  if (zret != Z_OK && zret != Z_STREAM_END) {
194  av_log(avctx, AV_LOG_ERROR,
195  "Inflate failed with return code: %d.\n", zret);
196  return AVERROR_INVALIDDATA;
197  }
198 
199  dst -= frame->linesize[0];
200  }
201  }
202 
203  frame->key_frame = intra;
204  frame->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
205 
207  if ((ret = av_frame_ref(s->prev_frame, frame)) < 0)
208  return ret;
209 
210  *got_frame = 1;
211 
212  return avpkt->size;
213 }
214 
216 {
217  WCMVContext *s = avctx->priv_data;
218  int zret;
219 
220  switch (avctx->bits_per_coded_sample) {
221  case 16: avctx->pix_fmt = AV_PIX_FMT_RGB565LE; break;
222  case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break;
223  case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA; break;
224  default: av_log(avctx, AV_LOG_ERROR, "Unsupported bits_per_coded_sample: %d\n",
225  avctx->bits_per_coded_sample);
226  return AVERROR_PATCHWELCOME;
227  }
228 
229  s->bpp = avctx->bits_per_coded_sample >> 3;
230 
231  s->zstream.zalloc = Z_NULL;
232  s->zstream.zfree = Z_NULL;
233  s->zstream.opaque = Z_NULL;
234  zret = inflateInit(&s->zstream);
235  if (zret != Z_OK) {
236  av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
237  return AVERROR_EXTERNAL;
238  }
239 
240  s->prev_frame = av_frame_alloc();
241  if (!s->prev_frame)
242  return AVERROR(ENOMEM);
243 
244  return 0;
245 }
246 
248 {
249  WCMVContext *s = avctx->priv_data;
250 
252  inflateEnd(&s->zstream);
253 
254  return 0;
255 }
256 
258  .name = "wcmv",
259  .long_name = NULL_IF_CONFIG_SMALL("WinCAM Motion Video"),
260  .type = AVMEDIA_TYPE_VIDEO,
261  .id = AV_CODEC_ID_WCMV,
262  .priv_data_size = sizeof(WCMVContext),
263  .init = decode_init,
264  .close = decode_close,
265  .decode = decode_frame,
266  .capabilities = AV_CODEC_CAP_DR1,
267  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
269 };
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
Definition: internal.h:48
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int size
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
misc image utilities
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int size
Definition: avcodec.h:1478
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1775
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
AVCodec.
Definition: avcodec.h:3481
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:42
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
Definition: pixfmt.h:106
AVCodec ff_wcmv_decoder
Definition: wcmv.c:257
static int16_t block[64]
Definition: dct.c:115
static av_cold int decode_close(AVCodecContext *avctx)
Definition: wcmv.c:247
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: internal.h:40
uint8_t
#define av_cold
Definition: attributes.h:82
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition: frame.c:443
static AVFrame * frame
const char data[16]
Definition: mxf.c:91
uint8_t * data
Definition: avcodec.h:1477
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:2789
#define av_log(a,...)
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AVERROR(e)
Definition: error.h:43
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
uint8_t block_data[65536 *8]
Definition: wcmv.c:39
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
const char * name
Name of the codec implementation.
Definition: avcodec.h:3488
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition: frame.c:792
int bpp
Definition: wcmv.c:36
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:378
int width
picture width / height.
Definition: avcodec.h:1738
uint8_t w
Definition: llviddspenc.c:38
#define s(width, name)
Definition: cbs_vp9.c:257
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
static av_cold int decode_init(AVCodecContext *avctx)
Definition: wcmv.c:215
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:188
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
main external API structure.
Definition: avcodec.h:1565
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1964
static void inflate(uint8_t *dst, const uint8_t *p1, int width, int threshold, const uint8_t *coordinates[], int coord, int maxc)
Definition: vf_neighbor.c:197
AVFrame * prev_frame
Definition: wcmv.c:38
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:553
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
common internal api header.
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: wcmv.c:42
void * priv_data
Definition: avcodec.h:1592
int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4], enum AVPixelFormat pix_fmt, enum AVColorRange range, int width, int height)
Overwrite the image data with black.
Definition: imgutils.c:535
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:373
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:208
z_stream zstream
Definition: wcmv.c:37
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
This structure stores compressed data.
Definition: avcodec.h:1454
#define AV_GET_BUFFER_FLAG_REF
The decoder will keep a reference to the frame and may reuse it later.
Definition: avcodec.h:1176
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:981
for(j=16;j >0;--j)
Predicted.
Definition: avutil.h:275