2 * Copyright (c) 2003 The FFmpeg Project
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * id RoQ Video Decoder by Dr. Tim Ferguson
24 * For more information about the id RoQ format, visit:
25 * http://www.csse.monash.edu.au/~timf/
28 #include "libavutil/avassert.h"
30 #include "bytestream.h"
34 static void roqvideo_decode_frame(RoqContext
*ri
)
36 unsigned int chunk_id
= 0, chunk_arg
= 0;
37 unsigned long chunk_size
= 0;
38 int i
, j
, k
, nv1
, nv2
, vqflg
= 0, vqflg_pos
= -1;
39 int vqid
, xpos
, ypos
, xp
, yp
, x
, y
, mx
, my
;
40 int frame_stats
[2][4] = {{0},{0}};
44 while (bytestream2_get_bytes_left(&ri
->gb
) >= 8) {
45 chunk_id
= bytestream2_get_le16(&ri
->gb
);
46 chunk_size
= bytestream2_get_le32(&ri
->gb
);
47 chunk_arg
= bytestream2_get_le16(&ri
->gb
);
49 if(chunk_id
== RoQ_QUAD_VQ
)
51 if(chunk_id
== RoQ_QUAD_CODEBOOK
) {
52 if((nv1
= chunk_arg
>> 8) == 0)
54 if((nv2
= chunk_arg
& 0xff) == 0 && nv1
* 6 < chunk_size
)
56 for(i
= 0; i
< nv1
; i
++) {
57 ri
->cb2x2
[i
].y
[0] = bytestream2_get_byte(&ri
->gb
);
58 ri
->cb2x2
[i
].y
[1] = bytestream2_get_byte(&ri
->gb
);
59 ri
->cb2x2
[i
].y
[2] = bytestream2_get_byte(&ri
->gb
);
60 ri
->cb2x2
[i
].y
[3] = bytestream2_get_byte(&ri
->gb
);
61 ri
->cb2x2
[i
].u
= bytestream2_get_byte(&ri
->gb
);
62 ri
->cb2x2
[i
].v
= bytestream2_get_byte(&ri
->gb
);
64 for(i
= 0; i
< nv2
; i
++)
65 for(j
= 0; j
< 4; j
++)
66 ri
->cb4x4
[i
].idx
[j
] = bytestream2_get_byte(&ri
->gb
);
70 chunk_start
= bytestream2_tell(&ri
->gb
);
73 if (chunk_size
> bytestream2_get_bytes_left(&ri
->gb
)) {
74 av_log(ri
->avctx
, AV_LOG_ERROR
, "Chunk does not fit in input buffer\n");
75 chunk_size
= bytestream2_get_bytes_left(&ri
->gb
);
78 while (bytestream2_tell(&ri
->gb
) < chunk_start
+ chunk_size
) {
79 for (yp
= ypos
; yp
< ypos
+ 16; yp
+= 8)
80 for (xp
= xpos
; xp
< xpos
+ 16; xp
+= 8) {
81 if (bytestream2_tell(&ri
->gb
) >= chunk_start
+ chunk_size
) {
82 av_log(ri
->avctx
, AV_LOG_VERBOSE
, "Chunk is too short\n");
86 vqflg
= bytestream2_get_le16(&ri
->gb
);
89 vqid
= (vqflg
>> (vqflg_pos
* 2)) & 0x3;
90 frame_stats
[0][vqid
]++;
97 int byte
= bytestream2_get_byte(&ri
->gb
);
98 mx
= 8 - (byte
>> 4) - ((signed char) (chunk_arg
>> 8));
99 my
= 8 - (byte
& 0xf) - ((signed char) chunk_arg
);
100 ff_apply_motion_8x8(ri
, xp
, yp
, mx
, my
);
104 qcell
= ri
->cb4x4
+ bytestream2_get_byte(&ri
->gb
);
105 ff_apply_vector_4x4(ri
, xp
, yp
, ri
->cb2x2
+ qcell
->idx
[0]);
106 ff_apply_vector_4x4(ri
, xp
+ 4, yp
, ri
->cb2x2
+ qcell
->idx
[1]);
107 ff_apply_vector_4x4(ri
, xp
, yp
+ 4, ri
->cb2x2
+ qcell
->idx
[2]);
108 ff_apply_vector_4x4(ri
, xp
+ 4, yp
+ 4, ri
->cb2x2
+ qcell
->idx
[3]);
111 for (k
= 0; k
< 4; k
++) {
116 if (bytestream2_tell(&ri
->gb
) >= chunk_start
+ chunk_size
) {
117 av_log(ri
->avctx
, AV_LOG_VERBOSE
, "Chunk is too short\n");
121 vqflg
= bytestream2_get_le16(&ri
->gb
);
124 vqid
= (vqflg
>> (vqflg_pos
* 2)) & 0x3;
125 frame_stats
[1][vqid
]++;
131 int byte
= bytestream2_get_byte(&ri
->gb
);
132 mx
= 8 - (byte
>> 4) - ((signed char) (chunk_arg
>> 8));
133 my
= 8 - (byte
& 0xf) - ((signed char) chunk_arg
);
134 ff_apply_motion_4x4(ri
, x
, y
, mx
, my
);
138 qcell
= ri
->cb4x4
+ bytestream2_get_byte(&ri
->gb
);
139 ff_apply_vector_2x2(ri
, x
, y
, ri
->cb2x2
+ qcell
->idx
[0]);
140 ff_apply_vector_2x2(ri
, x
+ 2, y
, ri
->cb2x2
+ qcell
->idx
[1]);
141 ff_apply_vector_2x2(ri
, x
, y
+ 2, ri
->cb2x2
+ qcell
->idx
[2]);
142 ff_apply_vector_2x2(ri
, x
+ 2, y
+ 2, ri
->cb2x2
+ qcell
->idx
[3]);
145 ff_apply_vector_2x2(ri
, x
, y
, ri
->cb2x2
+ bytestream2_get_byte(&ri
->gb
));
146 ff_apply_vector_2x2(ri
, x
+ 2, y
, ri
->cb2x2
+ bytestream2_get_byte(&ri
->gb
));
147 ff_apply_vector_2x2(ri
, x
, y
+ 2, ri
->cb2x2
+ bytestream2_get_byte(&ri
->gb
));
148 ff_apply_vector_2x2(ri
, x
+ 2, y
+ 2, ri
->cb2x2
+ bytestream2_get_byte(&ri
->gb
));
159 if (xpos
>= ri
->width
) {
163 if(ypos
>= ri
->height
)
169 static av_cold
int roq_decode_init(AVCodecContext
*avctx
)
171 RoqContext
*s
= avctx
->priv_data
;
175 if (avctx
->width
% 16 || avctx
->height
% 16) {
176 av_log(avctx
, AV_LOG_ERROR
,
177 "Dimensions must be a multiple of 16\n");
178 return AVERROR_PATCHWELCOME
;
181 s
->width
= avctx
->width
;
182 s
->height
= avctx
->height
;
184 s
->last_frame
= av_frame_alloc();
185 s
->current_frame
= av_frame_alloc();
186 if (!s
->current_frame
|| !s
->last_frame
) {
187 av_frame_free(&s
->current_frame
);
188 av_frame_free(&s
->last_frame
);
189 return AVERROR(ENOMEM
);
192 avctx
->pix_fmt
= AV_PIX_FMT_YUVJ444P
;
193 avctx
->color_range
= AVCOL_RANGE_JPEG
;
198 static int roq_decode_frame(AVCodecContext
*avctx
,
199 void *data
, int *got_frame
,
202 const uint8_t *buf
= avpkt
->data
;
203 int buf_size
= avpkt
->size
;
204 RoqContext
*s
= avctx
->priv_data
;
205 int copy
= !s
->current_frame
->data
[0];
208 if ((ret
= ff_reget_buffer(avctx
, s
->current_frame
)) < 0)
212 av_picture_copy((AVPicture
*)s
->current_frame
, (AVPicture
*)s
->last_frame
,
213 avctx
->pix_fmt
, avctx
->width
, avctx
->height
);
215 bytestream2_init(&s
->gb
, buf
, buf_size
);
216 roqvideo_decode_frame(s
);
218 if ((ret
= av_frame_ref(data
, s
->current_frame
)) < 0)
223 FFSWAP(AVFrame
*, s
->current_frame
, s
->last_frame
);
228 static av_cold
int roq_decode_end(AVCodecContext
*avctx
)
230 RoqContext
*s
= avctx
->priv_data
;
232 av_frame_free(&s
->current_frame
);
233 av_frame_free(&s
->last_frame
);
238 AVCodec ff_roq_decoder
= {
240 .long_name
= NULL_IF_CONFIG_SMALL("id RoQ video"),
241 .type
= AVMEDIA_TYPE_VIDEO
,
242 .id
= AV_CODEC_ID_ROQ
,
243 .priv_data_size
= sizeof(RoqContext
),
244 .init
= roq_decode_init
,
245 .close
= roq_decode_end
,
246 .decode
= roq_decode_frame
,
247 .capabilities
= CODEC_CAP_DR1
,