00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00033 #include "avcodec.h"
00034
00035 #define FPS_TAG MKTAG('F', 'P', 'S', 'x')
00036
00040 typedef struct FrapsContext{
00041 AVCodecContext *avctx;
00042 AVFrame frame;
00043 } FrapsContext;
00044
00045
00051 static int decode_init(AVCodecContext *avctx)
00052 {
00053 FrapsContext * const s = avctx->priv_data;
00054
00055 avctx->coded_frame = (AVFrame*)&s->frame;
00056 avctx->has_b_frames = 0;
00057 avctx->pix_fmt= PIX_FMT_NONE;
00058
00059 s->avctx = avctx;
00060 s->frame.data[0] = NULL;
00061
00062 return 0;
00063 }
00064
00065
00075 static int decode_frame(AVCodecContext *avctx,
00076 void *data, int *data_size,
00077 uint8_t *buf, int buf_size)
00078 {
00079 FrapsContext * const s = avctx->priv_data;
00080 AVFrame *frame = data;
00081 AVFrame * const f = (AVFrame*)&s->frame;
00082 uint32_t header;
00083 unsigned int version,header_size;
00084 unsigned int x, y;
00085 uint32_t *buf32;
00086 uint32_t *luma1,*luma2,*cb,*cr;
00087
00088
00089 header = LE_32(buf);
00090 version = header & 0xff;
00091 header_size = (header & (1<<30))? 8 : 4;
00092
00093 if (version > 1) {
00094 av_log(avctx, AV_LOG_ERROR,
00095 "This file is encoded with Fraps version %d. " \
00096 "This codec can only decode version 0 and 1.\n", version);
00097 return -1;
00098 }
00099
00100 buf+=4;
00101 if (header_size == 8)
00102 buf+=4;
00103
00104 switch(version) {
00105 case 0:
00106 default:
00107
00108 avctx->pix_fmt = PIX_FMT_YUV420P;
00109
00110 if ( (buf_size != avctx->width*avctx->height*3/2+header_size) &&
00111 (buf_size != header_size) ) {
00112 av_log(avctx, AV_LOG_ERROR,
00113 "Invalid frame length %d (should be %d)\n",
00114 buf_size, avctx->width*avctx->height*3/2+header_size);
00115 return -1;
00116 }
00117
00118 if (( (avctx->width % 8) != 0) || ( (avctx->height % 2) != 0 )) {
00119 av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n",
00120 avctx->width, avctx->height);
00121 return -1;
00122 }
00123
00124 f->reference = 1;
00125 f->buffer_hints = FF_BUFFER_HINTS_VALID |
00126 FF_BUFFER_HINTS_PRESERVE |
00127 FF_BUFFER_HINTS_REUSABLE;
00128 if (avctx->reget_buffer(avctx, f)) {
00129 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00130 return -1;
00131 }
00132
00133 f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE;
00134 f->key_frame = f->pict_type == FF_I_TYPE;
00135
00136 if (f->pict_type == FF_I_TYPE) {
00137 buf32=(uint32_t*)buf;
00138 for(y=0; y<avctx->height/2; y++){
00139 luma1=(uint32_t*)&f->data[0][ y*2*f->linesize[0] ];
00140 luma2=(uint32_t*)&f->data[0][ (y*2+1)*f->linesize[0] ];
00141 cr=(uint32_t*)&f->data[1][ y*f->linesize[1] ];
00142 cb=(uint32_t*)&f->data[2][ y*f->linesize[2] ];
00143 for(x=0; x<avctx->width; x+=8){
00144 *(luma1++) = *(buf32++);
00145 *(luma1++) = *(buf32++);
00146 *(luma2++) = *(buf32++);
00147 *(luma2++) = *(buf32++);
00148 *(cr++) = *(buf32++);
00149 *(cb++) = *(buf32++);
00150 }
00151 }
00152 }
00153 break;
00154
00155 case 1:
00156
00157 avctx->pix_fmt = PIX_FMT_BGR24;
00158
00159 if ( (buf_size != avctx->width*avctx->height*3+header_size) &&
00160 (buf_size != header_size) ) {
00161 av_log(avctx, AV_LOG_ERROR,
00162 "Invalid frame length %d (should be %d)\n",
00163 buf_size, avctx->width*avctx->height*3+header_size);
00164 return -1;
00165 }
00166
00167 f->reference = 1;
00168 f->buffer_hints = FF_BUFFER_HINTS_VALID |
00169 FF_BUFFER_HINTS_PRESERVE |
00170 FF_BUFFER_HINTS_REUSABLE;
00171 if (avctx->reget_buffer(avctx, f)) {
00172 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00173 return -1;
00174 }
00175
00176 f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE;
00177 f->key_frame = f->pict_type == FF_I_TYPE;
00178
00179 if (f->pict_type == FF_I_TYPE) {
00180 for(y=0; y<avctx->height; y++)
00181 memcpy(&f->data[0][ (avctx->height-y)*f->linesize[0] ],
00182 &buf[y*avctx->width*3],
00183 f->linesize[0]);
00184 }
00185 break;
00186
00187 case 2:
00205 if ((BE_32(buf) != FPS_TAG)||(buf_size < (3*1024 + 8))) {
00206 av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n");
00207 return -1;
00208 }
00209
00210
00211
00212 break;
00213 }
00214
00215 *frame = *f;
00216 *data_size = sizeof(AVFrame);
00217
00218 return buf_size;
00219 }
00220
00221
00227 static int decode_end(AVCodecContext *avctx)
00228 {
00229 FrapsContext *s = (FrapsContext*)avctx->priv_data;
00230
00231 if (s->frame.data[0])
00232 avctx->release_buffer(avctx, &s->frame);
00233
00234 return 0;
00235 }
00236
00237
00238 AVCodec fraps_decoder = {
00239 "fraps",
00240 CODEC_TYPE_VIDEO,
00241 CODEC_ID_FRAPS,
00242 sizeof(FrapsContext),
00243 decode_init,
00244 NULL,
00245 decode_end,
00246 decode_frame,
00247 CODEC_CAP_DR1,
00248 };