| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (C) 2003 The FFmpeg project | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 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. | ||
| 10 | * | ||
| 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. | ||
| 15 | * | ||
| 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 | ||
| 19 | */ | ||
| 20 | |||
| 21 | /** | ||
| 22 | * @file | ||
| 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/ | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include "libavutil/avassert.h" | ||
| 29 | |||
| 30 | #include "avcodec.h" | ||
| 31 | #include "bytestream.h" | ||
| 32 | #include "codec_internal.h" | ||
| 33 | #include "decode.h" | ||
| 34 | #include "roqvideo.h" | ||
| 35 | |||
| 36 | 225 | static void roqvideo_decode_frame(RoqContext *ri, GetByteContext *gb) | |
| 37 | { | ||
| 38 | 225 | unsigned int chunk_id = 0, chunk_arg = 0; | |
| 39 | 225 | unsigned long chunk_size = 0; | |
| 40 | 225 | int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1; | |
| 41 | int vqid, xpos, ypos, xp, yp, x, y, mx, my; | ||
| 42 | roq_qcell *qcell; | ||
| 43 | int64_t chunk_start; | ||
| 44 | |||
| 45 |
1/2✓ Branch 1 taken 428 times.
✗ Branch 2 not taken.
|
428 | while (bytestream2_get_bytes_left(gb) >= 8) { |
| 46 | 428 | chunk_id = bytestream2_get_le16(gb); | |
| 47 | 428 | chunk_size = bytestream2_get_le32(gb); | |
| 48 | 428 | chunk_arg = bytestream2_get_le16(gb); | |
| 49 | |||
| 50 |
2/2✓ Branch 0 taken 225 times.
✓ Branch 1 taken 203 times.
|
428 | if(chunk_id == RoQ_QUAD_VQ) |
| 51 | 225 | break; | |
| 52 |
1/2✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
|
203 | if(chunk_id == RoQ_QUAD_CODEBOOK) { |
| 53 |
2/2✓ Branch 0 taken 68 times.
✓ Branch 1 taken 135 times.
|
203 | if((nv1 = chunk_arg >> 8) == 0) |
| 54 | 68 | nv1 = 256; | |
| 55 |
4/4✓ Branch 0 taken 47 times.
✓ Branch 1 taken 156 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 46 times.
|
203 | if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size) |
| 56 | 1 | nv2 = 256; | |
| 57 |
2/2✓ Branch 0 taken 50900 times.
✓ Branch 1 taken 203 times.
|
51103 | for(i = 0; i < nv1; i++) { |
| 58 | 50900 | ri->cb2x2[i].y[0] = bytestream2_get_byte(gb); | |
| 59 | 50900 | ri->cb2x2[i].y[1] = bytestream2_get_byte(gb); | |
| 60 | 50900 | ri->cb2x2[i].y[2] = bytestream2_get_byte(gb); | |
| 61 | 50900 | ri->cb2x2[i].y[3] = bytestream2_get_byte(gb); | |
| 62 | 50900 | ri->cb2x2[i].u = bytestream2_get_byte(gb); | |
| 63 | 50900 | ri->cb2x2[i].v = bytestream2_get_byte(gb); | |
| 64 | } | ||
| 65 |
2/2✓ Branch 0 taken 17747 times.
✓ Branch 1 taken 203 times.
|
17950 | for(i = 0; i < nv2; i++) |
| 66 |
2/2✓ Branch 0 taken 70988 times.
✓ Branch 1 taken 17747 times.
|
88735 | for(j = 0; j < 4; j++) |
| 67 | 70988 | ri->cb4x4[i].idx[j] = bytestream2_get_byte(gb); | |
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | 225 | chunk_start = bytestream2_tell(gb); | |
| 72 | 225 | xpos = ypos = 0; | |
| 73 | |||
| 74 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 225 times.
|
225 | if (chunk_size > bytestream2_get_bytes_left(gb)) { |
| 75 | ✗ | av_log(ri->logctx, AV_LOG_ERROR, "Chunk does not fit in input buffer\n"); | |
| 76 | ✗ | chunk_size = bytestream2_get_bytes_left(gb); | |
| 77 | } | ||
| 78 | |||
| 79 |
1/2✓ Branch 1 taken 113460 times.
✗ Branch 2 not taken.
|
113460 | while (bytestream2_tell(gb) < chunk_start + chunk_size) { |
| 80 |
2/2✓ Branch 0 taken 226916 times.
✓ Branch 1 taken 113426 times.
|
340342 | for (yp = ypos; yp < ypos + 16; yp += 8) |
| 81 |
2/2✓ Branch 0 taken 453825 times.
✓ Branch 1 taken 226882 times.
|
680707 | for (xp = xpos; xp < xpos + 16; xp += 8) { |
| 82 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 453821 times.
|
453825 | if (bytestream2_tell(gb) >= chunk_start + chunk_size) { |
| 83 | 4 | av_log(ri->logctx, AV_LOG_VERBOSE, "Chunk is too short\n"); | |
| 84 | 4 | return; | |
| 85 | } | ||
| 86 |
2/2✓ Branch 0 taken 56773 times.
✓ Branch 1 taken 397048 times.
|
453821 | if (vqflg_pos < 0) { |
| 87 | 56773 | vqflg = bytestream2_get_le16(gb); | |
| 88 | 56773 | vqflg_pos = 7; | |
| 89 | } | ||
| 90 | 453821 | vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; | |
| 91 | 453821 | vqflg_pos--; | |
| 92 | |||
| 93 |
4/5✓ Branch 0 taken 121748 times.
✓ Branch 1 taken 9309 times.
✓ Branch 2 taken 7024 times.
✓ Branch 3 taken 315740 times.
✗ Branch 4 not taken.
|
453821 | switch(vqid) { |
| 94 | 121748 | case RoQ_ID_MOT: | |
| 95 | 121748 | break; | |
| 96 | 9309 | case RoQ_ID_FCC: { | |
| 97 | 9309 | int byte = bytestream2_get_byte(gb); | |
| 98 | 9309 | mx = 8 - (byte >> 4) - ((signed char) (chunk_arg >> 8)); | |
| 99 | 9309 | my = 8 - (byte & 0xf) - ((signed char) chunk_arg); | |
| 100 | 9309 | ff_apply_motion_8x8(ri, xp, yp, mx, my); | |
| 101 | 9309 | break; | |
| 102 | } | ||
| 103 | 7024 | case RoQ_ID_SLD: | |
| 104 | 7024 | qcell = ri->cb4x4 + bytestream2_get_byte(gb); | |
| 105 | 7024 | ff_apply_vector_4x4(ri, xp, yp, ri->cb2x2 + qcell->idx[0]); | |
| 106 | 7024 | ff_apply_vector_4x4(ri, xp + 4, yp, ri->cb2x2 + qcell->idx[1]); | |
| 107 | 7024 | ff_apply_vector_4x4(ri, xp, yp + 4, ri->cb2x2 + qcell->idx[2]); | |
| 108 | 7024 | ff_apply_vector_4x4(ri, xp + 4, yp + 4, ri->cb2x2 + qcell->idx[3]); | |
| 109 | 7024 | break; | |
| 110 | 315740 | case RoQ_ID_CCC: | |
| 111 |
2/2✓ Branch 0 taken 1262949 times.
✓ Branch 1 taken 315710 times.
|
1578659 | for (k = 0; k < 4; k++) { |
| 112 | 1262949 | x = xp; y = yp; | |
| 113 |
2/2✓ Branch 0 taken 631469 times.
✓ Branch 1 taken 631480 times.
|
1262949 | if(k & 0x01) x += 4; |
| 114 |
2/2✓ Branch 0 taken 631469 times.
✓ Branch 1 taken 631480 times.
|
1262949 | if(k & 0x02) y += 4; |
| 115 | |||
| 116 |
2/2✓ Branch 1 taken 30 times.
✓ Branch 2 taken 1262919 times.
|
1262949 | if (bytestream2_tell(gb) >= chunk_start + chunk_size) { |
| 117 | 30 | av_log(ri->logctx, AV_LOG_VERBOSE, "Chunk is too short\n"); | |
| 118 | 30 | return; | |
| 119 | } | ||
| 120 |
2/2✓ Branch 0 taken 157875 times.
✓ Branch 1 taken 1105044 times.
|
1262919 | if (vqflg_pos < 0) { |
| 121 | 157875 | vqflg = bytestream2_get_le16(gb); | |
| 122 | 157875 | vqflg_pos = 7; | |
| 123 | } | ||
| 124 | 1262919 | vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; | |
| 125 | 1262919 | vqflg_pos--; | |
| 126 |
4/5✓ Branch 0 taken 259086 times.
✓ Branch 1 taken 522066 times.
✓ Branch 2 taken 116905 times.
✓ Branch 3 taken 364862 times.
✗ Branch 4 not taken.
|
1262919 | switch(vqid) { |
| 127 | 259086 | case RoQ_ID_MOT: | |
| 128 | 259086 | break; | |
| 129 | 522066 | case RoQ_ID_FCC: { | |
| 130 | 522066 | int byte = bytestream2_get_byte(gb); | |
| 131 | 522066 | mx = 8 - (byte >> 4) - ((signed char) (chunk_arg >> 8)); | |
| 132 | 522066 | my = 8 - (byte & 0xf) - ((signed char) chunk_arg); | |
| 133 | 522066 | ff_apply_motion_4x4(ri, x, y, mx, my); | |
| 134 | 522066 | break; | |
| 135 | } | ||
| 136 | 116905 | case RoQ_ID_SLD: | |
| 137 | 116905 | qcell = ri->cb4x4 + bytestream2_get_byte(gb); | |
| 138 | 116905 | ff_apply_vector_2x2(ri, x, y, ri->cb2x2 + qcell->idx[0]); | |
| 139 | 116905 | ff_apply_vector_2x2(ri, x + 2, y, ri->cb2x2 + qcell->idx[1]); | |
| 140 | 116905 | ff_apply_vector_2x2(ri, x, y + 2, ri->cb2x2 + qcell->idx[2]); | |
| 141 | 116905 | ff_apply_vector_2x2(ri, x + 2, y + 2, ri->cb2x2 + qcell->idx[3]); | |
| 142 | 116905 | break; | |
| 143 | 364862 | case RoQ_ID_CCC: | |
| 144 | 364862 | ff_apply_vector_2x2(ri, x, y, ri->cb2x2 + bytestream2_get_byte(gb)); | |
| 145 | 364862 | ff_apply_vector_2x2(ri, x + 2, y, ri->cb2x2 + bytestream2_get_byte(gb)); | |
| 146 | 364862 | ff_apply_vector_2x2(ri, x, y + 2, ri->cb2x2 + bytestream2_get_byte(gb)); | |
| 147 | 364862 | ff_apply_vector_2x2(ri, x + 2, y + 2, ri->cb2x2 + bytestream2_get_byte(gb)); | |
| 148 | 364862 | break; | |
| 149 | } | ||
| 150 | } | ||
| 151 | 315710 | break; | |
| 152 | 453791 | default: | |
| 153 | av_assert2(0); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | 113426 | xpos += 16; | |
| 158 |
2/2✓ Branch 0 taken 3596 times.
✓ Branch 1 taken 109830 times.
|
113426 | if (xpos >= ri->width) { |
| 159 | 3596 | xpos -= ri->width; | |
| 160 | 3596 | ypos += 16; | |
| 161 | } | ||
| 162 |
2/2✓ Branch 0 taken 191 times.
✓ Branch 1 taken 113235 times.
|
113426 | if(ypos >= ri->height) |
| 163 | 191 | break; | |
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | |||
| 168 | 10 | static av_cold int roq_decode_init(AVCodecContext *avctx) | |
| 169 | { | ||
| 170 | 10 | RoqContext *s = avctx->priv_data; | |
| 171 | |||
| 172 | 10 | s->logctx = avctx; | |
| 173 | |||
| 174 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
10 | if (avctx->width % 16 || avctx->height % 16) { |
| 175 | ✗ | avpriv_request_sample(avctx, "Dimensions not being a multiple of 16"); | |
| 176 | ✗ | return AVERROR_PATCHWELCOME; | |
| 177 | } | ||
| 178 | |||
| 179 | 10 | s->width = avctx->width; | |
| 180 | 10 | s->height = avctx->height; | |
| 181 | |||
| 182 | 10 | s->last_frame = av_frame_alloc(); | |
| 183 | 10 | s->current_frame = av_frame_alloc(); | |
| 184 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
10 | if (!s->current_frame || !s->last_frame) |
| 185 | ✗ | return AVERROR(ENOMEM); | |
| 186 | |||
| 187 | 10 | avctx->pix_fmt = AV_PIX_FMT_YUVJ444P; | |
| 188 | 10 | avctx->color_range = AVCOL_RANGE_JPEG; | |
| 189 | |||
| 190 | 10 | return 0; | |
| 191 | } | ||
| 192 | |||
| 193 | 225 | static int roq_decode_frame(AVCodecContext *avctx, AVFrame *rframe, | |
| 194 | int *got_frame, AVPacket *avpkt) | ||
| 195 | { | ||
| 196 | 225 | const uint8_t *buf = avpkt->data; | |
| 197 | 225 | int buf_size = avpkt->size; | |
| 198 | 225 | RoqContext *s = avctx->priv_data; | |
| 199 |
4/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 217 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
|
225 | int copy = !s->current_frame->data[0] && s->last_frame->data[0]; |
| 200 | GetByteContext gb; | ||
| 201 | int ret; | ||
| 202 | |||
| 203 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 225 times.
|
225 | if ((ret = ff_reget_buffer(avctx, s->current_frame, 0)) < 0) |
| 204 | ✗ | return ret; | |
| 205 | |||
| 206 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 221 times.
|
225 | if (copy) { |
| 207 | 4 | ret = av_frame_copy(s->current_frame, s->last_frame); | |
| 208 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (ret < 0) |
| 209 | ✗ | return ret; | |
| 210 | } | ||
| 211 | |||
| 212 | 225 | bytestream2_init(&gb, buf, buf_size); | |
| 213 | 225 | roqvideo_decode_frame(s, &gb); | |
| 214 | |||
| 215 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 225 times.
|
225 | if ((ret = av_frame_ref(rframe, s->current_frame)) < 0) |
| 216 | ✗ | return ret; | |
| 217 | 225 | *got_frame = 1; | |
| 218 | |||
| 219 | /* shuffle frames */ | ||
| 220 | 225 | FFSWAP(AVFrame *, s->current_frame, s->last_frame); | |
| 221 | |||
| 222 | 225 | return buf_size; | |
| 223 | } | ||
| 224 | |||
| 225 | 10 | static av_cold int roq_decode_end(AVCodecContext *avctx) | |
| 226 | { | ||
| 227 | 10 | RoqContext *s = avctx->priv_data; | |
| 228 | |||
| 229 | 10 | av_frame_free(&s->current_frame); | |
| 230 | 10 | av_frame_free(&s->last_frame); | |
| 231 | |||
| 232 | 10 | return 0; | |
| 233 | } | ||
| 234 | |||
| 235 | const FFCodec ff_roq_decoder = { | ||
| 236 | .p.name = "roqvideo", | ||
| 237 | CODEC_LONG_NAME("id RoQ video"), | ||
| 238 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
| 239 | .p.id = AV_CODEC_ID_ROQ, | ||
| 240 | .priv_data_size = sizeof(RoqContext), | ||
| 241 | .init = roq_decode_init, | ||
| 242 | .close = roq_decode_end, | ||
| 243 | FF_CODEC_DECODE_CB(roq_decode_frame), | ||
| 244 | .p.capabilities = AV_CODEC_CAP_DR1, | ||
| 245 | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, | ||
| 246 | }; | ||
| 247 |