FFmpeg
msvideo1.c
Go to the documentation of this file.
1 /*
2  * Microsoft Video-1 Decoder
3  * Copyright (C) 2003 The FFmpeg project
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * Microsoft Video-1 Decoder by Mike Melanson (melanson@pcisys.net)
25  * For more information about the MS Video-1 format, visit:
26  * http://www.pcisys.net/~melanson/codecs/
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "libavutil/internal.h"
34 #include "libavutil/intreadwrite.h"
35 #include "avcodec.h"
36 #include "codec_internal.h"
37 #include "decode.h"
38 #include "internal.h"
39 
40 #define PALETTE_COUNT 256
41 #define CHECK_STREAM_PTR(n) \
42  if ((stream_ptr + n) > s->size ) { \
43  av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \
44  stream_ptr + n, s->size); \
45  return; \
46  }
47 
48 typedef struct Msvideo1Context {
49 
52 
53  const unsigned char *buf;
54  int size;
55 
56  int mode_8bit; /* if it's not 8-bit, it's 16-bit */
57 
58  uint32_t pal[256];
60 
62 {
63  Msvideo1Context *s = avctx->priv_data;
64 
65  s->avctx = avctx;
66 
67  if (avctx->width < 4 || avctx->height < 4)
68  return AVERROR_INVALIDDATA;
69 
70  /* figure out the colorspace based on the presence of a palette */
71  if (s->avctx->bits_per_coded_sample == 8) {
72  s->mode_8bit = 1;
73  avctx->pix_fmt = AV_PIX_FMT_PAL8;
74  if (avctx->extradata_size >= AVPALETTE_SIZE)
75  memcpy(s->pal, avctx->extradata, AVPALETTE_SIZE);
76  } else {
77  s->mode_8bit = 0;
78  avctx->pix_fmt = AV_PIX_FMT_RGB555;
79  }
80 
81  s->frame = av_frame_alloc();
82  if (!s->frame)
83  return AVERROR(ENOMEM);
84 
85  return 0;
86 }
87 
89 {
90  int block_ptr, pixel_ptr;
91  int total_blocks;
92  int pixel_x, pixel_y; /* pixel width and height iterators */
93  int block_x, block_y; /* block width and height iterators */
94  int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
95  int block_inc;
96  int row_dec;
97 
98  /* decoding parameters */
99  int stream_ptr;
100  unsigned char byte_a, byte_b;
101  unsigned short flags;
102  int skip_blocks;
103  unsigned char colors[8];
104  unsigned char *pixels = s->frame->data[0];
105  int stride = s->frame->linesize[0];
106 
107  stream_ptr = 0;
108  skip_blocks = 0;
109  blocks_wide = s->avctx->width / 4;
110  blocks_high = s->avctx->height / 4;
111  total_blocks = blocks_wide * blocks_high;
112  block_inc = 4;
113  row_dec = stride + 4;
114 
115  for (block_y = blocks_high; block_y > 0; block_y--) {
116  block_ptr = ((block_y * 4) - 1) * stride;
117  for (block_x = blocks_wide; block_x > 0; block_x--) {
118  /* check if this block should be skipped */
119  if (skip_blocks) {
120  block_ptr += block_inc;
121  skip_blocks--;
122  total_blocks--;
123  continue;
124  }
125 
126  pixel_ptr = block_ptr;
127 
128  /* get the next two bytes in the encoded data stream */
129  CHECK_STREAM_PTR(2);
130  byte_a = s->buf[stream_ptr++];
131  byte_b = s->buf[stream_ptr++];
132 
133  /* check if the decode is finished */
134  if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
135  return;
136  else if ((byte_b & 0xFC) == 0x84) {
137  /* skip code, but don't count the current block */
138  skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
139  } else if (byte_b < 0x80) {
140  /* 2-color encoding */
141  flags = (byte_b << 8) | byte_a;
142 
143  CHECK_STREAM_PTR(2);
144  colors[0] = s->buf[stream_ptr++];
145  colors[1] = s->buf[stream_ptr++];
146 
147  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
148  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
149  pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
150  pixel_ptr -= row_dec;
151  }
152  } else if (byte_b >= 0x90) {
153  /* 8-color encoding */
154  flags = (byte_b << 8) | byte_a;
155 
156  CHECK_STREAM_PTR(8);
157  memcpy(colors, &s->buf[stream_ptr], 8);
158  stream_ptr += 8;
159 
160  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
161  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
162  pixels[pixel_ptr++] =
163  colors[((pixel_y & 0x2) << 1) +
164  (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
165  pixel_ptr -= row_dec;
166  }
167  } else {
168  /* 1-color encoding */
169  colors[0] = byte_a;
170 
171  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
172  for (pixel_x = 0; pixel_x < 4; pixel_x++)
173  pixels[pixel_ptr++] = colors[0];
174  pixel_ptr -= row_dec;
175  }
176  }
177 
178  block_ptr += block_inc;
179  total_blocks--;
180  }
181  }
182 
183  /* make the palette available on the way out */
184  if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
185  memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
186 }
187 
189 {
190  int block_ptr, pixel_ptr;
191  int total_blocks;
192  int pixel_x, pixel_y; /* pixel width and height iterators */
193  int block_x, block_y; /* block width and height iterators */
194  int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
195  int block_inc;
196  int row_dec;
197 
198  /* decoding parameters */
199  int stream_ptr;
200  unsigned char byte_a, byte_b;
201  unsigned short flags;
202  int skip_blocks;
203  unsigned short colors[8];
204  unsigned short *pixels = (unsigned short *)s->frame->data[0];
205  int stride = s->frame->linesize[0] / 2;
206 
207  stream_ptr = 0;
208  skip_blocks = 0;
209  blocks_wide = s->avctx->width / 4;
210  blocks_high = s->avctx->height / 4;
211  total_blocks = blocks_wide * blocks_high;
212  block_inc = 4;
213  row_dec = stride + 4;
214 
215  for (block_y = blocks_high; block_y > 0; block_y--) {
216  block_ptr = ((block_y * 4) - 1) * stride;
217  for (block_x = blocks_wide; block_x > 0; block_x--) {
218  /* check if this block should be skipped */
219  if (skip_blocks) {
220  block_ptr += block_inc;
221  skip_blocks--;
222  total_blocks--;
223  continue;
224  }
225 
226  pixel_ptr = block_ptr;
227 
228  /* get the next two bytes in the encoded data stream */
229  CHECK_STREAM_PTR(2);
230  byte_a = s->buf[stream_ptr++];
231  byte_b = s->buf[stream_ptr++];
232 
233  /* check if the decode is finished */
234  if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
235  return;
236  } else if ((byte_b & 0xFC) == 0x84) {
237  /* skip code, but don't count the current block */
238  skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
239  } else if (byte_b < 0x80) {
240  /* 2- or 8-color encoding modes */
241  flags = (byte_b << 8) | byte_a;
242 
243  CHECK_STREAM_PTR(4);
244  colors[0] = AV_RL16(&s->buf[stream_ptr]);
245  stream_ptr += 2;
246  colors[1] = AV_RL16(&s->buf[stream_ptr]);
247  stream_ptr += 2;
248 
249  if (colors[0] & 0x8000) {
250  /* 8-color encoding */
251  CHECK_STREAM_PTR(12);
252  colors[2] = AV_RL16(&s->buf[stream_ptr]);
253  stream_ptr += 2;
254  colors[3] = AV_RL16(&s->buf[stream_ptr]);
255  stream_ptr += 2;
256  colors[4] = AV_RL16(&s->buf[stream_ptr]);
257  stream_ptr += 2;
258  colors[5] = AV_RL16(&s->buf[stream_ptr]);
259  stream_ptr += 2;
260  colors[6] = AV_RL16(&s->buf[stream_ptr]);
261  stream_ptr += 2;
262  colors[7] = AV_RL16(&s->buf[stream_ptr]);
263  stream_ptr += 2;
264 
265  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
266  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
267  pixels[pixel_ptr++] =
268  colors[((pixel_y & 0x2) << 1) +
269  (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
270  pixel_ptr -= row_dec;
271  }
272  } else {
273  /* 2-color encoding */
274  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
275  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
276  pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
277  pixel_ptr -= row_dec;
278  }
279  }
280  } else {
281  /* otherwise, it's a 1-color block */
282  colors[0] = (byte_b << 8) | byte_a;
283 
284  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
285  for (pixel_x = 0; pixel_x < 4; pixel_x++)
286  pixels[pixel_ptr++] = colors[0];
287  pixel_ptr -= row_dec;
288  }
289  }
290 
291  block_ptr += block_inc;
292  total_blocks--;
293  }
294  }
295 }
296 
297 static int msvideo1_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
298  int *got_frame, AVPacket *avpkt)
299 {
300  const uint8_t *buf = avpkt->data;
301  int buf_size = avpkt->size;
302  Msvideo1Context *s = avctx->priv_data;
303  int ret;
304 
305  s->buf = buf;
306  s->size = buf_size;
307 
308  // Discard frame if its smaller than the minimum frame size
309  if (buf_size < (avctx->width/4) * (avctx->height/4) / 512) {
310  av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
311  return AVERROR_INVALIDDATA;
312  }
313 
314  if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
315  return ret;
316 
317  if (s->mode_8bit) {
318  s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
319  }
320 
321  if (s->mode_8bit)
323  else
325 
326  if ((ret = av_frame_ref(rframe, s->frame)) < 0)
327  return ret;
328 
329  *got_frame = 1;
330 
331  /* report that the buffer was completely consumed */
332  return buf_size;
333 }
334 
336 {
337  Msvideo1Context *s = avctx->priv_data;
338 
339  av_frame_free(&s->frame);
340 
341  return 0;
342 }
343 
345  .p.name = "msvideo1",
346  .p.long_name = NULL_IF_CONFIG_SMALL("Microsoft Video 1"),
347  .p.type = AVMEDIA_TYPE_VIDEO,
348  .p.id = AV_CODEC_ID_MSVIDEO1,
349  .priv_data_size = sizeof(Msvideo1Context),
351  .close = msvideo1_decode_end,
353  .p.capabilities = AV_CODEC_CAP_DR1,
354  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
355 };
Msvideo1Context
Definition: msvideo1.c:48
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
CHECK_STREAM_PTR
#define CHECK_STREAM_PTR(n)
Definition: msvideo1.c:41
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:111
msvideo1_decode_init
static av_cold int msvideo1_decode_init(AVCodecContext *avctx)
Definition: msvideo1.c:61
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:374
FFCodec
Definition: codec_internal.h:112
msvideo1_decode_end
static av_cold int msvideo1_decode_end(AVCodecContext *avctx)
Definition: msvideo1.c:335
Msvideo1Context::frame
AVFrame * frame
Definition: msvideo1.c:51
init
static int init
Definition: av_tx.c:47
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:116
msvideo1_decode_16bit
static void msvideo1_decode_16bit(Msvideo1Context *s)
Definition: msvideo1.c:188
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:99
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
AVCodecContext::extradata_size
int extradata_size
Definition: avcodec.h:491
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:254
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:256
msvideo1_decode_8bit
static void msvideo1_decode_8bit(Msvideo1Context *s)
Definition: msvideo1.c:88
decode.h
AV_RL16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:94
msvideo1_decode_frame
static int msvideo1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, AVPacket *avpkt)
Definition: msvideo1.c:297
AVPALETTE_SIZE
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
Msvideo1Context::size
int size
Definition: msvideo1.c:54
Msvideo1Context::avctx
AVCodecContext * avctx
Definition: msvideo1.c:50
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
Msvideo1Context::pal
uint32_t pal[256]
Definition: msvideo1.c:58
AVPacket::size
int size
Definition: packet.h:375
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:116
av_frame_ref
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:343
codec_internal.h
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:425
AVCodecContext::extradata
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:490
internal.h
AV_PIX_FMT_RGB555
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:394
FF_CODEC_CAP_INIT_THREADSAFE
#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: codec_internal.h:31
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:203
AVCodecContext::height
int height
Definition: avcodec.h:562
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:599
avcodec.h
stride
#define stride
Definition: h264pred_template.c:537
AV_PIX_FMT_PAL8
@ AV_PIX_FMT_PAL8
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
ff_reget_buffer
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:1521
ret
ret
Definition: filter_design.txt:187
ff_msvideo1_decoder
const FFCodec ff_msvideo1_decoder
Definition: msvideo1.c:344
AVCodecContext
main external API structure.
Definition: avcodec.h:389
Msvideo1Context::mode_8bit
int mode_8bit
Definition: msvideo1.c:56
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
Msvideo1Context::buf
const unsigned char * buf
Definition: msvideo1.c:53
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:416
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:562
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
ff_copy_palette
int ff_copy_palette(void *dst, const AVPacket *src, void *logctx)
Check whether the side-data of src contains a palette of size AVPALETTE_SIZE; if so,...
Definition: decode.c:1624
AV_CODEC_ID_MSVIDEO1
@ AV_CODEC_ID_MSVIDEO1
Definition: codec_id.h:96