FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 
60  if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
61  return ret;
62 
63  if (s->prev_frame->data[0]) {
64  ret = av_frame_copy(frame, s->prev_frame);
65  if (ret < 0)
66  return ret;
67  } else {
68  ptrdiff_t linesize[4] = { frame->linesize[0], 0, 0, 0 };
69  av_image_fill_black(frame->data, linesize, avctx->pix_fmt, 0,
70  avctx->width, avctx->height);
71  }
72 
73  blocks = bytestream2_get_le16(&gb);
74  if (blocks > 5) {
75  GetByteContext bgb;
76  int x = 0, size;
77 
78  if (blocks * 8 >= 0xFFFF)
79  size = bytestream2_get_le24(&gb);
80  else if (blocks * 8 >= 0xFF)
81  size = bytestream2_get_le16(&gb);
82  else
83  size = bytestream2_get_byte(&gb);
84 
85  skip = bytestream2_tell(&gb);
86  if (size > avpkt->size - skip)
87  return AVERROR_INVALIDDATA;
88 
89  s->zstream.next_in = avpkt->data + skip;
90  s->zstream.avail_in = size;
91  s->zstream.next_out = s->block_data;
92  s->zstream.avail_out = sizeof(s->block_data);
93 
94  zret = inflate(&s->zstream, Z_FINISH);
95  if (zret != Z_STREAM_END) {
96  av_log(avctx, AV_LOG_ERROR,
97  "Inflate failed with return code: %d.\n", zret);
98  return AVERROR_INVALIDDATA;
99  }
100 
101  ret = inflateReset(&s->zstream);
102  if (ret != Z_OK) {
103  av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
104  return AVERROR_EXTERNAL;
105  }
106 
107  bytestream2_skip(&gb, size);
108  bytestream2_init(&bgb, s->block_data, blocks * 8);
109 
110  for (int i = 0; i < blocks; i++) {
111  int w, h;
112 
113  bytestream2_skip(&bgb, 4);
114  w = bytestream2_get_le16(&bgb);
115  h = bytestream2_get_le16(&bgb);
116  if (x + bpp * (int64_t)w * h > INT_MAX)
117  return AVERROR_INVALIDDATA;
118  x += bpp * w * h;
119  }
120 
121  if (x >= 0xFFFF)
122  bytestream2_skip(&gb, 3);
123  else if (x >= 0xFF)
124  bytestream2_skip(&gb, 2);
125  else
126  bytestream2_skip(&gb, 1);
127 
128  skip = bytestream2_tell(&gb);
129 
130  s->zstream.next_in = avpkt->data + skip;
131  s->zstream.avail_in = avpkt->size - skip;
132 
133  bytestream2_init(&gb, s->block_data, blocks * 8);
134  } else if (blocks) {
135  int x = 0;
136 
137  bytestream2_seek(&gb, 2, SEEK_SET);
138 
139  for (int i = 0; i < blocks; i++) {
140  int w, h;
141 
142  bytestream2_skip(&gb, 4);
143  w = bytestream2_get_le16(&gb);
144  h = bytestream2_get_le16(&gb);
145  if (x + bpp * (int64_t)w * h > INT_MAX)
146  return AVERROR_INVALIDDATA;
147  x += bpp * w * h;
148  }
149 
150  if (x >= 0xFFFF)
151  bytestream2_skip(&gb, 3);
152  else if (x >= 0xFF)
153  bytestream2_skip(&gb, 2);
154  else
155  bytestream2_skip(&gb, 1);
156 
157  skip = bytestream2_tell(&gb);
158 
159  s->zstream.next_in = avpkt->data + skip;
160  s->zstream.avail_in = avpkt->size - skip;
161 
162  bytestream2_seek(&gb, 2, SEEK_SET);
163  }
164 
165  for (int block = 0; block < blocks; block++) {
166  int x, y, w, h;
167 
168  x = bytestream2_get_le16(&gb);
169  y = bytestream2_get_le16(&gb);
170  w = bytestream2_get_le16(&gb);
171  h = bytestream2_get_le16(&gb);
172 
173  if (blocks == 1 && x == 0 && y == 0 && w == avctx->width && h == avctx->height)
174  intra = 1;
175 
176  if (x + w > avctx->width || y + h > avctx->height)
177  return AVERROR_INVALIDDATA;
178 
179  if (w > avctx->width || h > avctx->height)
180  return AVERROR_INVALIDDATA;
181 
182  dst = frame->data[0] + (avctx->height - y - 1) * frame->linesize[0] + x * bpp;
183  for (int i = 0; i < h; i++) {
184  s->zstream.next_out = dst;
185  s->zstream.avail_out = w * bpp;
186 
187  zret = inflate(&s->zstream, Z_SYNC_FLUSH);
188  if (zret != Z_OK && zret != Z_STREAM_END) {
189  av_log(avctx, AV_LOG_ERROR,
190  "Inflate failed with return code: %d.\n", zret);
191  return AVERROR_INVALIDDATA;
192  }
193 
194  dst -= frame->linesize[0];
195  }
196  }
197 
198  frame->key_frame = intra;
199  frame->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
200 
202  if ((ret = av_frame_ref(s->prev_frame, 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
This structure describes decoded (raw) audio or video data.
Definition: frame.h:226
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
misc image utilities
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int size
Definition: avcodec.h:1446
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1743
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
AVCodec.
Definition: avcodec.h:3424
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: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: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
uint8_t * data
Definition: avcodec.h:1445
static void inflate(uint8_t *dst, const uint8_t *p1, int width, int threshold, const uint8_t *coordinates[], int coord)
Definition: vf_neighbor.c:189
ptrdiff_t size
Definition: opengl_enc.c:101
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:2750
#define av_log(a,...)
#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
const char * name
Name of the codec implementation.
Definition: avcodec.h:3431
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:309
int width
picture width / height.
Definition: avcodec.h:1706
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:257
main external API structure.
Definition: avcodec.h:1533
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1918
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:240
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:1560
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:552
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:304
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:1422
#define AV_GET_BUFFER_FLAG_REF
The decoder will keep a reference to the frame and may reuse it later.
Definition: avcodec.h:1144
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:968
for(j=16;j >0;--j)
Predicted.
Definition: avutil.h:275