1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Fraps FPS1 decoder
3cabdff1aSopenharmony_ci * Copyright (c) 2005 Roine Gustafsson
4cabdff1aSopenharmony_ci * Copyright (c) 2006 Konstantin Shishkov
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci/**
24cabdff1aSopenharmony_ci * @file
25cabdff1aSopenharmony_ci * Lossless Fraps 'FPS1' decoder
26cabdff1aSopenharmony_ci * @author Roine Gustafsson (roine at users sf net)
27cabdff1aSopenharmony_ci * @author Konstantin Shishkov
28cabdff1aSopenharmony_ci *
29cabdff1aSopenharmony_ci * Codec algorithm for version 0 is taken from Transcode <www.transcoding.org>
30cabdff1aSopenharmony_ci *
31cabdff1aSopenharmony_ci * Version 2 files support by Konstantin Shishkov
32cabdff1aSopenharmony_ci */
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_ci#include "config.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_ci#define CACHED_BITSTREAM_READER HAVE_FAST_64BIT
37cabdff1aSopenharmony_ci#define UNCHECKED_BITSTREAM_READER 1
38cabdff1aSopenharmony_ci#include "avcodec.h"
39cabdff1aSopenharmony_ci#include "get_bits.h"
40cabdff1aSopenharmony_ci#include "huffman.h"
41cabdff1aSopenharmony_ci#include "bytestream.h"
42cabdff1aSopenharmony_ci#include "bswapdsp.h"
43cabdff1aSopenharmony_ci#include "codec_internal.h"
44cabdff1aSopenharmony_ci#include "thread.h"
45cabdff1aSopenharmony_ci
46cabdff1aSopenharmony_ci#define FPS_TAG MKTAG('F', 'P', 'S', 'x')
47cabdff1aSopenharmony_ci#define VLC_BITS 11
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_ci/**
50cabdff1aSopenharmony_ci * local variable storage
51cabdff1aSopenharmony_ci */
52cabdff1aSopenharmony_citypedef struct FrapsContext {
53cabdff1aSopenharmony_ci    AVCodecContext *avctx;
54cabdff1aSopenharmony_ci    BswapDSPContext bdsp;
55cabdff1aSopenharmony_ci    uint8_t *tmpbuf;
56cabdff1aSopenharmony_ci    int tmpbuf_size;
57cabdff1aSopenharmony_ci} FrapsContext;
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_ci/**
61cabdff1aSopenharmony_ci * initializes decoder
62cabdff1aSopenharmony_ci * @param avctx codec context
63cabdff1aSopenharmony_ci * @return 0 on success or negative if fails
64cabdff1aSopenharmony_ci */
65cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx)
66cabdff1aSopenharmony_ci{
67cabdff1aSopenharmony_ci    FrapsContext * const s = avctx->priv_data;
68cabdff1aSopenharmony_ci
69cabdff1aSopenharmony_ci    s->avctx  = avctx;
70cabdff1aSopenharmony_ci    s->tmpbuf = NULL;
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_ci    ff_bswapdsp_init(&s->bdsp);
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    return 0;
75cabdff1aSopenharmony_ci}
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci/**
78cabdff1aSopenharmony_ci * Comparator - our nodes should ascend by count
79cabdff1aSopenharmony_ci * but with preserved symbol order
80cabdff1aSopenharmony_ci */
81cabdff1aSopenharmony_cistatic int huff_cmp(const void *va, const void *vb)
82cabdff1aSopenharmony_ci{
83cabdff1aSopenharmony_ci    const Node *a = va, *b = vb;
84cabdff1aSopenharmony_ci    return (a->count - b->count)*256 + a->sym - b->sym;
85cabdff1aSopenharmony_ci}
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_ci/**
88cabdff1aSopenharmony_ci * decode Fraps v2 packed plane
89cabdff1aSopenharmony_ci */
90cabdff1aSopenharmony_cistatic int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w,
91cabdff1aSopenharmony_ci                               int h, const uint8_t *src, int size, int Uoff,
92cabdff1aSopenharmony_ci                               const int step)
93cabdff1aSopenharmony_ci{
94cabdff1aSopenharmony_ci    int i, j, ret;
95cabdff1aSopenharmony_ci    GetBitContext gb;
96cabdff1aSopenharmony_ci    VLC vlc;
97cabdff1aSopenharmony_ci    Node nodes[512];
98cabdff1aSopenharmony_ci
99cabdff1aSopenharmony_ci    for (i = 0; i < 256; i++)
100cabdff1aSopenharmony_ci        nodes[i].count = bytestream_get_le32(&src);
101cabdff1aSopenharmony_ci    size -= 1024;
102cabdff1aSopenharmony_ci    if ((ret = ff_huff_build_tree(s->avctx, &vlc, 256, VLC_BITS,
103cabdff1aSopenharmony_ci                                  nodes, huff_cmp,
104cabdff1aSopenharmony_ci                                  FF_HUFFMAN_FLAG_ZERO_COUNT)) < 0)
105cabdff1aSopenharmony_ci        return ret;
106cabdff1aSopenharmony_ci    /* we have built Huffman table and are ready to decode plane */
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ci    /* convert bits so they may be used by standard bitreader */
109cabdff1aSopenharmony_ci    s->bdsp.bswap_buf((uint32_t *) s->tmpbuf,
110cabdff1aSopenharmony_ci                      (const uint32_t *) src, size >> 2);
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    if ((ret = init_get_bits8(&gb, s->tmpbuf, size)) < 0)
113cabdff1aSopenharmony_ci        return ret;
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_ci    for (j = 0; j < h; j++) {
116cabdff1aSopenharmony_ci        for (i = 0; i < w*step; i += step) {
117cabdff1aSopenharmony_ci            dst[i] = get_vlc2(&gb, vlc.table, VLC_BITS, 3);
118cabdff1aSopenharmony_ci            /* lines are stored as deltas between previous lines
119cabdff1aSopenharmony_ci             * and we need to add 0x80 to the first lines of chroma planes
120cabdff1aSopenharmony_ci             */
121cabdff1aSopenharmony_ci            if (j)
122cabdff1aSopenharmony_ci                dst[i] += dst[i - stride];
123cabdff1aSopenharmony_ci            else if (Uoff)
124cabdff1aSopenharmony_ci                dst[i] += 0x80;
125cabdff1aSopenharmony_ci            if (get_bits_left(&gb) < 0) {
126cabdff1aSopenharmony_ci                ff_free_vlc(&vlc);
127cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
128cabdff1aSopenharmony_ci            }
129cabdff1aSopenharmony_ci        }
130cabdff1aSopenharmony_ci        dst += stride;
131cabdff1aSopenharmony_ci    }
132cabdff1aSopenharmony_ci    ff_free_vlc(&vlc);
133cabdff1aSopenharmony_ci    return 0;
134cabdff1aSopenharmony_ci}
135cabdff1aSopenharmony_ci
136cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *f,
137cabdff1aSopenharmony_ci                        int *got_frame, AVPacket *avpkt)
138cabdff1aSopenharmony_ci{
139cabdff1aSopenharmony_ci    FrapsContext * const s = avctx->priv_data;
140cabdff1aSopenharmony_ci    const uint8_t *buf     = avpkt->data;
141cabdff1aSopenharmony_ci    int buf_size           = avpkt->size;
142cabdff1aSopenharmony_ci    uint32_t header;
143cabdff1aSopenharmony_ci    unsigned int version,header_size;
144cabdff1aSopenharmony_ci    unsigned int x, y;
145cabdff1aSopenharmony_ci    const uint32_t *buf32;
146cabdff1aSopenharmony_ci    uint32_t *luma1,*luma2,*cb,*cr;
147cabdff1aSopenharmony_ci    uint32_t offs[4];
148cabdff1aSopenharmony_ci    int i, j, ret, is_chroma;
149cabdff1aSopenharmony_ci    const int planes = 3;
150cabdff1aSopenharmony_ci    int is_pal;
151cabdff1aSopenharmony_ci    uint8_t *out;
152cabdff1aSopenharmony_ci
153cabdff1aSopenharmony_ci    if (buf_size < 4) {
154cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Packet is too short\n");
155cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
156cabdff1aSopenharmony_ci    }
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_ci    header      = AV_RL32(buf);
159cabdff1aSopenharmony_ci    version     = header & 0xff;
160cabdff1aSopenharmony_ci    is_pal      = buf[1] == 2 && version == 1;
161cabdff1aSopenharmony_ci    header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_ci    if (version > 5) {
164cabdff1aSopenharmony_ci        avpriv_report_missing_feature(avctx, "Fraps version %u", version);
165cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
166cabdff1aSopenharmony_ci    }
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_ci    buf += header_size;
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_ci    if (is_pal) {
171cabdff1aSopenharmony_ci        unsigned needed_size = avctx->width * avctx->height + 1024;
172cabdff1aSopenharmony_ci        needed_size += header_size;
173cabdff1aSopenharmony_ci        if (buf_size != needed_size) {
174cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
175cabdff1aSopenharmony_ci                   "Invalid frame length %d (should be %d)\n",
176cabdff1aSopenharmony_ci                   buf_size, needed_size);
177cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
178cabdff1aSopenharmony_ci        }
179cabdff1aSopenharmony_ci    } else if (version < 2) {
180cabdff1aSopenharmony_ci        unsigned needed_size = avctx->width * avctx->height * 3;
181cabdff1aSopenharmony_ci        if (version == 0) needed_size /= 2;
182cabdff1aSopenharmony_ci        needed_size += header_size;
183cabdff1aSopenharmony_ci        /* bit 31 means same as previous pic */
184cabdff1aSopenharmony_ci        if (header & (1U<<31)) {
185cabdff1aSopenharmony_ci            *got_frame = 0;
186cabdff1aSopenharmony_ci            return buf_size;
187cabdff1aSopenharmony_ci        }
188cabdff1aSopenharmony_ci        if (buf_size != needed_size) {
189cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
190cabdff1aSopenharmony_ci                   "Invalid frame length %d (should be %d)\n",
191cabdff1aSopenharmony_ci                   buf_size, needed_size);
192cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
193cabdff1aSopenharmony_ci        }
194cabdff1aSopenharmony_ci    } else {
195cabdff1aSopenharmony_ci        /* skip frame */
196cabdff1aSopenharmony_ci        if (buf_size == 8) {
197cabdff1aSopenharmony_ci            *got_frame = 0;
198cabdff1aSopenharmony_ci            return buf_size;
199cabdff1aSopenharmony_ci        }
200cabdff1aSopenharmony_ci        if (AV_RL32(buf) != FPS_TAG || buf_size < planes*1024 + 24) {
201cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "error in data stream\n");
202cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
203cabdff1aSopenharmony_ci        }
204cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++) {
205cabdff1aSopenharmony_ci            offs[i] = AV_RL32(buf + 4 + i * 4);
206cabdff1aSopenharmony_ci            if (offs[i] >= buf_size - header_size || (i && offs[i] <= offs[i - 1] + 1024)) {
207cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "plane %i offset is out of bounds\n", i);
208cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
209cabdff1aSopenharmony_ci            }
210cabdff1aSopenharmony_ci        }
211cabdff1aSopenharmony_ci        offs[planes] = buf_size - header_size;
212cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++) {
213cabdff1aSopenharmony_ci            av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size, offs[i + 1] - offs[i] - 1024);
214cabdff1aSopenharmony_ci            if (!s->tmpbuf)
215cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
216cabdff1aSopenharmony_ci        }
217cabdff1aSopenharmony_ci    }
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci    f->pict_type = AV_PICTURE_TYPE_I;
220cabdff1aSopenharmony_ci    f->key_frame = 1;
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_ci    avctx->pix_fmt = version & 1 ? is_pal ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUVJ420P;
223cabdff1aSopenharmony_ci    avctx->color_range = version & 1 ? AVCOL_RANGE_UNSPECIFIED
224cabdff1aSopenharmony_ci                                     : AVCOL_RANGE_JPEG;
225cabdff1aSopenharmony_ci    avctx->colorspace = version & 1 ? AVCOL_SPC_UNSPECIFIED : AVCOL_SPC_BT709;
226cabdff1aSopenharmony_ci
227cabdff1aSopenharmony_ci    if ((ret = ff_thread_get_buffer(avctx, f, 0)) < 0)
228cabdff1aSopenharmony_ci        return ret;
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci    switch (version) {
231cabdff1aSopenharmony_ci    case 0:
232cabdff1aSopenharmony_ci    default:
233cabdff1aSopenharmony_ci        /* Fraps v0 is a reordered YUV420 */
234cabdff1aSopenharmony_ci        if (((avctx->width % 8) != 0) || ((avctx->height % 2) != 0)) {
235cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n",
236cabdff1aSopenharmony_ci                   avctx->width, avctx->height);
237cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
238cabdff1aSopenharmony_ci        }
239cabdff1aSopenharmony_ci
240cabdff1aSopenharmony_ci        buf32 = (const uint32_t*)buf;
241cabdff1aSopenharmony_ci        for (y = 0; y < avctx->height / 2; y++) {
242cabdff1aSopenharmony_ci            luma1 = (uint32_t*)&f->data[0][  y * 2      * f->linesize[0] ];
243cabdff1aSopenharmony_ci            luma2 = (uint32_t*)&f->data[0][ (y * 2 + 1) * f->linesize[0] ];
244cabdff1aSopenharmony_ci            cr    = (uint32_t*)&f->data[1][  y          * f->linesize[1] ];
245cabdff1aSopenharmony_ci            cb    = (uint32_t*)&f->data[2][  y          * f->linesize[2] ];
246cabdff1aSopenharmony_ci            for (x = 0; x < avctx->width; x += 8) {
247cabdff1aSopenharmony_ci                *luma1++ = *buf32++;
248cabdff1aSopenharmony_ci                *luma1++ = *buf32++;
249cabdff1aSopenharmony_ci                *luma2++ = *buf32++;
250cabdff1aSopenharmony_ci                *luma2++ = *buf32++;
251cabdff1aSopenharmony_ci                *cr++    = *buf32++;
252cabdff1aSopenharmony_ci                *cb++    = *buf32++;
253cabdff1aSopenharmony_ci            }
254cabdff1aSopenharmony_ci        }
255cabdff1aSopenharmony_ci        break;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci    case 1:
258cabdff1aSopenharmony_ci        if (is_pal) {
259cabdff1aSopenharmony_ci            uint32_t *pal = (uint32_t *)f->data[1];
260cabdff1aSopenharmony_ci
261cabdff1aSopenharmony_ci            for (y = 0; y < 256; y++) {
262cabdff1aSopenharmony_ci                pal[y] = AV_RL32(buf) | 0xFF000000;
263cabdff1aSopenharmony_ci                buf += 4;
264cabdff1aSopenharmony_ci            }
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci            for (y = 0; y <avctx->height; y++)
267cabdff1aSopenharmony_ci                memcpy(&f->data[0][y * f->linesize[0]],
268cabdff1aSopenharmony_ci                       &buf[y * avctx->width],
269cabdff1aSopenharmony_ci                       avctx->width);
270cabdff1aSopenharmony_ci        } else {
271cabdff1aSopenharmony_ci        /* Fraps v1 is an upside-down BGR24 */
272cabdff1aSopenharmony_ci            for (y = 0; y<avctx->height; y++)
273cabdff1aSopenharmony_ci                memcpy(&f->data[0][(avctx->height - y - 1) * f->linesize[0]],
274cabdff1aSopenharmony_ci                       &buf[y * avctx->width * 3],
275cabdff1aSopenharmony_ci                       3 * avctx->width);
276cabdff1aSopenharmony_ci        }
277cabdff1aSopenharmony_ci        break;
278cabdff1aSopenharmony_ci
279cabdff1aSopenharmony_ci    case 2:
280cabdff1aSopenharmony_ci    case 4:
281cabdff1aSopenharmony_ci        /**
282cabdff1aSopenharmony_ci         * Fraps v2 is Huffman-coded YUV420 planes
283cabdff1aSopenharmony_ci         * Fraps v4 is virtually the same
284cabdff1aSopenharmony_ci         */
285cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++) {
286cabdff1aSopenharmony_ci            is_chroma = !!i;
287cabdff1aSopenharmony_ci            if ((ret = fraps2_decode_plane(s, f->data[i], f->linesize[i],
288cabdff1aSopenharmony_ci                                           avctx->width  >> is_chroma,
289cabdff1aSopenharmony_ci                                           avctx->height >> is_chroma,
290cabdff1aSopenharmony_ci                                           buf + offs[i], offs[i + 1] - offs[i],
291cabdff1aSopenharmony_ci                                           is_chroma, 1)) < 0) {
292cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i);
293cabdff1aSopenharmony_ci                return ret;
294cabdff1aSopenharmony_ci            }
295cabdff1aSopenharmony_ci        }
296cabdff1aSopenharmony_ci        break;
297cabdff1aSopenharmony_ci    case 3:
298cabdff1aSopenharmony_ci    case 5:
299cabdff1aSopenharmony_ci        /* Virtually the same as version 4, but is for RGB24 */
300cabdff1aSopenharmony_ci        for (i = 0; i < planes; i++) {
301cabdff1aSopenharmony_ci            if ((ret = fraps2_decode_plane(s, f->data[0] + i + (f->linesize[0] * (avctx->height - 1)),
302cabdff1aSopenharmony_ci                                           -f->linesize[0], avctx->width, avctx->height,
303cabdff1aSopenharmony_ci                                           buf + offs[i], offs[i + 1] - offs[i], 0, 3)) < 0) {
304cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i);
305cabdff1aSopenharmony_ci                return ret;
306cabdff1aSopenharmony_ci            }
307cabdff1aSopenharmony_ci        }
308cabdff1aSopenharmony_ci        out = f->data[0];
309cabdff1aSopenharmony_ci        // convert pseudo-YUV into real RGB
310cabdff1aSopenharmony_ci        for (j = 0; j < avctx->height; j++) {
311cabdff1aSopenharmony_ci            uint8_t *line_end = out + 3*avctx->width;
312cabdff1aSopenharmony_ci            while (out < line_end) {
313cabdff1aSopenharmony_ci                out[0]  += out[1];
314cabdff1aSopenharmony_ci                out[2]  += out[1];
315cabdff1aSopenharmony_ci                out += 3;
316cabdff1aSopenharmony_ci            }
317cabdff1aSopenharmony_ci            out += f->linesize[0] - 3*avctx->width;
318cabdff1aSopenharmony_ci        }
319cabdff1aSopenharmony_ci        break;
320cabdff1aSopenharmony_ci    }
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_ci    *got_frame = 1;
323cabdff1aSopenharmony_ci
324cabdff1aSopenharmony_ci    return buf_size;
325cabdff1aSopenharmony_ci}
326cabdff1aSopenharmony_ci
327cabdff1aSopenharmony_ci
328cabdff1aSopenharmony_ci/**
329cabdff1aSopenharmony_ci * closes decoder
330cabdff1aSopenharmony_ci * @param avctx codec context
331cabdff1aSopenharmony_ci * @return 0 on success or negative if fails
332cabdff1aSopenharmony_ci */
333cabdff1aSopenharmony_cistatic av_cold int decode_end(AVCodecContext *avctx)
334cabdff1aSopenharmony_ci{
335cabdff1aSopenharmony_ci    FrapsContext *s = (FrapsContext*)avctx->priv_data;
336cabdff1aSopenharmony_ci
337cabdff1aSopenharmony_ci    av_freep(&s->tmpbuf);
338cabdff1aSopenharmony_ci    return 0;
339cabdff1aSopenharmony_ci}
340cabdff1aSopenharmony_ci
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_ciconst FFCodec ff_fraps_decoder = {
343cabdff1aSopenharmony_ci    .p.name         = "fraps",
344cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Fraps"),
345cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
346cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_FRAPS,
347cabdff1aSopenharmony_ci    .priv_data_size = sizeof(FrapsContext),
348cabdff1aSopenharmony_ci    .init           = decode_init,
349cabdff1aSopenharmony_ci    .close          = decode_end,
350cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(decode_frame),
351cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
352cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
353cabdff1aSopenharmony_ci};
354