2 * Microsoft Video-1 Decoder
3 * Copyright (C) 2003 The FFmpeg project
5 * This file is part of FFmpeg.
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.
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.
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
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/
31 #include "libavutil/internal.h"
32 #include "libavutil/intreadwrite.h"
34 #include "codec_internal.h"
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); \
45 typedef struct Msvideo1Context
{
47 AVCodecContext
*avctx
;
50 const unsigned char *buf
;
53 int mode_8bit
; /* if it's not 8-bit, it's 16-bit */
58 static av_cold
int msvideo1_decode_init(AVCodecContext
*avctx
)
60 Msvideo1Context
*s
= avctx
->priv_data
;
64 if (avctx
->width
< 4 || avctx
->height
< 4)
65 return AVERROR_INVALIDDATA
;
67 /* figure out the colorspace based on the presence of a palette */
68 if (s
->avctx
->bits_per_coded_sample
== 8) {
70 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
71 if (avctx
->extradata_size
>= AVPALETTE_SIZE
)
72 memcpy(s
->pal
, avctx
->extradata
, AVPALETTE_SIZE
);
75 avctx
->pix_fmt
= AV_PIX_FMT_RGB555
;
78 s
->frame
= av_frame_alloc();
80 return AVERROR(ENOMEM
);
85 static void msvideo1_decode_8bit(Msvideo1Context
*s
)
87 int block_ptr
, pixel_ptr
;
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 */
95 /* decoding parameters */
97 unsigned char byte_a
, byte_b
;
100 unsigned char colors
[8];
101 unsigned char *pixels
= s
->frame
->data
[0];
102 int stride
= s
->frame
->linesize
[0];
106 blocks_wide
= s
->avctx
->width
/ 4;
107 blocks_high
= s
->avctx
->height
/ 4;
108 total_blocks
= blocks_wide
* blocks_high
;
110 row_dec
= stride
+ 4;
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 */
117 block_ptr
+= block_inc
;
123 pixel_ptr
= block_ptr
;
125 /* get the next two bytes in the encoded data stream */
127 byte_a
= s
->buf
[stream_ptr
++];
128 byte_b
= s
->buf
[stream_ptr
++];
130 /* check if the decode is finished */
131 if ((byte_a
== 0) && (byte_b
== 0) && (total_blocks
== 0))
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
;
141 colors
[0] = s
->buf
[stream_ptr
++];
142 colors
[1] = s
->buf
[stream_ptr
++];
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
;
149 } else if (byte_b
>= 0x90) {
150 /* 8-color encoding */
151 flags
= (byte_b
<< 8) | byte_a
;
154 memcpy(colors
, &s
->buf
[stream_ptr
], 8);
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
;
165 /* 1-color encoding */
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
;
175 block_ptr
+= block_inc
;
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
);
185 static void msvideo1_decode_16bit(Msvideo1Context
*s
)
187 int block_ptr
, pixel_ptr
;
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 */
195 /* decoding parameters */
197 unsigned char byte_a
, byte_b
;
198 unsigned short flags
;
200 unsigned short colors
[8];
201 unsigned short *pixels
= (unsigned short *)s
->frame
->data
[0];
202 int stride
= s
->frame
->linesize
[0] / 2;
206 blocks_wide
= s
->avctx
->width
/ 4;
207 blocks_high
= s
->avctx
->height
/ 4;
208 total_blocks
= blocks_wide
* blocks_high
;
210 row_dec
= stride
+ 4;
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 */
217 block_ptr
+= block_inc
;
223 pixel_ptr
= block_ptr
;
225 /* get the next two bytes in the encoded data stream */
227 byte_a
= s
->buf
[stream_ptr
++];
228 byte_b
= s
->buf
[stream_ptr
++];
230 /* check if the decode is finished */
231 if ((byte_a
== 0) && (byte_b
== 0) && (total_blocks
== 0)) {
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
;
241 colors
[0] = AV_RL16(&s
->buf
[stream_ptr
]);
243 colors
[1] = AV_RL16(&s
->buf
[stream_ptr
]);
246 if (colors
[0] & 0x8000) {
247 /* 8-color encoding */
248 CHECK_STREAM_PTR(12);
249 colors
[2] = AV_RL16(&s
->buf
[stream_ptr
]);
251 colors
[3] = AV_RL16(&s
->buf
[stream_ptr
]);
253 colors
[4] = AV_RL16(&s
->buf
[stream_ptr
]);
255 colors
[5] = AV_RL16(&s
->buf
[stream_ptr
]);
257 colors
[6] = AV_RL16(&s
->buf
[stream_ptr
]);
259 colors
[7] = AV_RL16(&s
->buf
[stream_ptr
]);
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
;
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
;
278 /* otherwise, it's a 1-color block */
279 colors
[0] = (byte_b
<< 8) | byte_a
;
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
;
288 block_ptr
+= block_inc
;
294 static int msvideo1_decode_frame(AVCodecContext
*avctx
, AVFrame
*rframe
,
295 int *got_frame
, AVPacket
*avpkt
)
297 const uint8_t *buf
= avpkt
->data
;
298 int buf_size
= avpkt
->size
;
299 Msvideo1Context
*s
= avctx
->priv_data
;
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
;
311 if ((ret
= ff_reget_buffer(avctx
, s
->frame
, 0)) < 0)
315 #if FF_API_PALETTE_HAS_CHANGED
316 FF_DISABLE_DEPRECATION_WARNINGS
317 s
->frame
->palette_has_changed
=
319 ff_copy_palette(s
->pal
, avpkt
, avctx
);
320 #if FF_API_PALETTE_HAS_CHANGED
321 FF_ENABLE_DEPRECATION_WARNINGS
326 msvideo1_decode_8bit(s
);
328 msvideo1_decode_16bit(s
);
330 if ((ret
= av_frame_ref(rframe
, s
->frame
)) < 0)
335 /* report that the buffer was completely consumed */
339 static av_cold
int msvideo1_decode_end(AVCodecContext
*avctx
)
341 Msvideo1Context
*s
= avctx
->priv_data
;
343 av_frame_free(&s
->frame
);
348 const FFCodec ff_msvideo1_decoder
= {
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
),
354 .init
= msvideo1_decode_init
,
355 .close
= msvideo1_decode_end
,
356 FF_CODEC_DECODE_CB(msvideo1_decode_frame
),
357 .p
.capabilities
= AV_CODEC_CAP_DR1
,