2 * Electronic Arts TGV Video Decoder
3 * Copyright (c) 2007-2008 Peter Ross
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 St, Fifth Floor, Boston, MA 02110-1301 USA
24 * Electronic Arts TGV Video Decoder
25 * by Peter Ross (pross@xvid.org)
27 * Technical details here:
28 * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_TGV
31 #include "libavutil/imgutils.h"
32 #include "libavutil/mem.h"
34 #define BITSTREAM_READER_LE
36 #include "bitstream.h"
39 #define EA_PREAMBLE_SIZE 8
40 #define kVGT_TAG MKTAG('k', 'V', 'G', 'T')
42 typedef struct TgvContext
{
43 AVCodecContext
*avctx
;
45 uint8_t *frame_buffer
;
47 uint32_t palette
[AVPALETTE_COUNT
];
49 int (*mv_codebook
)[2];
50 uint8_t (*block_codebook
)[16];
51 int num_mvs
; ///< current length of mv_codebook
52 int num_blocks_packed
; ///< current length of block_codebook
55 static av_cold
int tgv_decode_init(AVCodecContext
*avctx
)
57 TgvContext
*s
= avctx
->priv_data
;
59 avctx
->framerate
= (AVRational
){ 15, 1 };
60 avctx
->pix_fmt
= AV_PIX_FMT_PAL8
;
62 s
->last_frame
= av_frame_alloc();
64 return AVERROR(ENOMEM
);
71 * @return 0 on success, -1 on critical buffer underflow
73 static int unpack(const uint8_t *src
, const uint8_t *src_end
,
74 uint8_t *dst
, int width
, int height
)
76 uint8_t *dst_end
= dst
+ width
*height
;
77 int size
, size1
, size2
, offset
, run
;
78 uint8_t *dst_start
= dst
;
85 if (src
+ 3 > src_end
)
86 return AVERROR_INVALIDDATA
;
90 while (size
> 0 && src
< src_end
) {
92 /* determine size1 and size2 */
94 if (src
[0] & 0x80) { // 1
95 if (src
[0] & 0x40 ) { // 11
96 if (src
[0] & 0x20) { // 111
97 if (src
[0] < 0xFC) // !(111111)
98 size1
= (((src
[0] & 31) + 1) << 2);
102 offset
= ((src
[0] & 0x10) << 12) + AV_RB16(&src
[1]) + 1;
103 size2
= ((src
[0] & 0xC) << 6) + src
[3] + 5;
107 size1
= ((src
[1] & 0xC0) >> 6);
108 offset
= (AV_RB16(&src
[1]) & 0x3FFF) + 1;
109 size2
= (src
[0] & 0x3F) + 4;
113 offset
= ((src
[0] & 0x60) << 3) + src
[1] + 1;
114 size2
= ((src
[0] & 0x1C) >> 2) + 3;
119 /* fetch strip from src */
120 if (size1
> src_end
- src
)
125 run
= FFMIN(size1
, dst_end
- dst
);
126 memcpy(dst
, src
, run
);
132 if (dst
- dst_start
< offset
)
135 run
= FFMIN(size2
, dst_end
- dst
);
136 av_memcpy_backptr(dst
, offset
, run
);
146 * @return 0 on success, -1 on critical buffer underflow
148 static int tgv_decode_inter(TgvContext
*s
, AVFrame
*frame
,
149 const uint8_t *buf
, const uint8_t *buf_end
)
153 int num_blocks_packed
;
158 const uint8_t *blocks_raw
;
160 if (buf
+ 12 > buf_end
)
161 return AVERROR_INVALIDDATA
;
163 num_mvs
= AV_RL16(&buf
[0]);
164 num_blocks_raw
= AV_RL16(&buf
[2]);
165 num_blocks_packed
= AV_RL16(&buf
[4]);
166 vector_bits
= AV_RL16(&buf
[6]);
169 if (vector_bits
> 32 || !vector_bits
) {
170 av_log(s
->avctx
, AV_LOG_ERROR
,
171 "Invalid value for motion vector bits: %d\n", vector_bits
);
172 return AVERROR_INVALIDDATA
;
175 /* allocate codebook buffers as necessary */
176 if (num_mvs
> s
->num_mvs
) {
177 int err
= av_reallocp(&s
->mv_codebook
, num_mvs
* 2 * sizeof(int));
180 s
->num_mvs
= num_mvs
;
183 if (num_blocks_packed
> s
->num_blocks_packed
) {
185 if ((err
= av_reallocp(&s
->block_codebook
, num_blocks_packed
* 16)) < 0) {
186 s
->num_blocks_packed
= 0;
189 s
->num_blocks_packed
= num_blocks_packed
;
192 /* read motion vectors */
193 mvbits
= (num_mvs
* 2 * 10 + 31) & ~31;
195 if (buf
+ (mvbits
>> 3) + 16 * num_blocks_raw
+ 8 * num_blocks_packed
> buf_end
)
196 return AVERROR_INVALIDDATA
;
198 bitstream_init(&bc
, buf
, mvbits
);
199 for (i
= 0; i
< num_mvs
; i
++) {
200 s
->mv_codebook
[i
][0] = bitstream_read_signed(&bc
, 10);
201 s
->mv_codebook
[i
][1] = bitstream_read_signed(&bc
, 10);
205 /* note ptr to uncompressed blocks */
207 buf
+= num_blocks_raw
* 16;
209 /* read compressed blocks */
210 bitstream_init8(&bc
, buf
, buf_end
- buf
);
211 for (i
= 0; i
< num_blocks_packed
; i
++) {
213 for (j
= 0; j
< 4; j
++)
214 tmp
[j
] = bitstream_read(&bc
, 8);
215 for (j
= 0; j
< 16; j
++)
216 s
->block_codebook
[i
][15-j
] = tmp
[bitstream_read(&bc
, 2)];
219 if (bitstream_bits_left(&bc
) < vector_bits
*
220 (s
->avctx
->height
/ 4) * (s
->avctx
->width
/ 4))
221 return AVERROR_INVALIDDATA
;
223 /* read vectors and build frame */
224 for (y
= 0; y
< s
->avctx
->height
/ 4; y
++)
225 for (x
= 0; x
< s
->avctx
->width
/ 4; x
++) {
226 unsigned int vector
= bitstream_read(&bc
, vector_bits
);
228 ptrdiff_t src_stride
;
230 if (vector
< num_mvs
) {
231 int mx
= x
* 4 + s
->mv_codebook
[vector
][0];
232 int my
= y
* 4 + s
->mv_codebook
[vector
][1];
234 if (mx
< 0 || mx
+ 4 > s
->avctx
->width
||
235 my
< 0 || my
+ 4 > s
->avctx
->height
)
238 src
= s
->last_frame
->data
[0] + mx
+ my
* s
->last_frame
->linesize
[0];
239 src_stride
= s
->last_frame
->linesize
[0];
241 int offset
= vector
- num_mvs
;
242 if (offset
< num_blocks_raw
)
243 src
= blocks_raw
+ 16*offset
;
244 else if (offset
- num_blocks_raw
< num_blocks_packed
)
245 src
= s
->block_codebook
[offset
- num_blocks_raw
];
251 for (j
= 0; j
< 4; j
++)
252 for (i
= 0; i
< 4; i
++)
253 frame
->data
[0][(y
* 4 + j
) * frame
->linesize
[0] + (x
* 4 + i
)] =
254 src
[j
* src_stride
+ i
];
260 static int tgv_decode_frame(AVCodecContext
*avctx
,
261 void *data
, int *got_frame
,
264 const uint8_t *buf
= avpkt
->data
;
265 int buf_size
= avpkt
->size
;
266 TgvContext
*s
= avctx
->priv_data
;
267 const uint8_t *buf_end
= buf
+ buf_size
;
268 AVFrame
*frame
= data
;
271 chunk_type
= AV_RL32(&buf
[0]);
272 buf
+= EA_PREAMBLE_SIZE
;
274 if (chunk_type
== kVGT_TAG
) {
276 if (buf
+ 12 > buf_end
) {
277 av_log(avctx
, AV_LOG_WARNING
, "truncated header\n");
278 return AVERROR_INVALIDDATA
;
281 s
->width
= AV_RL16(&buf
[0]);
282 s
->height
= AV_RL16(&buf
[2]);
283 if (s
->avctx
->width
!= s
->width
|| s
->avctx
->height
!= s
->height
) {
284 av_freep(&s
->frame_buffer
);
285 av_frame_unref(s
->last_frame
);
286 if ((ret
= ff_set_dimensions(s
->avctx
, s
->width
, s
->height
)) < 0)
290 pal_count
= AV_RL16(&buf
[6]);
292 for (i
= 0; i
< pal_count
&& i
< AVPALETTE_COUNT
&& buf
+ 2 < buf_end
; i
++) {
293 s
->palette
[i
] = AV_RB24(buf
);
298 if ((ret
= ff_get_buffer(avctx
, frame
, AV_GET_BUFFER_FLAG_REF
)) < 0)
301 memcpy(frame
->data
[1], s
->palette
, AVPALETTE_SIZE
);
303 if (chunk_type
== kVGT_TAG
) {
305 frame
->key_frame
= 1;
306 frame
->pict_type
= AV_PICTURE_TYPE_I
;
308 if (!s
->frame_buffer
&&
309 !(s
->frame_buffer
= av_malloc(s
->width
* s
->height
)))
310 return AVERROR(ENOMEM
);
312 if (unpack(buf
, buf_end
, s
->frame_buffer
, s
->avctx
->width
, s
->avctx
->height
) < 0) {
313 av_log(avctx
, AV_LOG_WARNING
, "truncated intra frame\n");
314 return AVERROR_INVALIDDATA
;
316 for (y
= 0; y
< s
->height
; y
++)
317 memcpy(frame
->data
[0] + y
* frame
->linesize
[0],
318 s
->frame_buffer
+ y
* s
->width
,
321 if (!s
->last_frame
->data
[0]) {
322 av_log(avctx
, AV_LOG_WARNING
, "inter frame without corresponding intra frame\n");
325 frame
->key_frame
= 0;
326 frame
->pict_type
= AV_PICTURE_TYPE_P
;
327 if (tgv_decode_inter(s
, frame
, buf
, buf_end
) < 0) {
328 av_log(avctx
, AV_LOG_WARNING
, "truncated inter frame\n");
329 return AVERROR_INVALIDDATA
;
333 av_frame_unref(s
->last_frame
);
334 if ((ret
= av_frame_ref(s
->last_frame
, frame
)) < 0)
342 static av_cold
int tgv_decode_end(AVCodecContext
*avctx
)
344 TgvContext
*s
= avctx
->priv_data
;
345 av_frame_free(&s
->last_frame
);
346 av_freep(&s
->frame_buffer
);
347 av_free(s
->mv_codebook
);
348 av_free(s
->block_codebook
);
352 AVCodec ff_eatgv_decoder
= {
354 .long_name
= NULL_IF_CONFIG_SMALL("Electronic Arts TGV video"),
355 .type
= AVMEDIA_TYPE_VIDEO
,
356 .id
= AV_CODEC_ID_TGV
,
357 .priv_data_size
= sizeof(TgvContext
),
358 .init
= tgv_decode_init
,
359 .close
= tgv_decode_end
,
360 .decode
= tgv_decode_frame
,
361 .capabilities
= AV_CODEC_CAP_DR1
,