2 * Microsoft Video-1 Decoder
3 * Copyright (C) 2003 the ffmpeg project
5 * This file is part of Libav.
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.
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.
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
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/
34 #include "libavutil/internal.h"
35 #include "libavutil/intreadwrite.h"
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); \
46 typedef struct Msvideo1Context
{
48 AVCodecContext
*avctx
;
51 const unsigned char *buf
;
54 int mode_8bit
; /* if it's not 8-bit, it's 16-bit */
59 static av_cold
int msvideo1_decode_init(AVCodecContext
*avctx
)
61 Msvideo1Context
*s
= avctx
->priv_data
;
65 /* figure out the colorspace based on the presence of a palette */
66 if (s
->avctx
->bits_per_coded_sample
== 8) {
68 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
71 avctx
->pix_fmt
= AV_PIX_FMT_RGB555
;
74 s
->frame
.data
[0] = NULL
;
79 static void msvideo1_decode_8bit(Msvideo1Context
*s
)
81 int block_ptr
, pixel_ptr
;
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 */
89 /* decoding parameters */
91 unsigned char byte_a
, byte_b
;
94 unsigned char colors
[8];
95 unsigned char *pixels
= s
->frame
.data
[0];
96 int stride
= s
->frame
.linesize
[0];
100 blocks_wide
= s
->avctx
->width
/ 4;
101 blocks_high
= s
->avctx
->height
/ 4;
102 total_blocks
= blocks_wide
* blocks_high
;
104 row_dec
= stride
+ 4;
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 */
111 block_ptr
+= block_inc
;
117 pixel_ptr
= block_ptr
;
119 /* get the next two bytes in the encoded data stream */
121 byte_a
= s
->buf
[stream_ptr
++];
122 byte_b
= s
->buf
[stream_ptr
++];
124 /* check if the decode is finished */
125 if ((byte_a
== 0) && (byte_b
== 0) && (total_blocks
== 0))
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
;
135 colors
[0] = s
->buf
[stream_ptr
++];
136 colors
[1] = s
->buf
[stream_ptr
++];
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
;
143 } else if (byte_b
>= 0x90) {
144 /* 8-color encoding */
145 flags
= (byte_b
<< 8) | byte_a
;
148 memcpy(colors
, &s
->buf
[stream_ptr
], 8);
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
;
159 /* 1-color encoding */
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
;
169 block_ptr
+= block_inc
;
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
);
179 static void msvideo1_decode_16bit(Msvideo1Context
*s
)
181 int block_ptr
, pixel_ptr
;
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 */
189 /* decoding parameters */
191 unsigned char byte_a
, byte_b
;
192 unsigned short flags
;
194 unsigned short colors
[8];
195 unsigned short *pixels
= (unsigned short *)s
->frame
.data
[0];
196 int stride
= s
->frame
.linesize
[0] / 2;
200 blocks_wide
= s
->avctx
->width
/ 4;
201 blocks_high
= s
->avctx
->height
/ 4;
202 total_blocks
= blocks_wide
* blocks_high
;
204 row_dec
= stride
+ 4;
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 */
211 block_ptr
+= block_inc
;
217 pixel_ptr
= block_ptr
;
219 /* get the next two bytes in the encoded data stream */
221 byte_a
= s
->buf
[stream_ptr
++];
222 byte_b
= s
->buf
[stream_ptr
++];
224 /* check if the decode is finished */
225 if ((byte_a
== 0) && (byte_b
== 0) && (total_blocks
== 0)) {
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
;
235 colors
[0] = AV_RL16(&s
->buf
[stream_ptr
]);
237 colors
[1] = AV_RL16(&s
->buf
[stream_ptr
]);
240 if (colors
[0] & 0x8000) {
241 /* 8-color encoding */
242 CHECK_STREAM_PTR(12);
243 colors
[2] = AV_RL16(&s
->buf
[stream_ptr
]);
245 colors
[3] = AV_RL16(&s
->buf
[stream_ptr
]);
247 colors
[4] = AV_RL16(&s
->buf
[stream_ptr
]);
249 colors
[5] = AV_RL16(&s
->buf
[stream_ptr
]);
251 colors
[6] = AV_RL16(&s
->buf
[stream_ptr
]);
253 colors
[7] = AV_RL16(&s
->buf
[stream_ptr
]);
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
;
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
;
272 /* otherwise, it's a 1-color block */
273 colors
[0] = (byte_b
<< 8) | byte_a
;
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
;
282 block_ptr
+= block_inc
;
288 static int msvideo1_decode_frame(AVCodecContext
*avctx
,
289 void *data
, int *got_frame
,
292 const uint8_t *buf
= avpkt
->data
;
293 int buf_size
= avpkt
->size
;
294 Msvideo1Context
*s
= avctx
->priv_data
;
299 s
->frame
.reference
= 1;
300 s
->frame
.buffer_hints
= FF_BUFFER_HINTS_VALID
| FF_BUFFER_HINTS_PRESERVE
| FF_BUFFER_HINTS_REUSABLE
;
301 if (avctx
->reget_buffer(avctx
, &s
->frame
)) {
302 av_log(s
->avctx
, AV_LOG_ERROR
, "reget_buffer() failed\n");
307 const uint8_t *pal
= av_packet_get_side_data(avpkt
, AV_PKT_DATA_PALETTE
, NULL
);
310 memcpy(s
->pal
, pal
, AVPALETTE_SIZE
);
311 s
->frame
.palette_has_changed
= 1;
316 msvideo1_decode_8bit(s
);
318 msvideo1_decode_16bit(s
);
321 *(AVFrame
*)data
= s
->frame
;
323 /* report that the buffer was completely consumed */
327 static av_cold
int msvideo1_decode_end(AVCodecContext
*avctx
)
329 Msvideo1Context
*s
= avctx
->priv_data
;
331 if (s
->frame
.data
[0])
332 avctx
->release_buffer(avctx
, &s
->frame
);
337 AVCodec ff_msvideo1_decoder
= {
339 .type
= AVMEDIA_TYPE_VIDEO
,
340 .id
= AV_CODEC_ID_MSVIDEO1
,
341 .priv_data_size
= sizeof(Msvideo1Context
),
342 .init
= msvideo1_decode_init
,
343 .close
= msvideo1_decode_end
,
344 .decode
= msvideo1_decode_frame
,
345 .capabilities
= CODEC_CAP_DR1
,
346 .long_name
= NULL_IF_CONFIG_SMALL("Microsoft Video 1"),