Ticket #963: frapsMTv2.patch

File frapsMTv2.patch, 15.3 KB (added by STaRGaZeR, 15 years ago)
  • libavcodec/fraps.c

    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  
    3232 */
    3333
    3434#include "avcodec.h"
     35#include "internal.h"
    3536#include "get_bits.h"
    3637#include "huffman.h"
    3738#include "bytestream.h"
    3839#include "dsputil.h"
    3940#include "thread.h"
     41#include "libavutil/imgutils.h"
    4042
    4143#define FPS_TAG MKTAG('F', 'P', 'S', 'x')
    4244
     
    4547 */
    4648typedef struct FrapsContext{
    4749    AVCodecContext *avctx;
    48     AVFrame frame;
     50    int cur_index, prev_index;
     51    int next_cur_index, next_prev_index;
     52    AVFrame buf_ptrs[2];
    4953    uint8_t *tmpbuf;
    5054    int tmpbuf_size;
    5155    DSPContext dsp;
    static av_cold int decode_init(AVCodecContext *avctx)  
    6165{
    6266    FrapsContext * const s = avctx->priv_data;
    6367
    64     avcodec_get_frame_defaults(&s->frame);
    65     avctx->coded_frame = (AVFrame*)&s->frame;
     68    s->prev_index = 0;
     69    s->cur_index = 1;
    6670
    6771    s->avctx = avctx;
    6872    s->tmpbuf = NULL;
    static av_cold int decode_init(AVCodecContext *avctx)  
    7276    return 0;
    7377}
    7478
     79static 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
    7595/**
    7696 * Comparator - our nodes should ascend by count
    7797 * but with preserved symbol order
    static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w,  
    93113    VLC vlc;
    94114    Node nodes[512];
    95115
    96     for(i = 0; i < 256; i++)
     116    for (i = 0; i < 256; i++)
    97117        nodes[i].count = bytestream_get_le32(&src);
    98118    size -= 1024;
    99119    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,  
    105125    s->dsp.bswap_buf((uint32_t *)s->tmpbuf, (const uint32_t *)src, size >> 2);
    106126
    107127    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){
    110130            dst[i] = get_vlc2(&gb, vlc.table, 9, 3);
    111131            /* lines are stored as deltas between previous lines
    112132             * and we need to add 0x80 to the first lines of chroma planes
    113133             */
    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;
    116138            if (get_bits_left(&gb) < 0) {
    117139                free_vlc(&vlc);
    118140                return AVERROR_INVALIDDATA;
    static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w,  
    124146    return 0;
    125147}
    126148
     149static 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
    127170static int decode_frame(AVCodecContext *avctx,
    128171                        void *data, int *data_size,
    129172                        AVPacket *avpkt)
    static int decode_frame(AVCodecContext *avctx,  
    131174    const uint8_t *buf = avpkt->data;
    132175    int buf_size = avpkt->size;
    133176    FrapsContext * const s = avctx->priv_data;
    134     AVFrame *frame = data;
    135     AVFrame * const f = (AVFrame*)&s->frame;
    136177    uint32_t header;
    137     unsigned int version,header_size;
     178    unsigned int version, header_size;
    138179    unsigned int x, y;
    139180    const uint32_t *buf32;
    140     uint32_t *luma1,*luma2,*cb,*cr;
     181    uint32_t *luma1, *luma2, *cb, *cr;
    141182    uint32_t offs[4];
    142     int i, j, is_chroma;
     183    int i, j, is_chroma, is_Pframe, ret;
    143184    const int planes = 3;
    144185    uint8_t *out;
    145186
    static int decode_frame(AVCodecContext *avctx,  
    148189    version = header & 0xff;
    149190    header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */
    150191
     192    buf += header_size;
     193
    151194    if (version > 5) {
    152195        av_log(avctx, AV_LOG_ERROR,
    153196               "This file is encoded with Fraps version %d. " \
    static int decode_frame(AVCodecContext *avctx,  
    155198        return -1;
    156199    }
    157200
    158     buf += header_size;
    159 
    160201    avctx->pix_fmt = version & 1 ? PIX_FMT_BGR24 : PIX_FMT_YUVJ420P;
    161202
    162203    if (version < 2) {
    163204        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        }
    165213        needed_size += header_size;
    166214        if (buf_size != needed_size && buf_size != header_size) {
    167215            av_log(avctx, AV_LOG_ERROR,
    static int decode_frame(AVCodecContext *avctx,  
    169217                   buf_size, needed_size);
    170218            return -1;
    171219        }
    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;
    177221    } 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");
    191226                return -1;
    192227            }
    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            }
    199241        }
    200242    }
    201243
    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");
    210246        return -1;
    211247    }
    212248
    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) {
    214279    case 0:
    215280    default:
    216281        /* 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){
    230289                *luma1++ = *buf32++;
    231290                *luma1++ = *buf32++;
    232291                *luma2++ = *buf32++;
    static int decode_frame(AVCodecContext *avctx,  
    235294                *cb++    = *buf32++;
    236295            }
    237296        }
     297        ff_thread_report_progress(&s->buf_ptrs[s->cur_index], INT_MAX, 0);
    238298        break;
    239299
    240300    case 1:
    241301        /* 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]],
    244304                   &buf[y*avctx->width*3],
    245305                   3*avctx->width);
     306        ff_thread_report_progress(&s->buf_ptrs[s->cur_index], INT_MAX, 0);
    246307        break;
    247308
    248309    case 2:
    static int decode_frame(AVCodecContext *avctx,  
    253314         */
    254315        for(i = 0; i < planes; i++){
    255316            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) {
    258319                av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i);
    259320                return -1;
    260321            }
     322            else
     323                ff_thread_report_progress(&s->buf_ptrs[s->cur_index], i, 0);
    261324        }
    262325        break;
     326
    263327    case 3:
    264328    case 5:
    265329        /* Virtually the same as version 4, but is for RGB24 */
    266330        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) {
    269333                av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i);
    270334                return -1;
    271335            }
    272336        }
    273         out = f->data[0];
    274337        // convert pseudo-YUV into real RGB
     338        out = s->buf_ptrs[s->cur_index].data[0];
    275339        for(j = 0; j < avctx->height; j++){
    276340            uint8_t *line_end = out + 3*avctx->width;
    277341            while (out < line_end) {
    static int decode_frame(AVCodecContext *avctx,  
    279343                out[2]  += out[1];
    280344                out += 3;
    281345            }
    282             out += f->linesize[0] - 3*avctx->width;
     346            out += s->buf_ptrs[s->cur_index].linesize[0] - 3*avctx->width;
    283347        }
     348        ff_thread_report_progress(&s->buf_ptrs[s->cur_index], INT_MAX, 0);
    284349        break;
    285350    }
    286351
    287     *frame = *f;
     352end:
     353    *(AVFrame*)data = s->buf_ptrs[s->cur_index];
    288354    *data_size = sizeof(AVFrame);
    289355
     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
    290363    return buf_size;
    291364}
    292365
    static int decode_frame(AVCodecContext *avctx,  
    299372static av_cold int decode_end(AVCodecContext *avctx)
    300373{
    301374    FrapsContext *s = (FrapsContext*)avctx->priv_data;
    302 
    303     if (s->frame.data[0])
    304         avctx->release_buffer(avctx, &s->frame);
     375    int i;
    305376
    306377    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
    307386    return 0;
    308387}
    309388
    AVCodec ff_fraps_decoder = {  
    318397    .decode         = decode_frame,
    319398    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS,
    320399    .long_name = NULL_IF_CONFIG_SMALL("Fraps"),
     400    .update_thread_context = ONLY_IF_THREADS_ENABLED(fraps_decode_update_thread_context)
    321401};