Libav
|
00001 /* 00002 * Copyright (C) 2003 the ffmpeg project 00003 * 00004 * This file is part of FFmpeg. 00005 * 00006 * FFmpeg is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * FFmpeg is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with FFmpeg; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00028 #include <stdio.h> 00029 #include <stdlib.h> 00030 #include <string.h> 00031 00032 #include "avcodec.h" 00033 #include "bytestream.h" 00034 #include "roqvideo.h" 00035 00036 static void roqvideo_decode_frame(RoqContext *ri) 00037 { 00038 unsigned int chunk_id = 0, chunk_arg = 0; 00039 unsigned long chunk_size = 0; 00040 int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1; 00041 int vqid, bpos, xpos, ypos, xp, yp, x, y, mx, my; 00042 int frame_stats[2][4] = {{0},{0}}; 00043 roq_qcell *qcell; 00044 const unsigned char *buf = ri->buf; 00045 const unsigned char *buf_end = ri->buf + ri->size; 00046 00047 while (buf < buf_end) { 00048 chunk_id = bytestream_get_le16(&buf); 00049 chunk_size = bytestream_get_le32(&buf); 00050 chunk_arg = bytestream_get_le16(&buf); 00051 00052 if(chunk_id == RoQ_QUAD_VQ) 00053 break; 00054 if(chunk_id == RoQ_QUAD_CODEBOOK) { 00055 if((nv1 = chunk_arg >> 8) == 0) 00056 nv1 = 256; 00057 if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size) 00058 nv2 = 256; 00059 for(i = 0; i < nv1; i++) { 00060 ri->cb2x2[i].y[0] = *buf++; 00061 ri->cb2x2[i].y[1] = *buf++; 00062 ri->cb2x2[i].y[2] = *buf++; 00063 ri->cb2x2[i].y[3] = *buf++; 00064 ri->cb2x2[i].u = *buf++; 00065 ri->cb2x2[i].v = *buf++; 00066 } 00067 for(i = 0; i < nv2; i++) 00068 for(j = 0; j < 4; j++) 00069 ri->cb4x4[i].idx[j] = *buf++; 00070 } 00071 } 00072 00073 bpos = xpos = ypos = 0; 00074 while(bpos < chunk_size) { 00075 for (yp = ypos; yp < ypos + 16; yp += 8) 00076 for (xp = xpos; xp < xpos + 16; xp += 8) { 00077 if (vqflg_pos < 0) { 00078 vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8); 00079 vqflg_pos = 7; 00080 } 00081 vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; 00082 frame_stats[0][vqid]++; 00083 vqflg_pos--; 00084 00085 switch(vqid) { 00086 case RoQ_ID_MOT: 00087 break; 00088 case RoQ_ID_FCC: 00089 mx = 8 - (buf[bpos] >> 4) - ((signed char) (chunk_arg >> 8)); 00090 my = 8 - (buf[bpos++] & 0xf) - ((signed char) chunk_arg); 00091 ff_apply_motion_8x8(ri, xp, yp, mx, my); 00092 break; 00093 case RoQ_ID_SLD: 00094 qcell = ri->cb4x4 + buf[bpos++]; 00095 ff_apply_vector_4x4(ri, xp, yp, ri->cb2x2 + qcell->idx[0]); 00096 ff_apply_vector_4x4(ri, xp+4, yp, ri->cb2x2 + qcell->idx[1]); 00097 ff_apply_vector_4x4(ri, xp, yp+4, ri->cb2x2 + qcell->idx[2]); 00098 ff_apply_vector_4x4(ri, xp+4, yp+4, ri->cb2x2 + qcell->idx[3]); 00099 break; 00100 case RoQ_ID_CCC: 00101 for (k = 0; k < 4; k++) { 00102 x = xp; y = yp; 00103 if(k & 0x01) x += 4; 00104 if(k & 0x02) y += 4; 00105 00106 if (vqflg_pos < 0) { 00107 vqflg = buf[bpos++]; 00108 vqflg |= (buf[bpos++] << 8); 00109 vqflg_pos = 7; 00110 } 00111 vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; 00112 frame_stats[1][vqid]++; 00113 vqflg_pos--; 00114 switch(vqid) { 00115 case RoQ_ID_MOT: 00116 break; 00117 case RoQ_ID_FCC: 00118 mx = 8 - (buf[bpos] >> 4) - ((signed char) (chunk_arg >> 8)); 00119 my = 8 - (buf[bpos++] & 0xf) - ((signed char) chunk_arg); 00120 ff_apply_motion_4x4(ri, x, y, mx, my); 00121 break; 00122 case RoQ_ID_SLD: 00123 qcell = ri->cb4x4 + buf[bpos++]; 00124 ff_apply_vector_2x2(ri, x, y, ri->cb2x2 + qcell->idx[0]); 00125 ff_apply_vector_2x2(ri, x+2, y, ri->cb2x2 + qcell->idx[1]); 00126 ff_apply_vector_2x2(ri, x, y+2, ri->cb2x2 + qcell->idx[2]); 00127 ff_apply_vector_2x2(ri, x+2, y+2, ri->cb2x2 + qcell->idx[3]); 00128 break; 00129 case RoQ_ID_CCC: 00130 ff_apply_vector_2x2(ri, x, y, ri->cb2x2 + buf[bpos]); 00131 ff_apply_vector_2x2(ri, x+2, y, ri->cb2x2 + buf[bpos+1]); 00132 ff_apply_vector_2x2(ri, x, y+2, ri->cb2x2 + buf[bpos+2]); 00133 ff_apply_vector_2x2(ri, x+2, y+2, ri->cb2x2 + buf[bpos+3]); 00134 bpos += 4; 00135 break; 00136 } 00137 } 00138 break; 00139 default: 00140 av_log(ri->avctx, AV_LOG_ERROR, "Unknown vq code: %d\n", vqid); 00141 } 00142 } 00143 00144 xpos += 16; 00145 if (xpos >= ri->width) { 00146 xpos -= ri->width; 00147 ypos += 16; 00148 } 00149 if(ypos >= ri->height) 00150 break; 00151 } 00152 } 00153 00154 00155 static av_cold int roq_decode_init(AVCodecContext *avctx) 00156 { 00157 RoqContext *s = avctx->priv_data; 00158 00159 s->avctx = avctx; 00160 s->width = avctx->width; 00161 s->height = avctx->height; 00162 s->last_frame = &s->frames[0]; 00163 s->current_frame = &s->frames[1]; 00164 avctx->pix_fmt = PIX_FMT_YUV444P; 00165 00166 return 0; 00167 } 00168 00169 static int roq_decode_frame(AVCodecContext *avctx, 00170 void *data, int *data_size, 00171 AVPacket *avpkt) 00172 { 00173 const uint8_t *buf = avpkt->data; 00174 int buf_size = avpkt->size; 00175 RoqContext *s = avctx->priv_data; 00176 int copy= !s->current_frame->data[0]; 00177 00178 if (avctx->reget_buffer(avctx, s->current_frame)) { 00179 av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n"); 00180 return -1; 00181 } 00182 00183 if(copy) 00184 av_picture_copy((AVPicture*)s->current_frame, (AVPicture*)s->last_frame, 00185 avctx->pix_fmt, avctx->width, avctx->height); 00186 00187 s->buf = buf; 00188 s->size = buf_size; 00189 roqvideo_decode_frame(s); 00190 00191 *data_size = sizeof(AVFrame); 00192 *(AVFrame*)data = *s->current_frame; 00193 00194 /* shuffle frames */ 00195 FFSWAP(AVFrame *, s->current_frame, s->last_frame); 00196 00197 return buf_size; 00198 } 00199 00200 static av_cold int roq_decode_end(AVCodecContext *avctx) 00201 { 00202 RoqContext *s = avctx->priv_data; 00203 00204 /* release the last frame */ 00205 if (s->last_frame->data[0]) 00206 avctx->release_buffer(avctx, s->last_frame); 00207 if (s->current_frame->data[0]) 00208 avctx->release_buffer(avctx, s->current_frame); 00209 00210 return 0; 00211 } 00212 00213 AVCodec roq_decoder = { 00214 "roqvideo", 00215 AVMEDIA_TYPE_VIDEO, 00216 CODEC_ID_ROQ, 00217 sizeof(RoqContext), 00218 roq_decode_init, 00219 NULL, 00220 roq_decode_end, 00221 roq_decode_frame, 00222 CODEC_CAP_DR1, 00223 .long_name = NULL_IF_CONFIG_SMALL("id RoQ video"), 00224 };