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 <string.h>
30 
31 #include "libavutil/internal.h"
32 #include "libavutil/intreadwrite.h"
33 #include "avcodec.h"
34 #include "codec_internal.h"
35 #include "decode.h"
36 
37 #define PALETTE_COUNT 256
38 #define CHECK_STREAM_PTR(n) \
39  if ((stream_ptr + n) > s->size ) { \
40  av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \
41  stream_ptr + n, s->size); \
42  return; \
43  }
44 
45 typedef struct Msvideo1Context {
46 
49 
50  const unsigned char *buf;
51  int size;
52 
53  int mode_8bit; /* if it's not 8-bit, it's 16-bit */
54 
55  uint32_t pal[256];
57 
59 {
60  Msvideo1Context *s = avctx->priv_data;
61 
62  s->avctx = avctx;
63 
64  if (avctx->width < 4 || avctx->height < 4)
65  return AVERROR_INVALIDDATA;
66 
67  /* figure out the colorspace based on the presence of a palette */
68  if (s->avctx->bits_per_coded_sample == 8) {
69  s->mode_8bit = 1;
70  avctx->pix_fmt = AV_PIX_FMT_PAL8;
71  if (avctx->extradata_size >= AVPALETTE_SIZE)
72  memcpy(s->pal, avctx->extradata, AVPALETTE_SIZE);
73  } else {
74  s->mode_8bit = 0;
75  avctx->pix_fmt = AV_PIX_FMT_RGB555;
76  }
77 
78  s->frame = av_frame_alloc();
79  if (!s->frame)
80  return AVERROR(ENOMEM);
81 
82  return 0;
83 }
84 
86 {
87  int block_ptr, pixel_ptr;
88  int total_blocks;
89  int pixel_x, pixel_y; /* pixel width and height iterators */
90  int block_x, block_y; /* block width and height iterators */
91  int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
92  int block_inc;
93  int row_dec;
94 
95  /* decoding parameters */
96  int stream_ptr;
97  unsigned char byte_a, byte_b;
98  unsigned short flags;
99  int skip_blocks;
100  unsigned char colors[8];
101  unsigned char *pixels = s->frame->data[0];
102  int stride = s->frame->linesize[0];
103 
104  stream_ptr = 0;
105  skip_blocks = 0;
106  blocks_wide = s->avctx->width / 4;
107  blocks_high = s->avctx->height / 4;
108  total_blocks = blocks_wide * blocks_high;
109  block_inc = 4;
110  row_dec = stride + 4;
111 
112  for (block_y = blocks_high; block_y > 0; block_y--) {
113  block_ptr = ((block_y * 4) - 1) * stride;
114  for (block_x = blocks_wide; block_x > 0; block_x--) {
115  /* check if this block should be skipped */
116  if (skip_blocks) {
117  block_ptr += block_inc;
118  skip_blocks--;
119  total_blocks--;
120  continue;
121  }
122 
123  pixel_ptr = block_ptr;
124 
125  /* get the next two bytes in the encoded data stream */
126  CHECK_STREAM_PTR(2);
127  byte_a = s->buf[stream_ptr++];
128  byte_b = s->buf[stream_ptr++];
129 
130  /* check if the decode is finished */
131  if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
132  return;
133  else if ((byte_b & 0xFC) == 0x84) {
134  /* skip code, but don't count the current block */
135  skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
136  } else if (byte_b < 0x80) {
137  /* 2-color encoding */
138  flags = (byte_b << 8) | byte_a;
139 
140  CHECK_STREAM_PTR(2);
141  colors[0] = s->buf[stream_ptr++];
142  colors[1] = s->buf[stream_ptr++];
143 
144  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
145  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
146  pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
147  pixel_ptr -= row_dec;
148  }
149  } else if (byte_b >= 0x90) {
150  /* 8-color encoding */
151  flags = (byte_b << 8) | byte_a;
152 
153  CHECK_STREAM_PTR(8);
154  memcpy(colors, &s->buf[stream_ptr], 8);
155  stream_ptr += 8;
156 
157  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
158  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
159  pixels[pixel_ptr++] =
160  colors[((pixel_y & 0x2) << 1) +
161  (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
162  pixel_ptr -= row_dec;
163  }
164  } else {
165  /* 1-color encoding */
166  colors[0] = byte_a;
167 
168  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
169  for (pixel_x = 0; pixel_x < 4; pixel_x++)
170  pixels[pixel_ptr++] = colors[0];
171  pixel_ptr -= row_dec;
172  }
173  }
174 
175  block_ptr += block_inc;
176  total_blocks--;
177  }
178  }
179 
180  /* make the palette available on the way out */
181  if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
182  memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
183 }
184 
186 {
187  int block_ptr, pixel_ptr;
188  int total_blocks;
189  int pixel_x, pixel_y; /* pixel width and height iterators */
190  int block_x, block_y; /* block width and height iterators */
191  int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
192  int block_inc;
193  int row_dec;
194 
195  /* decoding parameters */
196  int stream_ptr;
197  unsigned char byte_a, byte_b;
198  unsigned short flags;
199  int skip_blocks;
200  unsigned short colors[8];
201  unsigned short *pixels = (unsigned short *)s->frame->data[0];
202  int stride = s->frame->linesize[0] / 2;
203 
204  stream_ptr = 0;
205  skip_blocks = 0;
206  blocks_wide = s->avctx->width / 4;
207  blocks_high = s->avctx->height / 4;
208  total_blocks = blocks_wide * blocks_high;
209  block_inc = 4;
210  row_dec = stride + 4;
211 
212  for (block_y = blocks_high; block_y > 0; block_y--) {
213  block_ptr = ((block_y * 4) - 1) * stride;
214  for (block_x = blocks_wide; block_x > 0; block_x--) {
215  /* check if this block should be skipped */
216  if (skip_blocks) {
217  block_ptr += block_inc;
218  skip_blocks--;
219  total_blocks--;
220  continue;
221  }
222 
223  pixel_ptr = block_ptr;
224 
225  /* get the next two bytes in the encoded data stream */
226  CHECK_STREAM_PTR(2);
227  byte_a = s->buf[stream_ptr++];
228  byte_b = s->buf[stream_ptr++];
229 
230  /* check if the decode is finished */
231  if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
232  return;
233  } else if ((byte_b & 0xFC) == 0x84) {
234  /* skip code, but don't count the current block */
235  skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
236  } else if (byte_b < 0x80) {
237  /* 2- or 8-color encoding modes */
238  flags = (byte_b << 8) | byte_a;
239 
240  CHECK_STREAM_PTR(4);
241  colors[0] = AV_RL16(&s->buf[stream_ptr]);
242  stream_ptr += 2;
243  colors[1] = AV_RL16(&s->buf[stream_ptr]);
244  stream_ptr += 2;
245 
246  if (colors[0] & 0x8000) {
247  /* 8-color encoding */
248  CHECK_STREAM_PTR(12);
249  colors[2] = AV_RL16(&s->buf[stream_ptr]);
250  stream_ptr += 2;
251  colors[3] = AV_RL16(&s->buf[stream_ptr]);
252  stream_ptr += 2;
253  colors[4] = AV_RL16(&s->buf[stream_ptr]);
254  stream_ptr += 2;
255  colors[5] = AV_RL16(&s->buf[stream_ptr]);
256  stream_ptr += 2;
257  colors[6] = AV_RL16(&s->buf[stream_ptr]);
258  stream_ptr += 2;
259  colors[7] = AV_RL16(&s->buf[stream_ptr]);
260  stream_ptr += 2;
261 
262  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
263  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
264  pixels[pixel_ptr++] =
265  colors[((pixel_y & 0x2) << 1) +
266  (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
267  pixel_ptr -= row_dec;
268  }
269  } else {
270  /* 2-color encoding */
271  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
272  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
273  pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
274  pixel_ptr -= row_dec;
275  }
276  }
277  } else {
278  /* otherwise, it's a 1-color block */
279  colors[0] = (byte_b << 8) | byte_a;
280 
281  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
282  for (pixel_x = 0; pixel_x < 4; pixel_x++)
283  pixels[pixel_ptr++] = colors[0];
284  pixel_ptr -= row_dec;
285  }
286  }
287 
288  block_ptr += block_inc;
289  total_blocks--;
290  }
291  }
292 }
293 
294 static int msvideo1_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
295  int *got_frame, AVPacket *avpkt)
296 {
297  const uint8_t *buf = avpkt->data;
298  int buf_size = avpkt->size;
299  Msvideo1Context *s = avctx->priv_data;
300  int ret;
301 
302  s->buf = buf;
303  s->size = buf_size;
304 
305  // Discard frame if its smaller than the minimum frame size
306  if (buf_size < (avctx->width/4) * (avctx->height/4) / 512) {
307  av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
308  return AVERROR_INVALIDDATA;
309  }
310 
311  if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
312  return ret;
313 
314  if (s->mode_8bit) {
315 #if FF_API_PALETTE_HAS_CHANGED
317  s->frame->palette_has_changed =
318 #endif
319  ff_copy_palette(s->pal, avpkt, avctx);
320 #if FF_API_PALETTE_HAS_CHANGED
322 #endif
323  }
324 
325  if (s->mode_8bit)
327  else
329 
330  if ((ret = av_frame_ref(rframe, s->frame)) < 0)
331  return ret;
332 
333  *got_frame = 1;
334 
335  /* report that the buffer was completely consumed */
336  return buf_size;
337 }
338 
340 {
341  Msvideo1Context *s = avctx->priv_data;
342 
343  av_frame_free(&s->frame);
344 
345  return 0;
346 }
347 
349  .p.name = "msvideo1",
350  CODEC_LONG_NAME("Microsoft Video 1"),
351  .p.type = AVMEDIA_TYPE_VIDEO,
352  .p.id = AV_CODEC_ID_MSVIDEO1,
353  .priv_data_size = sizeof(Msvideo1Context),
355  .close = msvideo1_decode_end,
357  .p.capabilities = AV_CODEC_CAP_DR1,
358 };
FF_ENABLE_DEPRECATION_WARNINGS
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition: internal.h:73
Msvideo1Context
Definition: msvideo1.c:45
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:38
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:100
msvideo1_decode_init
static av_cold int msvideo1_decode_init(AVCodecContext *avctx)
Definition: msvideo1.c:58
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
AVPacket::data
uint8_t * data
Definition: packet.h:491
FFCodec
Definition: codec_internal.h:127
msvideo1_decode_end
static av_cold int msvideo1_decode_end(AVCodecContext *avctx)
Definition: msvideo1.c:339
Msvideo1Context::frame
AVFrame * frame
Definition: msvideo1.c:48
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
msvideo1_decode_16bit
static void msvideo1_decode_16bit(Msvideo1Context *s)
Definition: msvideo1.c:185
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:88
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:543
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:306
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
msvideo1_decode_8bit
static void msvideo1_decode_8bit(Msvideo1Context *s)
Definition: msvideo1.c:85
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
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
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
msvideo1_decode_frame
static int msvideo1_decode_frame(AVCodecContext *avctx, AVFrame *rframe, int *got_frame, AVPacket *avpkt)
Definition: msvideo1.c:294
AVPALETTE_SIZE
#define AVPALETTE_SIZE
Definition: pixfmt.h:32
Msvideo1Context::size
int size
Definition: msvideo1.c:51
Msvideo1Context::avctx
AVCodecContext * avctx
Definition: msvideo1.c:47
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:55
AVPacket::size
int size
Definition: packet.h:492
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:361
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:542
internal.h
AV_PIX_FMT_RGB555
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:456
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AVCodecContext::height
int height
Definition: avcodec.h:621
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:658
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:1735
ret
ret
Definition: filter_design.txt:187
ff_msvideo1_decoder
const FFCodec ff_msvideo1_decoder
Definition: msvideo1.c:348
AVCodecContext
main external API structure.
Definition: avcodec.h:441
Msvideo1Context::mode_8bit
int mode_8bit
Definition: msvideo1.c:53
FF_DISABLE_DEPRECATION_WARNINGS
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:72
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
Msvideo1Context::buf
const unsigned char * buf
Definition: msvideo1.c:50
AVPacket
This structure stores compressed data.
Definition: packet.h:468
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:468
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:621
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
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:1823
AV_CODEC_ID_MSVIDEO1
@ AV_CODEC_ID_MSVIDEO1
Definition: codec_id.h:98