2 * Motion Pixels Video Decoder
3 * Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net)
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
27 #define MAX_HUFF_CODES 16
29 #include "motionpixels_tablegen.h"
31 typedef struct HuffCode
{
37 typedef struct MotionPixelsContext
{
38 AVCodecContext
*avctx
;
43 int codes_count
, current_codes_count
;
45 HuffCode codes
[MAX_HUFF_CODES
];
48 uint8_t gradient_scale
[3];
51 } MotionPixelsContext
;
53 static av_cold
int mp_decode_end(AVCodecContext
*avctx
)
55 MotionPixelsContext
*mp
= avctx
->priv_data
;
57 av_freep(&mp
->changes_map
);
60 av_freep(&mp
->bswapbuf
);
61 av_frame_free(&mp
->frame
);
66 static av_cold
int mp_decode_init(AVCodecContext
*avctx
)
68 MotionPixelsContext
*mp
= avctx
->priv_data
;
69 int w4
= (avctx
->width
+ 3) & ~3;
70 int h4
= (avctx
->height
+ 3) & ~3;
72 if(avctx
->extradata_size
< 2){
73 av_log(avctx
, AV_LOG_ERROR
, "extradata too small\n");
74 return AVERROR_INVALIDDATA
;
77 motionpixels_tableinit();
79 ff_bswapdsp_init(&mp
->bdsp
);
80 mp
->changes_map
= av_mallocz_array(avctx
->width
, h4
);
81 mp
->offset_bits_len
= av_log2(avctx
->width
* avctx
->height
) + 1;
82 mp
->vpt
= av_mallocz_array(avctx
->height
, sizeof(YuvPixel
));
83 mp
->hpt
= av_mallocz_array(h4
/ 4, w4
/ 4 * sizeof(YuvPixel
));
84 if (!mp
->changes_map
|| !mp
->vpt
|| !mp
->hpt
) {
85 av_freep(&mp
->changes_map
);
88 return AVERROR(ENOMEM
);
90 avctx
->pix_fmt
= AV_PIX_FMT_RGB555
;
92 mp
->frame
= av_frame_alloc();
95 return AVERROR(ENOMEM
);
101 static void mp_read_changes_map(MotionPixelsContext
*mp
, GetBitContext
*gb
, int count
, int bits_len
, int read_color
)
104 int offset
, w
, h
, color
= 0, x
, y
, i
;
107 offset
= get_bits_long(gb
, mp
->offset_bits_len
);
108 w
= get_bits(gb
, bits_len
) + 1;
109 h
= get_bits(gb
, bits_len
) + 1;
111 color
= get_bits(gb
, 15);
112 x
= offset
% mp
->avctx
->width
;
113 y
= offset
/ mp
->avctx
->width
;
114 if (y
>= mp
->avctx
->height
)
116 w
= FFMIN(w
, mp
->avctx
->width
- x
);
117 h
= FFMIN(h
, mp
->avctx
->height
- y
);
118 pixels
= (uint16_t *)&mp
->frame
->data
[0][y
* mp
->frame
->linesize
[0] + x
* 2];
120 mp
->changes_map
[offset
] = w
;
122 for (i
= 0; i
< w
; ++i
)
124 offset
+= mp
->avctx
->width
;
125 pixels
+= mp
->frame
->linesize
[0] / 2;
130 static int mp_get_code(MotionPixelsContext
*mp
, GetBitContext
*gb
, int size
, int code
)
132 while (get_bits1(gb
)) {
134 if (size
> mp
->max_codes_bits
) {
135 av_log(mp
->avctx
, AV_LOG_ERROR
, "invalid code size %d/%d\n", size
, mp
->max_codes_bits
);
136 return AVERROR_INVALIDDATA
;
139 if (mp_get_code(mp
, gb
, size
, code
+ 1) < 0)
140 return AVERROR_INVALIDDATA
;
142 if (mp
->current_codes_count
>= MAX_HUFF_CODES
) {
143 av_log(mp
->avctx
, AV_LOG_ERROR
, "too many codes\n");
144 return AVERROR_INVALIDDATA
;
147 mp
->codes
[mp
->current_codes_count
].code
= code
;
148 mp
->codes
[mp
->current_codes_count
++].size
= size
;
152 static int mp_read_codes_table(MotionPixelsContext
*mp
, GetBitContext
*gb
)
154 if (mp
->codes_count
== 1) {
155 mp
->codes
[0].delta
= get_bits(gb
, 4);
160 mp
->max_codes_bits
= get_bits(gb
, 4);
161 for (i
= 0; i
< mp
->codes_count
; ++i
)
162 mp
->codes
[i
].delta
= get_bits(gb
, 4);
163 mp
->current_codes_count
= 0;
164 if ((ret
= mp_get_code(mp
, gb
, 0, 0)) < 0)
166 if (mp
->current_codes_count
< mp
->codes_count
) {
167 av_log(mp
->avctx
, AV_LOG_ERROR
, "too few codes\n");
168 return AVERROR_INVALIDDATA
;
174 static int mp_gradient(MotionPixelsContext
*mp
, int component
, int v
)
178 delta
= (v
- 7) * mp
->gradient_scale
[component
];
179 mp
->gradient_scale
[component
] = (v
== 0 || v
== 14) ? 2 : 1;
183 static YuvPixel
mp_get_yuv_from_rgb(MotionPixelsContext
*mp
, int x
, int y
)
187 color
= *(uint16_t *)&mp
->frame
->data
[0][y
* mp
->frame
->linesize
[0] + x
* 2];
188 return mp_rgb_yuv_table
[color
];
191 static void mp_set_rgb_from_yuv(MotionPixelsContext
*mp
, int x
, int y
, const YuvPixel
*p
)
195 color
= mp_yuv_to_rgb(p
->y
, p
->v
, p
->u
, 1);
196 *(uint16_t *)&mp
->frame
->data
[0][y
* mp
->frame
->linesize
[0] + x
* 2] = color
;
199 static int mp_get_vlc(MotionPixelsContext
*mp
, GetBitContext
*gb
)
203 i
= (mp
->codes_count
== 1) ? 0 : get_vlc2(gb
, mp
->vlc
.table
, mp
->max_codes_bits
, 1);
204 return mp
->codes
[i
].delta
;
207 static void mp_decode_line(MotionPixelsContext
*mp
, GetBitContext
*gb
, int y
)
210 const int y0
= y
* mp
->avctx
->width
;
214 if (mp
->changes_map
[y0
+ x
] == 0) {
215 memset(mp
->gradient_scale
, 1, sizeof(mp
->gradient_scale
));
218 while (x
< mp
->avctx
->width
) {
219 w
= mp
->changes_map
[y0
+ x
];
222 if (mp
->changes_map
[y0
+ x
+ mp
->avctx
->width
] < w
||
223 mp
->changes_map
[y0
+ x
+ mp
->avctx
->width
* 2] < w
||
224 mp
->changes_map
[y0
+ x
+ mp
->avctx
->width
* 3] < w
) {
225 for (i
= (x
+ 3) & ~3; i
< x
+ w
; i
+= 4) {
226 mp
->hpt
[((y
/ 4) * mp
->avctx
->width
+ i
) / 4] = mp_get_yuv_from_rgb(mp
, i
, y
);
231 memset(mp
->gradient_scale
, 1, sizeof(mp
->gradient_scale
));
232 p
= mp_get_yuv_from_rgb(mp
, x
- 1, y
);
234 p
.y
+= mp_gradient(mp
, 0, mp_get_vlc(mp
, gb
));
235 p
.y
= av_clip(p
.y
, 0, 31);
238 p
.v
+= mp_gradient(mp
, 1, mp_get_vlc(mp
, gb
));
239 p
.v
= av_clip(p
.v
, -32, 31);
240 p
.u
+= mp_gradient(mp
, 2, mp_get_vlc(mp
, gb
));
241 p
.u
= av_clip(p
.u
, -32, 31);
242 mp
->hpt
[((y
/ 4) * mp
->avctx
->width
+ x
) / 4] = p
;
244 p
.v
= mp
->hpt
[((y
/ 4) * mp
->avctx
->width
+ x
) / 4].v
;
245 p
.u
= mp
->hpt
[((y
/ 4) * mp
->avctx
->width
+ x
) / 4].u
;
248 mp_set_rgb_from_yuv(mp
, x
, y
, &p
);
254 static void mp_decode_frame_helper(MotionPixelsContext
*mp
, GetBitContext
*gb
)
259 av_assert1(mp
->changes_map
[0]);
261 for (y
= 0; y
< mp
->avctx
->height
; ++y
) {
262 if (mp
->changes_map
[y
* mp
->avctx
->width
] != 0) {
263 memset(mp
->gradient_scale
, 1, sizeof(mp
->gradient_scale
));
264 p
= mp_get_yuv_from_rgb(mp
, 0, y
);
266 p
.y
+= mp_gradient(mp
, 0, mp_get_vlc(mp
, gb
));
267 p
.y
= av_clip(p
.y
, 0, 31);
269 p
.v
+= mp_gradient(mp
, 1, mp_get_vlc(mp
, gb
));
270 p
.v
= av_clip(p
.v
, -32, 31);
271 p
.u
+= mp_gradient(mp
, 2, mp_get_vlc(mp
, gb
));
272 p
.u
= av_clip(p
.u
, -32, 31);
275 mp_set_rgb_from_yuv(mp
, 0, y
, &p
);
278 for (y0
= 0; y0
< 2; ++y0
)
279 for (y
= y0
; y
< mp
->avctx
->height
; y
+= 2)
280 mp_decode_line(mp
, gb
, y
);
283 static int mp_decode_frame(AVCodecContext
*avctx
,
284 void *data
, int *got_frame
,
287 const uint8_t *buf
= avpkt
->data
;
288 int buf_size
= avpkt
->size
;
289 MotionPixelsContext
*mp
= avctx
->priv_data
;
291 int i
, count1
, count2
, sz
, ret
;
293 if ((ret
= ff_reget_buffer(avctx
, mp
->frame
)) < 0)
296 /* le32 bitstream msb first */
297 av_fast_padded_malloc(&mp
->bswapbuf
, &mp
->bswapbuf_size
, buf_size
);
299 return AVERROR(ENOMEM
);
300 mp
->bdsp
.bswap_buf((uint32_t *) mp
->bswapbuf
, (const uint32_t *) buf
,
303 memcpy(mp
->bswapbuf
+ (buf_size
& ~3), buf
+ (buf_size
& ~3), buf_size
& 3);
304 init_get_bits(&gb
, mp
->bswapbuf
, buf_size
* 8);
306 memset(mp
->changes_map
, 0, avctx
->width
* avctx
->height
);
307 for (i
= !(avctx
->extradata
[1] & 2); i
< 2; ++i
) {
308 count1
= get_bits(&gb
, 12);
309 count2
= get_bits(&gb
, 12);
310 mp_read_changes_map(mp
, &gb
, count1
, 8, i
);
311 mp_read_changes_map(mp
, &gb
, count2
, 4, i
);
314 mp
->codes_count
= get_bits(&gb
, 4);
315 if (mp
->codes_count
== 0)
318 if (mp
->changes_map
[0] == 0) {
319 *(uint16_t *)mp
->frame
->data
[0] = get_bits(&gb
, 15);
320 mp
->changes_map
[0] = 1;
322 if (mp_read_codes_table(mp
, &gb
) < 0)
325 sz
= get_bits(&gb
, 18);
326 if (avctx
->extradata
[0] != 5)
327 sz
+= get_bits(&gb
, 18);
331 if (mp
->max_codes_bits
<= 0)
333 if (init_vlc(&mp
->vlc
, mp
->max_codes_bits
, mp
->codes_count
, &mp
->codes
[0].size
, sizeof(HuffCode
), 1, &mp
->codes
[0].code
, sizeof(HuffCode
), 4, 0))
335 mp_decode_frame_helper(mp
, &gb
);
336 ff_free_vlc(&mp
->vlc
);
339 if ((ret
= av_frame_ref(data
, mp
->frame
)) < 0)
345 AVCodec ff_motionpixels_decoder
= {
346 .name
= "motionpixels",
347 .long_name
= NULL_IF_CONFIG_SMALL("Motion Pixels video"),
348 .type
= AVMEDIA_TYPE_VIDEO
,
349 .id
= AV_CODEC_ID_MOTIONPIXELS
,
350 .priv_data_size
= sizeof(MotionPixelsContext
),
351 .init
= mp_decode_init
,
352 .close
= mp_decode_end
,
353 .decode
= mp_decode_frame
,
354 .capabilities
= CODEC_CAP_DR1
,