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 Libav.
6  *
7  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "libavutil/internal.h"
35 #include "libavutil/intreadwrite.h"
36 #include "avcodec.h"
37 
38 #define PALETTE_COUNT 256
39 #define CHECK_STREAM_PTR(n) \
40  if ((stream_ptr + n) > s->size ) { \
41  av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \
42  stream_ptr + n, s->size); \
43  return; \
44  }
45 
46 typedef struct Msvideo1Context {
47 
50 
51  const unsigned char *buf;
52  int size;
53 
54  int mode_8bit; /* if it's not 8-bit, it's 16-bit */
55 
56  uint32_t pal[256];
58 
60 {
61  Msvideo1Context *s = avctx->priv_data;
62 
63  s->avctx = avctx;
64 
65  /* figure out the colorspace based on the presence of a palette */
66  if (s->avctx->bits_per_coded_sample == 8) {
67  s->mode_8bit = 1;
68  avctx->pix_fmt = AV_PIX_FMT_PAL8;
69  } else {
70  s->mode_8bit = 0;
71  avctx->pix_fmt = AV_PIX_FMT_RGB555;
72  }
73 
74  s->frame.data[0] = NULL;
75 
76  return 0;
77 }
78 
80 {
81  int block_ptr, pixel_ptr;
82  int total_blocks;
83  int pixel_x, pixel_y; /* pixel width and height iterators */
84  int block_x, block_y; /* block width and height iterators */
85  int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
86  int block_inc;
87  int row_dec;
88 
89  /* decoding parameters */
90  int stream_ptr;
91  unsigned char byte_a, byte_b;
92  unsigned short flags;
93  int skip_blocks;
94  unsigned char colors[8];
95  unsigned char *pixels = s->frame.data[0];
96  int stride = s->frame.linesize[0];
97 
98  stream_ptr = 0;
99  skip_blocks = 0;
100  blocks_wide = s->avctx->width / 4;
101  blocks_high = s->avctx->height / 4;
102  total_blocks = blocks_wide * blocks_high;
103  block_inc = 4;
104  row_dec = stride + 4;
105 
106  for (block_y = blocks_high; block_y > 0; block_y--) {
107  block_ptr = ((block_y * 4) - 1) * stride;
108  for (block_x = blocks_wide; block_x > 0; block_x--) {
109  /* check if this block should be skipped */
110  if (skip_blocks) {
111  block_ptr += block_inc;
112  skip_blocks--;
113  total_blocks--;
114  continue;
115  }
116 
117  pixel_ptr = block_ptr;
118 
119  /* get the next two bytes in the encoded data stream */
120  CHECK_STREAM_PTR(2);
121  byte_a = s->buf[stream_ptr++];
122  byte_b = s->buf[stream_ptr++];
123 
124  /* check if the decode is finished */
125  if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0))
126  return;
127  else if ((byte_b & 0xFC) == 0x84) {
128  /* skip code, but don't count the current block */
129  skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
130  } else if (byte_b < 0x80) {
131  /* 2-color encoding */
132  flags = (byte_b << 8) | byte_a;
133 
134  CHECK_STREAM_PTR(2);
135  colors[0] = s->buf[stream_ptr++];
136  colors[1] = s->buf[stream_ptr++];
137 
138  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
139  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
140  pixels[pixel_ptr++] = colors[(flags & 0x1) ^ 1];
141  pixel_ptr -= row_dec;
142  }
143  } else if (byte_b >= 0x90) {
144  /* 8-color encoding */
145  flags = (byte_b << 8) | byte_a;
146 
147  CHECK_STREAM_PTR(8);
148  memcpy(colors, &s->buf[stream_ptr], 8);
149  stream_ptr += 8;
150 
151  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
152  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
153  pixels[pixel_ptr++] =
154  colors[((pixel_y & 0x2) << 1) +
155  (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
156  pixel_ptr -= row_dec;
157  }
158  } else {
159  /* 1-color encoding */
160  colors[0] = byte_a;
161 
162  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
163  for (pixel_x = 0; pixel_x < 4; pixel_x++)
164  pixels[pixel_ptr++] = colors[0];
165  pixel_ptr -= row_dec;
166  }
167  }
168 
169  block_ptr += block_inc;
170  total_blocks--;
171  }
172  }
173 
174  /* make the palette available on the way out */
175  if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
176  memcpy(s->frame.data[1], s->pal, AVPALETTE_SIZE);
177 }
178 
180 {
181  int block_ptr, pixel_ptr;
182  int total_blocks;
183  int pixel_x, pixel_y; /* pixel width and height iterators */
184  int block_x, block_y; /* block width and height iterators */
185  int blocks_wide, blocks_high; /* width and height in 4x4 blocks */
186  int block_inc;
187  int row_dec;
188 
189  /* decoding parameters */
190  int stream_ptr;
191  unsigned char byte_a, byte_b;
192  unsigned short flags;
193  int skip_blocks;
194  unsigned short colors[8];
195  unsigned short *pixels = (unsigned short *)s->frame.data[0];
196  int stride = s->frame.linesize[0] / 2;
197 
198  stream_ptr = 0;
199  skip_blocks = 0;
200  blocks_wide = s->avctx->width / 4;
201  blocks_high = s->avctx->height / 4;
202  total_blocks = blocks_wide * blocks_high;
203  block_inc = 4;
204  row_dec = stride + 4;
205 
206  for (block_y = blocks_high; block_y > 0; block_y--) {
207  block_ptr = ((block_y * 4) - 1) * stride;
208  for (block_x = blocks_wide; block_x > 0; block_x--) {
209  /* check if this block should be skipped */
210  if (skip_blocks) {
211  block_ptr += block_inc;
212  skip_blocks--;
213  total_blocks--;
214  continue;
215  }
216 
217  pixel_ptr = block_ptr;
218 
219  /* get the next two bytes in the encoded data stream */
220  CHECK_STREAM_PTR(2);
221  byte_a = s->buf[stream_ptr++];
222  byte_b = s->buf[stream_ptr++];
223 
224  /* check if the decode is finished */
225  if ((byte_a == 0) && (byte_b == 0) && (total_blocks == 0)) {
226  return;
227  } else if ((byte_b & 0xFC) == 0x84) {
228  /* skip code, but don't count the current block */
229  skip_blocks = ((byte_b - 0x84) << 8) + byte_a - 1;
230  } else if (byte_b < 0x80) {
231  /* 2- or 8-color encoding modes */
232  flags = (byte_b << 8) | byte_a;
233 
234  CHECK_STREAM_PTR(4);
235  colors[0] = AV_RL16(&s->buf[stream_ptr]);
236  stream_ptr += 2;
237  colors[1] = AV_RL16(&s->buf[stream_ptr]);
238  stream_ptr += 2;
239 
240  if (colors[0] & 0x8000) {
241  /* 8-color encoding */
242  CHECK_STREAM_PTR(12);
243  colors[2] = AV_RL16(&s->buf[stream_ptr]);
244  stream_ptr += 2;
245  colors[3] = AV_RL16(&s->buf[stream_ptr]);
246  stream_ptr += 2;
247  colors[4] = AV_RL16(&s->buf[stream_ptr]);
248  stream_ptr += 2;
249  colors[5] = AV_RL16(&s->buf[stream_ptr]);
250  stream_ptr += 2;
251  colors[6] = AV_RL16(&s->buf[stream_ptr]);
252  stream_ptr += 2;
253  colors[7] = AV_RL16(&s->buf[stream_ptr]);
254  stream_ptr += 2;
255 
256  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
257  for (pixel_x = 0; pixel_x < 4; pixel_x++, flags >>= 1)
258  pixels[pixel_ptr++] =
259  colors[((pixel_y & 0x2) << 1) +
260  (pixel_x & 0x2) + ((flags & 0x1) ^ 1)];
261  pixel_ptr -= row_dec;
262  }
263  } else {
264  /* 2-color encoding */
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++] = colors[(flags & 0x1) ^ 1];
268  pixel_ptr -= row_dec;
269  }
270  }
271  } else {
272  /* otherwise, it's a 1-color block */
273  colors[0] = (byte_b << 8) | byte_a;
274 
275  for (pixel_y = 0; pixel_y < 4; pixel_y++) {
276  for (pixel_x = 0; pixel_x < 4; pixel_x++)
277  pixels[pixel_ptr++] = colors[0];
278  pixel_ptr -= row_dec;
279  }
280  }
281 
282  block_ptr += block_inc;
283  total_blocks--;
284  }
285  }
286 }
287 
289  void *data, int *got_frame,
290  AVPacket *avpkt)
291 {
292  const uint8_t *buf = avpkt->data;
293  int buf_size = avpkt->size;
294  Msvideo1Context *s = avctx->priv_data;
295 
296  s->buf = buf;
297  s->size = buf_size;
298 
299  s->frame.reference = 1;
301  if (avctx->reget_buffer(avctx, &s->frame)) {
302  av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
303  return -1;
304  }
305 
306  if (s->mode_8bit) {
308 
309  if (pal) {
310  memcpy(s->pal, pal, AVPALETTE_SIZE);
311  s->frame.palette_has_changed = 1;
312  }
313  }
314 
315  if (s->mode_8bit)
317  else
319 
320  *got_frame = 1;
321  *(AVFrame*)data = s->frame;
322 
323  /* report that the buffer was completely consumed */
324  return buf_size;
325 }
326 
328 {
329  Msvideo1Context *s = avctx->priv_data;
330 
331  if (s->frame.data[0])
332  avctx->release_buffer(avctx, &s->frame);
333 
334  return 0;
335 }
336 
338  .name = "msvideo1",
339  .type = AVMEDIA_TYPE_VIDEO,
340  .id = AV_CODEC_ID_MSVIDEO1,
341  .priv_data_size = sizeof(Msvideo1Context),
345  .capabilities = CODEC_CAP_DR1,
346  .long_name = NULL_IF_CONFIG_SMALL("Microsoft Video 1"),
347 };