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