FFmpeg  4.3.8
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, flags = 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)
62 
63  if ((ret = ff_reget_buffer(avctx, s->prev_frame, flags)) < 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 (!avctx->frame_number) {
161  ptrdiff_t linesize[4] = { s->prev_frame->linesize[0], 0, 0, 0 };
162  av_image_fill_black(s->prev_frame->data, linesize, avctx->pix_fmt, 0,
163  avctx->width, avctx->height);
164  }
165 
166  for (int block = 0; block < blocks; block++) {
167  int x, y, w, h;
168 
169  x = bytestream2_get_le16(&gb);
170  y = bytestream2_get_le16(&gb);
171  w = bytestream2_get_le16(&gb);
172  h = bytestream2_get_le16(&gb);
173 
174  if (blocks == 1 && x == 0 && y == 0 && w == avctx->width && h == avctx->height)
175  intra = 1;
176 
177  if (x + w > avctx->width || y + h > avctx->height)
178  return AVERROR_INVALIDDATA;
179 
180  if (w > avctx->width || h > avctx->height)
181  return AVERROR_INVALIDDATA;
182 
183  dst = s->prev_frame->data[0] + (avctx->height - y - 1) * s->prev_frame->linesize[0] + x * bpp;
184  for (int i = 0; i < h; i++) {
185  s->zstream.next_out = dst;
186  s->zstream.avail_out = w * bpp;
187 
188  zret = inflate(&s->zstream, Z_SYNC_FLUSH);
189  if (zret != Z_OK && zret != Z_STREAM_END) {
190  av_log(avctx, AV_LOG_ERROR,
191  "Inflate failed with return code: %d.\n", zret);
192  return AVERROR_INVALIDDATA;
193  }
194 
195  dst -= s->prev_frame->linesize[0];
196  }
197  }
198 
199  s->prev_frame->key_frame = intra;
201 
202  if ((ret = av_frame_ref(frame, s->prev_frame)) < 0)
203  return ret;
204 
205  *got_frame = 1;
206 
207  return avpkt->size;
208 }
209 
211 {
212  WCMVContext *s = avctx->priv_data;
213  int zret;
214 
215  switch (avctx->bits_per_coded_sample) {
216  case 16: avctx->pix_fmt = AV_PIX_FMT_RGB565LE; break;
217  case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break;
218  case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA; break;
219  default: av_log(avctx, AV_LOG_ERROR, "Unsupported bits_per_coded_sample: %d\n",
220  avctx->bits_per_coded_sample);
221  return AVERROR_PATCHWELCOME;
222  }
223 
224  s->bpp = avctx->bits_per_coded_sample >> 3;
225 
226  s->zstream.zalloc = Z_NULL;
227  s->zstream.zfree = Z_NULL;
228  s->zstream.opaque = Z_NULL;
229  zret = inflateInit(&s->zstream);
230  if (zret != Z_OK) {
231  av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret);
232  return AVERROR_EXTERNAL;
233  }
234 
235  s->prev_frame = av_frame_alloc();
236  if (!s->prev_frame)
237  return AVERROR(ENOMEM);
238 
239  return 0;
240 }
241 
243 {
244  WCMVContext *s = avctx->priv_data;
245 
247  inflateEnd(&s->zstream);
248 
249  return 0;
250 }
251 
253  .name = "wcmv",
254  .long_name = NULL_IF_CONFIG_SMALL("WinCAM Motion Video"),
255  .type = AVMEDIA_TYPE_VIDEO,
256  .id = AV_CODEC_ID_WCMV,
257  .priv_data_size = sizeof(WCMVContext),
258  .init = decode_init,
259  .close = decode_close,
260  .decode = decode_frame,
261  .capabilities = AV_CODEC_CAP_DR1,
262  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
264 };
#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:300
misc image utilities
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int size
Definition: packet.h:356
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:736
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
AVCodec.
Definition: codec.h:190
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:71
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
Definition: pixfmt.h:106
AVCodec ff_wcmv_decoder
Definition: wcmv.c:252
static int16_t block[64]
Definition: dct.c:115
static av_cold int decode_close(AVCodecContext *avctx)
Definition: wcmv.c:242
#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:88
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
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:444
static AVFrame * frame
const char data[16]
Definition: mxf.c:91
uint8_t * data
Definition: packet.h:355
#define FF_REGET_BUFFER_FLAG_READONLY
the returned buffer does not need to be writable
Definition: internal.h:291
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:1750
#define av_log(a,...)
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:154
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
#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:203
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:188
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Identical in function to ff_get_buffer(), except it reuses the existing buffer if available...
Definition: decode.c:1961
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
uint8_t block_data[65536 *8]
Definition: wcmv.c:39
const char * name
Name of the codec implementation.
Definition: codec.h:197
int bpp
Definition: wcmv.c:36
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:383
int width
picture width / height.
Definition: avcodec.h:699
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:210
#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:331
main external API structure.
Definition: avcodec.h:526
long long int64_t
Definition: coverity.c:34
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:198
AVFrame * prev_frame
Definition: wcmv.c:38
#define flags(name, subs,...)
Definition: cbs_av1.c:576
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:314
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:553
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:534
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:378
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:208
int frame_number
Frame counter, set by libavcodec.
Definition: avcodec.h:1217
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: packet.h:332
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:50
for(j=16;j >0;--j)
Predicted.
Definition: avutil.h:275