From a4065ca4146fb0dfe555ffa7ed553f687af200a6 Mon Sep 17 00:00:00 2001
From: Javier Cabezas <jcabgz@gmail.com>
Date: Mon, 30 Jan 2012 20:16:55 +0100
Subject: [PATCH] Fraps: restore old behavior regarding P frames.
P frames are repeated frames in Fraps, not skip frames. Restore the old behavior where those P frames are outputted as normal frames with their own timestamp. This matches the Fraps reference decoder. In order to make frame multithreading work, a 2 frame buffer is used.
---
libavcodec/fraps.c | 228 +++++++++++++++++++++++++++++++++++-----------------
1 files changed, 154 insertions(+), 74 deletions(-)
diff --git a/libavcodec/fraps.c b/libavcodec/fraps.c
index a7d5a73..8e3b816 100644
|
a
|
b
|
|
| 32 | 32 | */ |
| 33 | 33 | |
| 34 | 34 | #include "avcodec.h" |
| | 35 | #include "internal.h" |
| 35 | 36 | #include "get_bits.h" |
| 36 | 37 | #include "huffman.h" |
| 37 | 38 | #include "bytestream.h" |
| 38 | 39 | #include "dsputil.h" |
| 39 | 40 | #include "thread.h" |
| | 41 | #include "libavutil/imgutils.h" |
| 40 | 42 | |
| 41 | 43 | #define FPS_TAG MKTAG('F', 'P', 'S', 'x') |
| 42 | 44 | |
| … |
… |
|
| 45 | 47 | */ |
| 46 | 48 | typedef struct FrapsContext{ |
| 47 | 49 | AVCodecContext *avctx; |
| 48 | | AVFrame frame; |
| | 50 | int cur_index, prev_index; |
| | 51 | int next_cur_index, next_prev_index; |
| | 52 | AVFrame buf_ptrs[2]; |
| 49 | 53 | uint8_t *tmpbuf; |
| 50 | 54 | int tmpbuf_size; |
| 51 | 55 | DSPContext dsp; |
| … |
… |
static av_cold int decode_init(AVCodecContext *avctx) |
| 61 | 65 | { |
| 62 | 66 | FrapsContext * const s = avctx->priv_data; |
| 63 | 67 | |
| 64 | | avcodec_get_frame_defaults(&s->frame); |
| 65 | | avctx->coded_frame = (AVFrame*)&s->frame; |
| | 68 | s->prev_index = 0; |
| | 69 | s->cur_index = 1; |
| 66 | 70 | |
| 67 | 71 | s->avctx = avctx; |
| 68 | 72 | s->tmpbuf = NULL; |
| … |
… |
static av_cold int decode_init(AVCodecContext *avctx) |
| 72 | 76 | return 0; |
| 73 | 77 | } |
| 74 | 78 | |
| | 79 | static int fraps_decode_update_thread_context(AVCodecContext *avctx, const AVCodecContext *avctx_from) |
| | 80 | { |
| | 81 | FrapsContext *dst = avctx->priv_data, *src = avctx_from->priv_data; |
| | 82 | |
| | 83 | if (avctx == avctx_from) return 0; |
| | 84 | |
| | 85 | dst->cur_index = src->next_cur_index; |
| | 86 | dst->prev_index = src->next_prev_index; |
| | 87 | |
| | 88 | memcpy(dst->buf_ptrs, src->buf_ptrs, sizeof(src->buf_ptrs)); |
| | 89 | |
| | 90 | memset(&dst->buf_ptrs[dst->cur_index], 0, sizeof(AVFrame)); |
| | 91 | |
| | 92 | return 0; |
| | 93 | } |
| | 94 | |
| 75 | 95 | /** |
| 76 | 96 | * Comparator - our nodes should ascend by count |
| 77 | 97 | * but with preserved symbol order |
| … |
… |
static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w, |
| 93 | 113 | VLC vlc; |
| 94 | 114 | Node nodes[512]; |
| 95 | 115 | |
| 96 | | for(i = 0; i < 256; i++) |
| | 116 | for (i = 0; i < 256; i++) |
| 97 | 117 | nodes[i].count = bytestream_get_le32(&src); |
| 98 | 118 | size -= 1024; |
| 99 | 119 | if (ff_huff_build_tree(s->avctx, &vlc, 256, nodes, huff_cmp, |
| … |
… |
static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w, |
| 105 | 125 | s->dsp.bswap_buf((uint32_t *)s->tmpbuf, (const uint32_t *)src, size >> 2); |
| 106 | 126 | |
| 107 | 127 | init_get_bits(&gb, s->tmpbuf, size * 8); |
| 108 | | for(j = 0; j < h; j++){ |
| 109 | | for(i = 0; i < w*step; i += step){ |
| | 128 | for (j = 0; j < h; j++){ |
| | 129 | for (i = 0; i < w*step; i += step){ |
| 110 | 130 | dst[i] = get_vlc2(&gb, vlc.table, 9, 3); |
| 111 | 131 | /* lines are stored as deltas between previous lines |
| 112 | 132 | * and we need to add 0x80 to the first lines of chroma planes |
| 113 | 133 | */ |
| 114 | | if(j) dst[i] += dst[i - stride]; |
| 115 | | else if(Uoff) dst[i] += 0x80; |
| | 134 | if (j) |
| | 135 | dst[i] += dst[i - stride]; |
| | 136 | else if (Uoff) |
| | 137 | dst[i] += 0x80; |
| 116 | 138 | if (get_bits_left(&gb) < 0) { |
| 117 | 139 | free_vlc(&vlc); |
| 118 | 140 | return AVERROR_INVALIDDATA; |
| … |
… |
static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w, |
| 124 | 146 | return 0; |
| 125 | 147 | } |
| 126 | 148 | |
| | 149 | static void fraps_frame_copy(FrapsContext *s, uint8_t *dst_data[3], int dst_linesizes[3], |
| | 150 | uint8_t *src_data[3], const int src_linesizes[3], |
| | 151 | enum PixelFormat pix_fmt, int width, int height) |
| | 152 | { |
| | 153 | const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[pix_fmt]; |
| | 154 | int i; |
| | 155 | |
| | 156 | for (i = 0; i < 3; i++) { |
| | 157 | int h = height; |
| | 158 | int bwidth = av_image_get_linesize(pix_fmt, width, i); |
| | 159 | if (i) { |
| | 160 | h = -((-height)>>desc->log2_chroma_h); |
| | 161 | } |
| | 162 | ff_thread_await_progress(&s->buf_ptrs[s->prev_index], i, 0); |
| | 163 | av_image_copy_plane(dst_data[i], dst_linesizes[i], |
| | 164 | src_data[i], src_linesizes[i], |
| | 165 | bwidth, h); |
| | 166 | ff_thread_report_progress(&s->buf_ptrs[s->cur_index], i, 0); |
| | 167 | } |
| | 168 | } |
| | 169 | |
| 127 | 170 | static int decode_frame(AVCodecContext *avctx, |
| 128 | 171 | void *data, int *data_size, |
| 129 | 172 | AVPacket *avpkt) |
| … |
… |
static int decode_frame(AVCodecContext *avctx, |
| 131 | 174 | const uint8_t *buf = avpkt->data; |
| 132 | 175 | int buf_size = avpkt->size; |
| 133 | 176 | FrapsContext * const s = avctx->priv_data; |
| 134 | | AVFrame *frame = data; |
| 135 | | AVFrame * const f = (AVFrame*)&s->frame; |
| 136 | 177 | uint32_t header; |
| 137 | | unsigned int version,header_size; |
| | 178 | unsigned int version, header_size; |
| 138 | 179 | unsigned int x, y; |
| 139 | 180 | const uint32_t *buf32; |
| 140 | | uint32_t *luma1,*luma2,*cb,*cr; |
| | 181 | uint32_t *luma1, *luma2, *cb, *cr; |
| 141 | 182 | uint32_t offs[4]; |
| 142 | | int i, j, is_chroma; |
| | 183 | int i, j, is_chroma, is_Pframe, ret; |
| 143 | 184 | const int planes = 3; |
| 144 | 185 | uint8_t *out; |
| 145 | 186 | |
| … |
… |
static int decode_frame(AVCodecContext *avctx, |
| 148 | 189 | version = header & 0xff; |
| 149 | 190 | header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ |
| 150 | 191 | |
| | 192 | buf += header_size; |
| | 193 | |
| 151 | 194 | if (version > 5) { |
| 152 | 195 | av_log(avctx, AV_LOG_ERROR, |
| 153 | 196 | "This file is encoded with Fraps version %d. " \ |
| … |
… |
static int decode_frame(AVCodecContext *avctx, |
| 155 | 198 | return -1; |
| 156 | 199 | } |
| 157 | 200 | |
| 158 | | buf += header_size; |
| 159 | | |
| 160 | 201 | avctx->pix_fmt = version & 1 ? PIX_FMT_BGR24 : PIX_FMT_YUVJ420P; |
| 161 | 202 | |
| 162 | 203 | if (version < 2) { |
| 163 | 204 | unsigned needed_size = avctx->width*avctx->height*3; |
| 164 | | if (version == 0) needed_size /= 2; |
| | 205 | if (version == 0) { |
| | 206 | if ( (avctx->width % 8) != 0 || (avctx->height % 2) != 0 ) { |
| | 207 | av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", |
| | 208 | avctx->width, avctx->height); |
| | 209 | return -1; |
| | 210 | } |
| | 211 | needed_size /= 2; |
| | 212 | } |
| 165 | 213 | needed_size += header_size; |
| 166 | 214 | if (buf_size != needed_size && buf_size != header_size) { |
| 167 | 215 | av_log(avctx, AV_LOG_ERROR, |
| … |
… |
static int decode_frame(AVCodecContext *avctx, |
| 169 | 217 | buf_size, needed_size); |
| 170 | 218 | return -1; |
| 171 | 219 | } |
| 172 | | /* bit 31 means same as previous pic */ |
| 173 | | if (header & (1U<<31)) { |
| 174 | | *data_size = 0; |
| 175 | | return buf_size; |
| 176 | | } |
| | 220 | is_Pframe = (header & (1U<<31)) ? 1 : 0; |
| 177 | 221 | } else { |
| 178 | | /* skip frame */ |
| 179 | | if (buf_size == 8) { |
| 180 | | *data_size = 0; |
| 181 | | return buf_size; |
| 182 | | } |
| 183 | | if (AV_RL32(buf) != FPS_TAG || buf_size < planes*1024 + 24) { |
| 184 | | av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); |
| 185 | | return -1; |
| 186 | | } |
| 187 | | for(i = 0; i < planes; i++) { |
| 188 | | offs[i] = AV_RL32(buf + 4 + i * 4); |
| 189 | | if(offs[i] >= buf_size - header_size || (i && offs[i] <= offs[i - 1] + 1024)) { |
| 190 | | av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); |
| | 222 | is_Pframe = buf_size == 8 ? 1 : 0; |
| | 223 | if (!is_Pframe) { |
| | 224 | if (AV_RL32(buf) != FPS_TAG || buf_size < (planes*1024 + 24)) { |
| | 225 | av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); |
| 191 | 226 | return -1; |
| 192 | 227 | } |
| 193 | | } |
| 194 | | offs[planes] = buf_size - header_size; |
| 195 | | for(i = 0; i < planes; i++) { |
| 196 | | av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size, offs[i + 1] - offs[i] - 1024); |
| 197 | | if (!s->tmpbuf) |
| 198 | | return AVERROR(ENOMEM); |
| | 228 | for(i = 0; i < planes; i++) { |
| | 229 | offs[i] = AV_RL32(buf + 4 + i * 4); |
| | 230 | if(offs[i] >= buf_size - header_size || (i && offs[i] <= offs[i - 1] + 1024)) { |
| | 231 | av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); |
| | 232 | return -1; |
| | 233 | } |
| | 234 | } |
| | 235 | offs[planes] = buf_size - header_size; |
| | 236 | for(i = 0; i < planes; i++) { |
| | 237 | av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size, offs[i + 1] - offs[i] - 1024); |
| | 238 | if (!s->tmpbuf) |
| | 239 | return AVERROR(ENOMEM); |
| | 240 | } |
| 199 | 241 | } |
| 200 | 242 | } |
| 201 | 243 | |
| 202 | | if (f->data[0]) |
| 203 | | ff_thread_release_buffer(avctx, f); |
| 204 | | f->pict_type = AV_PICTURE_TYPE_I; |
| 205 | | f->key_frame = 1; |
| 206 | | f->reference = 0; |
| 207 | | f->buffer_hints = FF_BUFFER_HINTS_VALID; |
| 208 | | if (ff_thread_get_buffer(avctx, f)) { |
| 209 | | av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); |
| | 244 | if (is_Pframe && !s->buf_ptrs[s->prev_index].data[0]) { |
| | 245 | av_log(avctx, AV_LOG_ERROR, "decoding must start with keyframe\n"); |
| 210 | 246 | return -1; |
| 211 | 247 | } |
| 212 | 248 | |
| 213 | | switch(version) { |
| | 249 | s->buf_ptrs[s->cur_index].reference = 3; |
| | 250 | |
| | 251 | if (is_Pframe) { |
| | 252 | s->buf_ptrs[s->cur_index].pict_type = AV_PICTURE_TYPE_P; |
| | 253 | s->buf_ptrs[s->cur_index].key_frame = 0; |
| | 254 | } else { |
| | 255 | s->buf_ptrs[s->cur_index].pict_type = AV_PICTURE_TYPE_I; |
| | 256 | s->buf_ptrs[s->cur_index].key_frame = 1; |
| | 257 | } |
| | 258 | |
| | 259 | if ((ret = ff_thread_get_buffer(avctx, &s->buf_ptrs[s->cur_index])) < 0) { |
| | 260 | av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); |
| | 261 | return ret; |
| | 262 | } |
| | 263 | |
| | 264 | s->next_prev_index = s->cur_index; |
| | 265 | s->next_cur_index = (s->cur_index - 1) & 1; |
| | 266 | |
| | 267 | ff_thread_finish_setup(avctx); |
| | 268 | |
| | 269 | /* Copy previous frame */ |
| | 270 | if (is_Pframe) { |
| | 271 | fraps_frame_copy(s, s->buf_ptrs[s->cur_index].data, s->buf_ptrs[s->cur_index].linesize, |
| | 272 | s->buf_ptrs[s->prev_index].data, s->buf_ptrs[s->prev_index].linesize, |
| | 273 | avctx->pix_fmt, avctx->width, avctx->height); |
| | 274 | goto end; |
| | 275 | } |
| | 276 | |
| | 277 | /* Decode I-frame */ |
| | 278 | switch (version) { |
| 214 | 279 | case 0: |
| 215 | 280 | default: |
| 216 | 281 | /* Fraps v0 is a reordered YUV420 */ |
| 217 | | if ( (avctx->width % 8) != 0 || (avctx->height % 2) != 0 ) { |
| 218 | | av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", |
| 219 | | avctx->width, avctx->height); |
| 220 | | return -1; |
| 221 | | } |
| 222 | | |
| 223 | | buf32=(const uint32_t*)buf; |
| 224 | | for(y=0; y<avctx->height/2; y++){ |
| 225 | | luma1=(uint32_t*)&f->data[0][ y*2*f->linesize[0] ]; |
| 226 | | luma2=(uint32_t*)&f->data[0][ (y*2+1)*f->linesize[0] ]; |
| 227 | | cr=(uint32_t*)&f->data[1][ y*f->linesize[1] ]; |
| 228 | | cb=(uint32_t*)&f->data[2][ y*f->linesize[2] ]; |
| 229 | | for(x=0; x<avctx->width; x+=8){ |
| | 282 | buf32 = (const uint32_t*)buf; |
| | 283 | for(y = 0; y < avctx->height/2; y++){ |
| | 284 | luma1 = (uint32_t*)&s->buf_ptrs[s->cur_index].data[0][y*2*s->buf_ptrs[s->cur_index].linesize[0]]; |
| | 285 | luma2 = (uint32_t*)&s->buf_ptrs[s->cur_index].data[0][(y*2+1)*s->buf_ptrs[s->cur_index].linesize[0]]; |
| | 286 | cr = (uint32_t*)&s->buf_ptrs[s->cur_index].data[1][y*s->buf_ptrs[s->cur_index].linesize[1]]; |
| | 287 | cb = (uint32_t*)&s->buf_ptrs[s->cur_index].data[2][y*s->buf_ptrs[s->cur_index].linesize[2]]; |
| | 288 | for(x = 0; x < avctx->width; x += 8){ |
| 230 | 289 | *luma1++ = *buf32++; |
| 231 | 290 | *luma1++ = *buf32++; |
| 232 | 291 | *luma2++ = *buf32++; |
| … |
… |
static int decode_frame(AVCodecContext *avctx, |
| 235 | 294 | *cb++ = *buf32++; |
| 236 | 295 | } |
| 237 | 296 | } |
| | 297 | ff_thread_report_progress(&s->buf_ptrs[s->cur_index], INT_MAX, 0); |
| 238 | 298 | break; |
| 239 | 299 | |
| 240 | 300 | case 1: |
| 241 | 301 | /* Fraps v1 is an upside-down BGR24 */ |
| 242 | | for(y=0; y<avctx->height; y++) |
| 243 | | memcpy(&f->data[0][ (avctx->height-y)*f->linesize[0] ], |
| | 302 | for(y = 0; y < avctx->height; y++) |
| | 303 | memcpy(&s->buf_ptrs[s->cur_index].data[0][(avctx->height-y)*s->buf_ptrs[s->cur_index].linesize[0]], |
| 244 | 304 | &buf[y*avctx->width*3], |
| 245 | 305 | 3*avctx->width); |
| | 306 | ff_thread_report_progress(&s->buf_ptrs[s->cur_index], INT_MAX, 0); |
| 246 | 307 | break; |
| 247 | 308 | |
| 248 | 309 | case 2: |
| … |
… |
static int decode_frame(AVCodecContext *avctx, |
| 253 | 314 | */ |
| 254 | 315 | for(i = 0; i < planes; i++){ |
| 255 | 316 | is_chroma = !!i; |
| 256 | | if(fraps2_decode_plane(s, f->data[i], f->linesize[i], avctx->width >> is_chroma, |
| 257 | | avctx->height >> is_chroma, buf + offs[i], offs[i + 1] - offs[i], is_chroma, 1) < 0) { |
| | 317 | if(fraps2_decode_plane(s, s->buf_ptrs[s->cur_index].data[i], s->buf_ptrs[s->cur_index].linesize[i], avctx->width >> is_chroma, |
| | 318 | avctx->height >> is_chroma, buf + offs[i], offs[i + 1] - offs[i], is_chroma, 1) < 0) { |
| 258 | 319 | av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); |
| 259 | 320 | return -1; |
| 260 | 321 | } |
| | 322 | else |
| | 323 | ff_thread_report_progress(&s->buf_ptrs[s->cur_index], i, 0); |
| 261 | 324 | } |
| 262 | 325 | break; |
| | 326 | |
| 263 | 327 | case 3: |
| 264 | 328 | case 5: |
| 265 | 329 | /* Virtually the same as version 4, but is for RGB24 */ |
| 266 | 330 | for(i = 0; i < planes; i++){ |
| 267 | | if(fraps2_decode_plane(s, f->data[0] + i + (f->linesize[0] * (avctx->height - 1)), -f->linesize[0], |
| 268 | | avctx->width, avctx->height, buf + offs[i], offs[i + 1] - offs[i], 0, 3) < 0) { |
| | 331 | if(fraps2_decode_plane(s, s->buf_ptrs[s->cur_index].data[0] + i + (s->buf_ptrs[s->cur_index].linesize[0] * (avctx->height - 1)), -s->buf_ptrs[s->cur_index].linesize[0], |
| | 332 | avctx->width, avctx->height, buf + offs[i], offs[i + 1] - offs[i], 0, 3) < 0) { |
| 269 | 333 | av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); |
| 270 | 334 | return -1; |
| 271 | 335 | } |
| 272 | 336 | } |
| 273 | | out = f->data[0]; |
| 274 | 337 | // convert pseudo-YUV into real RGB |
| | 338 | out = s->buf_ptrs[s->cur_index].data[0]; |
| 275 | 339 | for(j = 0; j < avctx->height; j++){ |
| 276 | 340 | uint8_t *line_end = out + 3*avctx->width; |
| 277 | 341 | while (out < line_end) { |
| … |
… |
static int decode_frame(AVCodecContext *avctx, |
| 279 | 343 | out[2] += out[1]; |
| 280 | 344 | out += 3; |
| 281 | 345 | } |
| 282 | | out += f->linesize[0] - 3*avctx->width; |
| | 346 | out += s->buf_ptrs[s->cur_index].linesize[0] - 3*avctx->width; |
| 283 | 347 | } |
| | 348 | ff_thread_report_progress(&s->buf_ptrs[s->cur_index], INT_MAX, 0); |
| 284 | 349 | break; |
| 285 | 350 | } |
| 286 | 351 | |
| 287 | | *frame = *f; |
| | 352 | end: |
| | 353 | *(AVFrame*)data = s->buf_ptrs[s->cur_index]; |
| 288 | 354 | *data_size = sizeof(AVFrame); |
| 289 | 355 | |
| | 356 | s->prev_index = s->next_prev_index; |
| | 357 | s->cur_index = s->next_cur_index; |
| | 358 | |
| | 359 | /* Only release frames that aren't used anymore */ |
| | 360 | if(s->buf_ptrs[s->cur_index].data[0]) |
| | 361 | ff_thread_release_buffer(avctx, &s->buf_ptrs[s->cur_index]); |
| | 362 | |
| 290 | 363 | return buf_size; |
| 291 | 364 | } |
| 292 | 365 | |
| … |
… |
static int decode_frame(AVCodecContext *avctx, |
| 299 | 372 | static av_cold int decode_end(AVCodecContext *avctx) |
| 300 | 373 | { |
| 301 | 374 | FrapsContext *s = (FrapsContext*)avctx->priv_data; |
| 302 | | |
| 303 | | if (s->frame.data[0]) |
| 304 | | avctx->release_buffer(avctx, &s->frame); |
| | 375 | int i; |
| 305 | 376 | |
| 306 | 377 | av_freep(&s->tmpbuf); |
| | 378 | |
| | 379 | if (avctx->internal->is_copy) |
| | 380 | return 0; |
| | 381 | |
| | 382 | for(i = 0; i < 2; i++) |
| | 383 | if(s->buf_ptrs[i].data[0]) |
| | 384 | ff_thread_release_buffer(avctx, &s->buf_ptrs[i]); |
| | 385 | |
| 307 | 386 | return 0; |
| 308 | 387 | } |
| 309 | 388 | |
| … |
… |
AVCodec ff_fraps_decoder = { |
| 318 | 397 | .decode = decode_frame, |
| 319 | 398 | .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, |
| 320 | 399 | .long_name = NULL_IF_CONFIG_SMALL("Fraps"), |
| | 400 | .update_thread_context = ONLY_IF_THREADS_ENABLED(fraps_decode_update_thread_context) |
| 321 | 401 | }; |