1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (C) 2003 The FFmpeg project 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14cabdff1aSopenharmony_ci * Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci/** 22cabdff1aSopenharmony_ci * @file 23cabdff1aSopenharmony_ci * id RoQ Video Decoder by Dr. Tim Ferguson 24cabdff1aSopenharmony_ci * For more information about the id RoQ format, visit: 25cabdff1aSopenharmony_ci * http://www.csse.monash.edu.au/~timf/ 26cabdff1aSopenharmony_ci */ 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 29cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_ci#include "avcodec.h" 32cabdff1aSopenharmony_ci#include "bytestream.h" 33cabdff1aSopenharmony_ci#include "codec_internal.h" 34cabdff1aSopenharmony_ci#include "internal.h" 35cabdff1aSopenharmony_ci#include "roqvideo.h" 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_cistatic void roqvideo_decode_frame(RoqContext *ri, GetByteContext *gb) 38cabdff1aSopenharmony_ci{ 39cabdff1aSopenharmony_ci unsigned int chunk_id = 0, chunk_arg = 0; 40cabdff1aSopenharmony_ci unsigned long chunk_size = 0; 41cabdff1aSopenharmony_ci int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1; 42cabdff1aSopenharmony_ci int vqid, xpos, ypos, xp, yp, x, y, mx, my; 43cabdff1aSopenharmony_ci roq_qcell *qcell; 44cabdff1aSopenharmony_ci int64_t chunk_start; 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_ci while (bytestream2_get_bytes_left(gb) >= 8) { 47cabdff1aSopenharmony_ci chunk_id = bytestream2_get_le16(gb); 48cabdff1aSopenharmony_ci chunk_size = bytestream2_get_le32(gb); 49cabdff1aSopenharmony_ci chunk_arg = bytestream2_get_le16(gb); 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_ci if(chunk_id == RoQ_QUAD_VQ) 52cabdff1aSopenharmony_ci break; 53cabdff1aSopenharmony_ci if(chunk_id == RoQ_QUAD_CODEBOOK) { 54cabdff1aSopenharmony_ci if((nv1 = chunk_arg >> 8) == 0) 55cabdff1aSopenharmony_ci nv1 = 256; 56cabdff1aSopenharmony_ci if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size) 57cabdff1aSopenharmony_ci nv2 = 256; 58cabdff1aSopenharmony_ci for(i = 0; i < nv1; i++) { 59cabdff1aSopenharmony_ci ri->cb2x2[i].y[0] = bytestream2_get_byte(gb); 60cabdff1aSopenharmony_ci ri->cb2x2[i].y[1] = bytestream2_get_byte(gb); 61cabdff1aSopenharmony_ci ri->cb2x2[i].y[2] = bytestream2_get_byte(gb); 62cabdff1aSopenharmony_ci ri->cb2x2[i].y[3] = bytestream2_get_byte(gb); 63cabdff1aSopenharmony_ci ri->cb2x2[i].u = bytestream2_get_byte(gb); 64cabdff1aSopenharmony_ci ri->cb2x2[i].v = bytestream2_get_byte(gb); 65cabdff1aSopenharmony_ci } 66cabdff1aSopenharmony_ci for(i = 0; i < nv2; i++) 67cabdff1aSopenharmony_ci for(j = 0; j < 4; j++) 68cabdff1aSopenharmony_ci ri->cb4x4[i].idx[j] = bytestream2_get_byte(gb); 69cabdff1aSopenharmony_ci } 70cabdff1aSopenharmony_ci } 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci chunk_start = bytestream2_tell(gb); 73cabdff1aSopenharmony_ci xpos = ypos = 0; 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_ci if (chunk_size > bytestream2_get_bytes_left(gb)) { 76cabdff1aSopenharmony_ci av_log(ri->avctx, AV_LOG_ERROR, "Chunk does not fit in input buffer\n"); 77cabdff1aSopenharmony_ci chunk_size = bytestream2_get_bytes_left(gb); 78cabdff1aSopenharmony_ci } 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_ci while (bytestream2_tell(gb) < chunk_start + chunk_size) { 81cabdff1aSopenharmony_ci for (yp = ypos; yp < ypos + 16; yp += 8) 82cabdff1aSopenharmony_ci for (xp = xpos; xp < xpos + 16; xp += 8) { 83cabdff1aSopenharmony_ci if (bytestream2_tell(gb) >= chunk_start + chunk_size) { 84cabdff1aSopenharmony_ci av_log(ri->avctx, AV_LOG_VERBOSE, "Chunk is too short\n"); 85cabdff1aSopenharmony_ci return; 86cabdff1aSopenharmony_ci } 87cabdff1aSopenharmony_ci if (vqflg_pos < 0) { 88cabdff1aSopenharmony_ci vqflg = bytestream2_get_le16(gb); 89cabdff1aSopenharmony_ci vqflg_pos = 7; 90cabdff1aSopenharmony_ci } 91cabdff1aSopenharmony_ci vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; 92cabdff1aSopenharmony_ci vqflg_pos--; 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_ci switch(vqid) { 95cabdff1aSopenharmony_ci case RoQ_ID_MOT: 96cabdff1aSopenharmony_ci break; 97cabdff1aSopenharmony_ci case RoQ_ID_FCC: { 98cabdff1aSopenharmony_ci int byte = bytestream2_get_byte(gb); 99cabdff1aSopenharmony_ci mx = 8 - (byte >> 4) - ((signed char) (chunk_arg >> 8)); 100cabdff1aSopenharmony_ci my = 8 - (byte & 0xf) - ((signed char) chunk_arg); 101cabdff1aSopenharmony_ci ff_apply_motion_8x8(ri, xp, yp, mx, my); 102cabdff1aSopenharmony_ci break; 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci case RoQ_ID_SLD: 105cabdff1aSopenharmony_ci qcell = ri->cb4x4 + bytestream2_get_byte(gb); 106cabdff1aSopenharmony_ci ff_apply_vector_4x4(ri, xp, yp, ri->cb2x2 + qcell->idx[0]); 107cabdff1aSopenharmony_ci ff_apply_vector_4x4(ri, xp + 4, yp, ri->cb2x2 + qcell->idx[1]); 108cabdff1aSopenharmony_ci ff_apply_vector_4x4(ri, xp, yp + 4, ri->cb2x2 + qcell->idx[2]); 109cabdff1aSopenharmony_ci ff_apply_vector_4x4(ri, xp + 4, yp + 4, ri->cb2x2 + qcell->idx[3]); 110cabdff1aSopenharmony_ci break; 111cabdff1aSopenharmony_ci case RoQ_ID_CCC: 112cabdff1aSopenharmony_ci for (k = 0; k < 4; k++) { 113cabdff1aSopenharmony_ci x = xp; y = yp; 114cabdff1aSopenharmony_ci if(k & 0x01) x += 4; 115cabdff1aSopenharmony_ci if(k & 0x02) y += 4; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci if (bytestream2_tell(gb) >= chunk_start + chunk_size) { 118cabdff1aSopenharmony_ci av_log(ri->avctx, AV_LOG_VERBOSE, "Chunk is too short\n"); 119cabdff1aSopenharmony_ci return; 120cabdff1aSopenharmony_ci } 121cabdff1aSopenharmony_ci if (vqflg_pos < 0) { 122cabdff1aSopenharmony_ci vqflg = bytestream2_get_le16(gb); 123cabdff1aSopenharmony_ci vqflg_pos = 7; 124cabdff1aSopenharmony_ci } 125cabdff1aSopenharmony_ci vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; 126cabdff1aSopenharmony_ci vqflg_pos--; 127cabdff1aSopenharmony_ci switch(vqid) { 128cabdff1aSopenharmony_ci case RoQ_ID_MOT: 129cabdff1aSopenharmony_ci break; 130cabdff1aSopenharmony_ci case RoQ_ID_FCC: { 131cabdff1aSopenharmony_ci int byte = bytestream2_get_byte(gb); 132cabdff1aSopenharmony_ci mx = 8 - (byte >> 4) - ((signed char) (chunk_arg >> 8)); 133cabdff1aSopenharmony_ci my = 8 - (byte & 0xf) - ((signed char) chunk_arg); 134cabdff1aSopenharmony_ci ff_apply_motion_4x4(ri, x, y, mx, my); 135cabdff1aSopenharmony_ci break; 136cabdff1aSopenharmony_ci } 137cabdff1aSopenharmony_ci case RoQ_ID_SLD: 138cabdff1aSopenharmony_ci qcell = ri->cb4x4 + bytestream2_get_byte(gb); 139cabdff1aSopenharmony_ci ff_apply_vector_2x2(ri, x, y, ri->cb2x2 + qcell->idx[0]); 140cabdff1aSopenharmony_ci ff_apply_vector_2x2(ri, x + 2, y, ri->cb2x2 + qcell->idx[1]); 141cabdff1aSopenharmony_ci ff_apply_vector_2x2(ri, x, y + 2, ri->cb2x2 + qcell->idx[2]); 142cabdff1aSopenharmony_ci ff_apply_vector_2x2(ri, x + 2, y + 2, ri->cb2x2 + qcell->idx[3]); 143cabdff1aSopenharmony_ci break; 144cabdff1aSopenharmony_ci case RoQ_ID_CCC: 145cabdff1aSopenharmony_ci ff_apply_vector_2x2(ri, x, y, ri->cb2x2 + bytestream2_get_byte(gb)); 146cabdff1aSopenharmony_ci ff_apply_vector_2x2(ri, x + 2, y, ri->cb2x2 + bytestream2_get_byte(gb)); 147cabdff1aSopenharmony_ci ff_apply_vector_2x2(ri, x, y + 2, ri->cb2x2 + bytestream2_get_byte(gb)); 148cabdff1aSopenharmony_ci ff_apply_vector_2x2(ri, x + 2, y + 2, ri->cb2x2 + bytestream2_get_byte(gb)); 149cabdff1aSopenharmony_ci break; 150cabdff1aSopenharmony_ci } 151cabdff1aSopenharmony_ci } 152cabdff1aSopenharmony_ci break; 153cabdff1aSopenharmony_ci default: 154cabdff1aSopenharmony_ci av_assert2(0); 155cabdff1aSopenharmony_ci } 156cabdff1aSopenharmony_ci } 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci xpos += 16; 159cabdff1aSopenharmony_ci if (xpos >= ri->width) { 160cabdff1aSopenharmony_ci xpos -= ri->width; 161cabdff1aSopenharmony_ci ypos += 16; 162cabdff1aSopenharmony_ci } 163cabdff1aSopenharmony_ci if(ypos >= ri->height) 164cabdff1aSopenharmony_ci break; 165cabdff1aSopenharmony_ci } 166cabdff1aSopenharmony_ci} 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci 169cabdff1aSopenharmony_cistatic av_cold int roq_decode_init(AVCodecContext *avctx) 170cabdff1aSopenharmony_ci{ 171cabdff1aSopenharmony_ci RoqContext *s = avctx->priv_data; 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci s->avctx = avctx; 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci if (avctx->width % 16 || avctx->height % 16) { 176cabdff1aSopenharmony_ci avpriv_request_sample(avctx, "Dimensions not being a multiple of 16"); 177cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 178cabdff1aSopenharmony_ci } 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci s->width = avctx->width; 181cabdff1aSopenharmony_ci s->height = avctx->height; 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_ci s->last_frame = av_frame_alloc(); 184cabdff1aSopenharmony_ci s->current_frame = av_frame_alloc(); 185cabdff1aSopenharmony_ci if (!s->current_frame || !s->last_frame) 186cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 187cabdff1aSopenharmony_ci 188cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUVJ444P; 189cabdff1aSopenharmony_ci avctx->color_range = AVCOL_RANGE_JPEG; 190cabdff1aSopenharmony_ci 191cabdff1aSopenharmony_ci return 0; 192cabdff1aSopenharmony_ci} 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_cistatic int roq_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 195cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 196cabdff1aSopenharmony_ci{ 197cabdff1aSopenharmony_ci const uint8_t *buf = avpkt->data; 198cabdff1aSopenharmony_ci int buf_size = avpkt->size; 199cabdff1aSopenharmony_ci RoqContext *s = avctx->priv_data; 200cabdff1aSopenharmony_ci int copy = !s->current_frame->data[0] && s->last_frame->data[0]; 201cabdff1aSopenharmony_ci GetByteContext gb; 202cabdff1aSopenharmony_ci int ret; 203cabdff1aSopenharmony_ci 204cabdff1aSopenharmony_ci if ((ret = ff_reget_buffer(avctx, s->current_frame, 0)) < 0) 205cabdff1aSopenharmony_ci return ret; 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci if (copy) { 208cabdff1aSopenharmony_ci ret = av_frame_copy(s->current_frame, s->last_frame); 209cabdff1aSopenharmony_ci if (ret < 0) 210cabdff1aSopenharmony_ci return ret; 211cabdff1aSopenharmony_ci } 212cabdff1aSopenharmony_ci 213cabdff1aSopenharmony_ci bytestream2_init(&gb, buf, buf_size); 214cabdff1aSopenharmony_ci roqvideo_decode_frame(s, &gb); 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci if ((ret = av_frame_ref(rframe, s->current_frame)) < 0) 217cabdff1aSopenharmony_ci return ret; 218cabdff1aSopenharmony_ci *got_frame = 1; 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci /* shuffle frames */ 221cabdff1aSopenharmony_ci FFSWAP(AVFrame *, s->current_frame, s->last_frame); 222cabdff1aSopenharmony_ci 223cabdff1aSopenharmony_ci return buf_size; 224cabdff1aSopenharmony_ci} 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_cistatic av_cold int roq_decode_end(AVCodecContext *avctx) 227cabdff1aSopenharmony_ci{ 228cabdff1aSopenharmony_ci RoqContext *s = avctx->priv_data; 229cabdff1aSopenharmony_ci 230cabdff1aSopenharmony_ci av_frame_free(&s->current_frame); 231cabdff1aSopenharmony_ci av_frame_free(&s->last_frame); 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci return 0; 234cabdff1aSopenharmony_ci} 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_ciconst FFCodec ff_roq_decoder = { 237cabdff1aSopenharmony_ci .p.name = "roqvideo", 238cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("id RoQ video"), 239cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 240cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_ROQ, 241cabdff1aSopenharmony_ci .priv_data_size = sizeof(RoqContext), 242cabdff1aSopenharmony_ci .init = roq_decode_init, 243cabdff1aSopenharmony_ci .close = roq_decode_end, 244cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(roq_decode_frame), 245cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 246cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, 247cabdff1aSopenharmony_ci}; 248