1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * AVS3-P2/IEEE1857.10 video decoder (using the uavs3d library) 3cabdff1aSopenharmony_ci * Copyright (c) 2020 Zhenyu Wang <wangzhenyu@pkusz.edu.cn> 4cabdff1aSopenharmony_ci * Bingjie Han <hanbj@pkusz.edu.cn> 5cabdff1aSopenharmony_ci * Huiwen Ren <hwrenx@gmail.com> 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * This file is part of FFmpeg. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 10cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 11cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 12cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 15cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 16cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17cabdff1aSopenharmony_ci * Lesser General Public License for more details. 18cabdff1aSopenharmony_ci * 19cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 20cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 21cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22cabdff1aSopenharmony_ci */ 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "libavutil/avutil.h" 25cabdff1aSopenharmony_ci#include "libavutil/common.h" 26cabdff1aSopenharmony_ci#include "libavutil/cpu.h" 27cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 28cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 29cabdff1aSopenharmony_ci#include "libavutil/opt.h" 30cabdff1aSopenharmony_ci#include "avcodec.h" 31cabdff1aSopenharmony_ci#include "avs3.h" 32cabdff1aSopenharmony_ci#include "codec_internal.h" 33cabdff1aSopenharmony_ci#include "internal.h" 34cabdff1aSopenharmony_ci#include "uavs3d.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_citypedef struct uavs3d_context { 37cabdff1aSopenharmony_ci AVCodecContext *avctx; 38cabdff1aSopenharmony_ci void *dec_handle; 39cabdff1aSopenharmony_ci int frame_threads; 40cabdff1aSopenharmony_ci int got_seqhdr; 41cabdff1aSopenharmony_ci uavs3d_io_frm_t dec_frame; 42cabdff1aSopenharmony_ci} uavs3d_context; 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ci#define UAVS3D_CHECK_START_CODE(data_ptr, PIC_START_CODE) \ 45cabdff1aSopenharmony_ci (AV_RL32(data_ptr) != (PIC_START_CODE << 24) + AVS3_NAL_START_CODE) 46cabdff1aSopenharmony_cistatic int uavs3d_find_next_start_code(const unsigned char *bs_data, int bs_len, int *left) 47cabdff1aSopenharmony_ci{ 48cabdff1aSopenharmony_ci const unsigned char *data_ptr = bs_data + 4; 49cabdff1aSopenharmony_ci int count = bs_len - 4; 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_ci while (count >= 4 && 52cabdff1aSopenharmony_ci UAVS3D_CHECK_START_CODE(data_ptr, AVS3_INTER_PIC_START_CODE) && 53cabdff1aSopenharmony_ci UAVS3D_CHECK_START_CODE(data_ptr, AVS3_INTRA_PIC_START_CODE) && 54cabdff1aSopenharmony_ci UAVS3D_CHECK_START_CODE(data_ptr, AVS3_SEQ_START_CODE) && 55cabdff1aSopenharmony_ci UAVS3D_CHECK_START_CODE(data_ptr, AVS3_FIRST_SLICE_START_CODE) && 56cabdff1aSopenharmony_ci UAVS3D_CHECK_START_CODE(data_ptr, AVS3_SEQ_END_CODE)) { 57cabdff1aSopenharmony_ci data_ptr++; 58cabdff1aSopenharmony_ci count--; 59cabdff1aSopenharmony_ci } 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci if (count >= 4) { 62cabdff1aSopenharmony_ci *left = count; 63cabdff1aSopenharmony_ci return 1; 64cabdff1aSopenharmony_ci } 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_ci return 0; 67cabdff1aSopenharmony_ci} 68cabdff1aSopenharmony_ci 69cabdff1aSopenharmony_cistatic void uavs3d_output_callback(uavs3d_io_frm_t *dec_frame) { 70cabdff1aSopenharmony_ci uavs3d_io_frm_t frm_out; 71cabdff1aSopenharmony_ci AVFrame *frm = (AVFrame *)dec_frame->priv; 72cabdff1aSopenharmony_ci int i; 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_ci if (!frm || !frm->data[0]) { 75cabdff1aSopenharmony_ci dec_frame->got_pic = 0; 76cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Invalid AVFrame in uavs3d output.\n"); 77cabdff1aSopenharmony_ci return; 78cabdff1aSopenharmony_ci } 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_ci frm->pts = dec_frame->pts; 81cabdff1aSopenharmony_ci frm->pkt_dts = dec_frame->dts; 82cabdff1aSopenharmony_ci frm->pkt_pos = dec_frame->pkt_pos; 83cabdff1aSopenharmony_ci frm->pkt_size = dec_frame->pkt_size; 84cabdff1aSopenharmony_ci frm->coded_picture_number = dec_frame->dtr; 85cabdff1aSopenharmony_ci frm->display_picture_number = dec_frame->ptr; 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci if (dec_frame->type < 0 || dec_frame->type >= FF_ARRAY_ELEMS(ff_avs3_image_type)) { 88cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_WARNING, "Error frame type in uavs3d: %d.\n", dec_frame->type); 89cabdff1aSopenharmony_ci } else { 90cabdff1aSopenharmony_ci frm->pict_type = ff_avs3_image_type[dec_frame->type]; 91cabdff1aSopenharmony_ci frm->key_frame = (frm->pict_type == AV_PICTURE_TYPE_I); 92cabdff1aSopenharmony_ci } 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_ci for (i = 0; i < 3; i++) { 95cabdff1aSopenharmony_ci frm_out.width [i] = dec_frame->width[i]; 96cabdff1aSopenharmony_ci frm_out.height[i] = dec_frame->height[i]; 97cabdff1aSopenharmony_ci frm_out.stride[i] = frm->linesize[i]; 98cabdff1aSopenharmony_ci frm_out.buffer[i] = frm->data[i]; 99cabdff1aSopenharmony_ci } 100cabdff1aSopenharmony_ci 101cabdff1aSopenharmony_ci uavs3d_img_cpy_cvt(&frm_out, dec_frame, dec_frame->bit_depth); 102cabdff1aSopenharmony_ci} 103cabdff1aSopenharmony_ci 104cabdff1aSopenharmony_cistatic av_cold int libuavs3d_init(AVCodecContext *avctx) 105cabdff1aSopenharmony_ci{ 106cabdff1aSopenharmony_ci uavs3d_context *h = avctx->priv_data; 107cabdff1aSopenharmony_ci uavs3d_cfg_t cdsc; 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci cdsc.frm_threads = avctx->thread_count > 0 ? avctx->thread_count : av_cpu_count(); 110cabdff1aSopenharmony_ci cdsc.check_md5 = 0; 111cabdff1aSopenharmony_ci h->dec_handle = uavs3d_create(&cdsc, uavs3d_output_callback, NULL); 112cabdff1aSopenharmony_ci h->got_seqhdr = 0; 113cabdff1aSopenharmony_ci 114cabdff1aSopenharmony_ci if (!h->dec_handle) { 115cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 116cabdff1aSopenharmony_ci } 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci return 0; 119cabdff1aSopenharmony_ci} 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_cistatic av_cold int libuavs3d_end(AVCodecContext *avctx) 122cabdff1aSopenharmony_ci{ 123cabdff1aSopenharmony_ci uavs3d_context *h = avctx->priv_data; 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci if (h->dec_handle) { 126cabdff1aSopenharmony_ci uavs3d_flush(h->dec_handle, NULL); 127cabdff1aSopenharmony_ci uavs3d_delete(h->dec_handle); 128cabdff1aSopenharmony_ci h->dec_handle = NULL; 129cabdff1aSopenharmony_ci } 130cabdff1aSopenharmony_ci h->got_seqhdr = 0; 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci return 0; 133cabdff1aSopenharmony_ci} 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_cistatic void libuavs3d_flush(AVCodecContext * avctx) 136cabdff1aSopenharmony_ci{ 137cabdff1aSopenharmony_ci uavs3d_context *h = avctx->priv_data; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci if (h->dec_handle) { 140cabdff1aSopenharmony_ci uavs3d_reset(h->dec_handle); 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci} 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_ci#define UAVS3D_CHECK_INVALID_RANGE(v, l, r) ((v)<(l)||(v)>(r)) 145cabdff1aSopenharmony_cistatic int libuavs3d_decode_frame(AVCodecContext *avctx, AVFrame *frm, 146cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 147cabdff1aSopenharmony_ci{ 148cabdff1aSopenharmony_ci uavs3d_context *h = avctx->priv_data; 149cabdff1aSopenharmony_ci const uint8_t *buf = avpkt->data; 150cabdff1aSopenharmony_ci int buf_size = avpkt->size; 151cabdff1aSopenharmony_ci const uint8_t *buf_end; 152cabdff1aSopenharmony_ci const uint8_t *buf_ptr = buf; 153cabdff1aSopenharmony_ci int left_bytes; 154cabdff1aSopenharmony_ci int ret, finish = 0; 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci *got_frame = 0; 157cabdff1aSopenharmony_ci frm->pts = -1; 158cabdff1aSopenharmony_ci frm->pict_type = AV_PICTURE_TYPE_NONE; 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci if (!buf_size) { 161cabdff1aSopenharmony_ci if (h->got_seqhdr) { 162cabdff1aSopenharmony_ci if (!frm->data[0] && (ret = ff_get_buffer(avctx, frm, 0)) < 0) { 163cabdff1aSopenharmony_ci return ret; 164cabdff1aSopenharmony_ci } 165cabdff1aSopenharmony_ci h->dec_frame.priv = frm; // AVFrame 166cabdff1aSopenharmony_ci } 167cabdff1aSopenharmony_ci do { 168cabdff1aSopenharmony_ci ret = uavs3d_flush(h->dec_handle, &h->dec_frame); 169cabdff1aSopenharmony_ci } while (ret > 0 && !h->dec_frame.got_pic); 170cabdff1aSopenharmony_ci } else { 171cabdff1aSopenharmony_ci uavs3d_io_frm_t *frm_dec = &h->dec_frame; 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci buf_end = buf + buf_size; 174cabdff1aSopenharmony_ci frm_dec->pkt_pos = avpkt->pos; 175cabdff1aSopenharmony_ci frm_dec->pkt_size = avpkt->size; 176cabdff1aSopenharmony_ci 177cabdff1aSopenharmony_ci while (!finish) { 178cabdff1aSopenharmony_ci int bs_len; 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci if (h->got_seqhdr) { 181cabdff1aSopenharmony_ci if (!frm->data[0] && (ret = ff_get_buffer(avctx, frm, 0)) < 0) { 182cabdff1aSopenharmony_ci return ret; 183cabdff1aSopenharmony_ci } 184cabdff1aSopenharmony_ci h->dec_frame.priv = frm; // AVFrame 185cabdff1aSopenharmony_ci } 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci if (uavs3d_find_next_start_code(buf_ptr, buf_end - buf_ptr, &left_bytes)) { 188cabdff1aSopenharmony_ci bs_len = buf_end - buf_ptr - left_bytes; 189cabdff1aSopenharmony_ci } else { 190cabdff1aSopenharmony_ci bs_len = buf_end - buf_ptr; 191cabdff1aSopenharmony_ci finish = 1; 192cabdff1aSopenharmony_ci } 193cabdff1aSopenharmony_ci frm_dec->bs = (unsigned char *)buf_ptr; 194cabdff1aSopenharmony_ci frm_dec->bs_len = bs_len; 195cabdff1aSopenharmony_ci frm_dec->pts = avpkt->pts; 196cabdff1aSopenharmony_ci frm_dec->dts = avpkt->dts; 197cabdff1aSopenharmony_ci uavs3d_decode(h->dec_handle, frm_dec); 198cabdff1aSopenharmony_ci buf_ptr += bs_len; 199cabdff1aSopenharmony_ci 200cabdff1aSopenharmony_ci if (frm_dec->nal_type == NAL_SEQ_HEADER) { 201cabdff1aSopenharmony_ci struct uavs3d_com_seqh_t *seqh = frm_dec->seqhdr; 202cabdff1aSopenharmony_ci if (UAVS3D_CHECK_INVALID_RANGE(seqh->frame_rate_code, 0, 15)) { 203cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Invalid frame rate code: %d.\n", seqh->frame_rate_code); 204cabdff1aSopenharmony_ci seqh->frame_rate_code = 3; // default 25 fps 205cabdff1aSopenharmony_ci } else { 206cabdff1aSopenharmony_ci avctx->framerate.num = ff_avs3_frame_rate_tab[seqh->frame_rate_code].num; 207cabdff1aSopenharmony_ci avctx->framerate.den = ff_avs3_frame_rate_tab[seqh->frame_rate_code].den; 208cabdff1aSopenharmony_ci } 209cabdff1aSopenharmony_ci avctx->has_b_frames = seqh->output_reorder_delay; 210cabdff1aSopenharmony_ci avctx->pix_fmt = seqh->bit_depth_internal == 8 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUV420P10LE; 211cabdff1aSopenharmony_ci ret = ff_set_dimensions(avctx, seqh->horizontal_size, seqh->vertical_size); 212cabdff1aSopenharmony_ci if (ret < 0) 213cabdff1aSopenharmony_ci return ret; 214cabdff1aSopenharmony_ci h->got_seqhdr = 1; 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci if (seqh->colour_description) { 217cabdff1aSopenharmony_ci if (UAVS3D_CHECK_INVALID_RANGE(seqh->colour_primaries, 0, 9) || 218cabdff1aSopenharmony_ci UAVS3D_CHECK_INVALID_RANGE(seqh->transfer_characteristics, 0, 14) || 219cabdff1aSopenharmony_ci UAVS3D_CHECK_INVALID_RANGE(seqh->matrix_coefficients, 0, 11)) { 220cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, 221cabdff1aSopenharmony_ci "Invalid colour description: primaries: %d" 222cabdff1aSopenharmony_ci "transfer characteristics: %d" 223cabdff1aSopenharmony_ci "matrix coefficients: %d.\n", 224cabdff1aSopenharmony_ci seqh->colour_primaries, 225cabdff1aSopenharmony_ci seqh->transfer_characteristics, 226cabdff1aSopenharmony_ci seqh->matrix_coefficients); 227cabdff1aSopenharmony_ci } else { 228cabdff1aSopenharmony_ci avctx->color_primaries = ff_avs3_color_primaries_tab[seqh->colour_primaries]; 229cabdff1aSopenharmony_ci avctx->color_trc = ff_avs3_color_transfer_tab [seqh->transfer_characteristics]; 230cabdff1aSopenharmony_ci avctx->colorspace = ff_avs3_color_matrix_tab [seqh->matrix_coefficients]; 231cabdff1aSopenharmony_ci } 232cabdff1aSopenharmony_ci } 233cabdff1aSopenharmony_ci } 234cabdff1aSopenharmony_ci if (frm_dec->got_pic) { 235cabdff1aSopenharmony_ci break; 236cabdff1aSopenharmony_ci } 237cabdff1aSopenharmony_ci } 238cabdff1aSopenharmony_ci } 239cabdff1aSopenharmony_ci 240cabdff1aSopenharmony_ci *got_frame = h->dec_frame.got_pic; 241cabdff1aSopenharmony_ci 242cabdff1aSopenharmony_ci if (!(*got_frame)) { 243cabdff1aSopenharmony_ci av_frame_unref(frm); 244cabdff1aSopenharmony_ci } 245cabdff1aSopenharmony_ci 246cabdff1aSopenharmony_ci return buf_ptr - buf; 247cabdff1aSopenharmony_ci} 248cabdff1aSopenharmony_ci 249cabdff1aSopenharmony_ciconst FFCodec ff_libuavs3d_decoder = { 250cabdff1aSopenharmony_ci .p.name = "libuavs3d", 251cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("libuavs3d AVS3-P2/IEEE1857.10"), 252cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 253cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_AVS3, 254cabdff1aSopenharmony_ci .priv_data_size = sizeof(uavs3d_context), 255cabdff1aSopenharmony_ci .init = libuavs3d_init, 256cabdff1aSopenharmony_ci .close = libuavs3d_end, 257cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(libuavs3d_decode_frame), 258cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, 259cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_AUTO_THREADS, 260cabdff1aSopenharmony_ci .flush = libuavs3d_flush, 261cabdff1aSopenharmony_ci .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, 262cabdff1aSopenharmony_ci AV_PIX_FMT_YUV420P10LE, 263cabdff1aSopenharmony_ci AV_PIX_FMT_NONE }, 264cabdff1aSopenharmony_ci .p.wrapper_name = "libuavs3d", 265cabdff1aSopenharmony_ci}; 266