1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2010, Google, Inc. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14cabdff1aSopenharmony_ci * Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci/** 22cabdff1aSopenharmony_ci * @file 23cabdff1aSopenharmony_ci * AV1 decoder support via libaom 24cabdff1aSopenharmony_ci */ 25cabdff1aSopenharmony_ci 26cabdff1aSopenharmony_ci#include <aom/aom_decoder.h> 27cabdff1aSopenharmony_ci#include <aom/aomdx.h> 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_ci#include "libavutil/common.h" 30cabdff1aSopenharmony_ci#include "libavutil/cpu.h" 31cabdff1aSopenharmony_ci#include "libavutil/imgutils.h" 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_ci#include "avcodec.h" 34cabdff1aSopenharmony_ci#include "codec_internal.h" 35cabdff1aSopenharmony_ci#include "internal.h" 36cabdff1aSopenharmony_ci#include "profiles.h" 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_citypedef struct AV1DecodeContext { 39cabdff1aSopenharmony_ci struct aom_codec_ctx decoder; 40cabdff1aSopenharmony_ci} AV1DecodeContext; 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_cistatic av_cold int aom_init(AVCodecContext *avctx, 43cabdff1aSopenharmony_ci const struct aom_codec_iface *iface) 44cabdff1aSopenharmony_ci{ 45cabdff1aSopenharmony_ci AV1DecodeContext *ctx = avctx->priv_data; 46cabdff1aSopenharmony_ci struct aom_codec_dec_cfg deccfg = { 47cabdff1aSopenharmony_ci .threads = FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), 16) 48cabdff1aSopenharmony_ci }; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_INFO, "%s\n", aom_codec_version_str()); 51cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_VERBOSE, "%s\n", aom_codec_build_config()); 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci if (aom_codec_dec_init(&ctx->decoder, iface, &deccfg, 0) != AOM_CODEC_OK) { 54cabdff1aSopenharmony_ci const char *error = aom_codec_error(&ctx->decoder); 55cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n", 56cabdff1aSopenharmony_ci error); 57cabdff1aSopenharmony_ci return AVERROR(EINVAL); 58cabdff1aSopenharmony_ci } 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci return 0; 61cabdff1aSopenharmony_ci} 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_cistatic void image_copy_16_to_8(AVFrame *pic, struct aom_image *img) 64cabdff1aSopenharmony_ci{ 65cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format); 66cabdff1aSopenharmony_ci int i; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_components; i++) { 69cabdff1aSopenharmony_ci int w = img->d_w; 70cabdff1aSopenharmony_ci int h = img->d_h; 71cabdff1aSopenharmony_ci int x, y; 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_ci if (i) { 74cabdff1aSopenharmony_ci w = (w + img->x_chroma_shift) >> img->x_chroma_shift; 75cabdff1aSopenharmony_ci h = (h + img->y_chroma_shift) >> img->y_chroma_shift; 76cabdff1aSopenharmony_ci } 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci for (y = 0; y < h; y++) { 79cabdff1aSopenharmony_ci uint16_t *src = (uint16_t *)(img->planes[i] + y * img->stride[i]); 80cabdff1aSopenharmony_ci uint8_t *dst = pic->data[i] + y * pic->linesize[i]; 81cabdff1aSopenharmony_ci for (x = 0; x < w; x++) 82cabdff1aSopenharmony_ci *dst++ = *src++; 83cabdff1aSopenharmony_ci } 84cabdff1aSopenharmony_ci } 85cabdff1aSopenharmony_ci} 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci// returns 0 on success, AVERROR_INVALIDDATA otherwise 88cabdff1aSopenharmony_cistatic int set_pix_fmt(AVCodecContext *avctx, struct aom_image *img) 89cabdff1aSopenharmony_ci{ 90cabdff1aSopenharmony_ci static const enum AVColorRange color_ranges[] = { 91cabdff1aSopenharmony_ci AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG 92cabdff1aSopenharmony_ci }; 93cabdff1aSopenharmony_ci avctx->color_range = color_ranges[img->range]; 94cabdff1aSopenharmony_ci avctx->color_primaries = img->cp; 95cabdff1aSopenharmony_ci avctx->colorspace = img->mc; 96cabdff1aSopenharmony_ci avctx->color_trc = img->tc; 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci switch (img->fmt) { 99cabdff1aSopenharmony_ci case AOM_IMG_FMT_I420: 100cabdff1aSopenharmony_ci case AOM_IMG_FMT_I42016: 101cabdff1aSopenharmony_ci if (img->bit_depth == 8) { 102cabdff1aSopenharmony_ci avctx->pix_fmt = img->monochrome ? 103cabdff1aSopenharmony_ci AV_PIX_FMT_GRAY8 : AV_PIX_FMT_YUV420P; 104cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_MAIN; 105cabdff1aSopenharmony_ci return 0; 106cabdff1aSopenharmony_ci } else if (img->bit_depth == 10) { 107cabdff1aSopenharmony_ci avctx->pix_fmt = img->monochrome ? 108cabdff1aSopenharmony_ci AV_PIX_FMT_GRAY10 : AV_PIX_FMT_YUV420P10; 109cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_MAIN; 110cabdff1aSopenharmony_ci return 0; 111cabdff1aSopenharmony_ci } else if (img->bit_depth == 12) { 112cabdff1aSopenharmony_ci avctx->pix_fmt = img->monochrome ? 113cabdff1aSopenharmony_ci AV_PIX_FMT_GRAY12 : AV_PIX_FMT_YUV420P12; 114cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; 115cabdff1aSopenharmony_ci return 0; 116cabdff1aSopenharmony_ci } else { 117cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 118cabdff1aSopenharmony_ci } 119cabdff1aSopenharmony_ci case AOM_IMG_FMT_I422: 120cabdff1aSopenharmony_ci case AOM_IMG_FMT_I42216: 121cabdff1aSopenharmony_ci if (img->bit_depth == 8) { 122cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV422P; 123cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; 124cabdff1aSopenharmony_ci return 0; 125cabdff1aSopenharmony_ci } else if (img->bit_depth == 10) { 126cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV422P10; 127cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; 128cabdff1aSopenharmony_ci return 0; 129cabdff1aSopenharmony_ci } else if (img->bit_depth == 12) { 130cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV422P12; 131cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; 132cabdff1aSopenharmony_ci return 0; 133cabdff1aSopenharmony_ci } else { 134cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 135cabdff1aSopenharmony_ci } 136cabdff1aSopenharmony_ci case AOM_IMG_FMT_I444: 137cabdff1aSopenharmony_ci case AOM_IMG_FMT_I44416: 138cabdff1aSopenharmony_ci if (img->bit_depth == 8) { 139cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV444P; 140cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_HIGH; 141cabdff1aSopenharmony_ci return 0; 142cabdff1aSopenharmony_ci } else if (img->bit_depth == 10) { 143cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV444P10; 144cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_HIGH; 145cabdff1aSopenharmony_ci return 0; 146cabdff1aSopenharmony_ci } else if (img->bit_depth == 12) { 147cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV444P12; 148cabdff1aSopenharmony_ci avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; 149cabdff1aSopenharmony_ci return 0; 150cabdff1aSopenharmony_ci } else { 151cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 152cabdff1aSopenharmony_ci } 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_ci default: 155cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 156cabdff1aSopenharmony_ci } 157cabdff1aSopenharmony_ci} 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_cistatic int aom_decode(AVCodecContext *avctx, AVFrame *picture, 160cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 161cabdff1aSopenharmony_ci{ 162cabdff1aSopenharmony_ci AV1DecodeContext *ctx = avctx->priv_data; 163cabdff1aSopenharmony_ci const void *iter = NULL; 164cabdff1aSopenharmony_ci struct aom_image *img; 165cabdff1aSopenharmony_ci int ret; 166cabdff1aSopenharmony_ci 167cabdff1aSopenharmony_ci if (aom_codec_decode(&ctx->decoder, avpkt->data, avpkt->size, NULL) != 168cabdff1aSopenharmony_ci AOM_CODEC_OK) { 169cabdff1aSopenharmony_ci const char *error = aom_codec_error(&ctx->decoder); 170cabdff1aSopenharmony_ci const char *detail = aom_codec_error_detail(&ctx->decoder); 171cabdff1aSopenharmony_ci 172cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error); 173cabdff1aSopenharmony_ci if (detail) 174cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", 175cabdff1aSopenharmony_ci detail); 176cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 177cabdff1aSopenharmony_ci } 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ci if ((img = aom_codec_get_frame(&ctx->decoder, &iter))) { 180cabdff1aSopenharmony_ci if (img->d_w > img->w || img->d_h > img->h) { 181cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Display dimensions %dx%d exceed storage %dx%d\n", 182cabdff1aSopenharmony_ci img->d_w, img->d_h, img->w, img->h); 183cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 184cabdff1aSopenharmony_ci } 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci if ((ret = set_pix_fmt(avctx, img)) < 0) { 187cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n", 188cabdff1aSopenharmony_ci img->fmt, img->bit_depth); 189cabdff1aSopenharmony_ci return ret; 190cabdff1aSopenharmony_ci } 191cabdff1aSopenharmony_ci 192cabdff1aSopenharmony_ci if ((int)img->d_w != avctx->width || (int)img->d_h != avctx->height) { 193cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n", 194cabdff1aSopenharmony_ci avctx->width, avctx->height, img->d_w, img->d_h); 195cabdff1aSopenharmony_ci ret = ff_set_dimensions(avctx, img->d_w, img->d_h); 196cabdff1aSopenharmony_ci if (ret < 0) 197cabdff1aSopenharmony_ci return ret; 198cabdff1aSopenharmony_ci } 199cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) 200cabdff1aSopenharmony_ci return ret; 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci#ifdef AOM_CTRL_AOMD_GET_FRAME_FLAGS 203cabdff1aSopenharmony_ci { 204cabdff1aSopenharmony_ci aom_codec_frame_flags_t flags; 205cabdff1aSopenharmony_ci ret = aom_codec_control(&ctx->decoder, AOMD_GET_FRAME_FLAGS, &flags); 206cabdff1aSopenharmony_ci if (ret == AOM_CODEC_OK) { 207cabdff1aSopenharmony_ci picture->key_frame = !!(flags & AOM_FRAME_IS_KEY); 208cabdff1aSopenharmony_ci if (flags & (AOM_FRAME_IS_KEY | AOM_FRAME_IS_INTRAONLY)) 209cabdff1aSopenharmony_ci picture->pict_type = AV_PICTURE_TYPE_I; 210cabdff1aSopenharmony_ci else if (flags & AOM_FRAME_IS_SWITCH) 211cabdff1aSopenharmony_ci picture->pict_type = AV_PICTURE_TYPE_SP; 212cabdff1aSopenharmony_ci else 213cabdff1aSopenharmony_ci picture->pict_type = AV_PICTURE_TYPE_P; 214cabdff1aSopenharmony_ci } 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci#endif 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_ci av_reduce(&picture->sample_aspect_ratio.num, 219cabdff1aSopenharmony_ci &picture->sample_aspect_ratio.den, 220cabdff1aSopenharmony_ci picture->height * img->r_w, 221cabdff1aSopenharmony_ci picture->width * img->r_h, 222cabdff1aSopenharmony_ci INT_MAX); 223cabdff1aSopenharmony_ci ff_set_sar(avctx, picture->sample_aspect_ratio); 224cabdff1aSopenharmony_ci 225cabdff1aSopenharmony_ci if ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) && img->bit_depth == 8) 226cabdff1aSopenharmony_ci image_copy_16_to_8(picture, img); 227cabdff1aSopenharmony_ci else { 228cabdff1aSopenharmony_ci const uint8_t *planes[4] = { img->planes[0], img->planes[1], img->planes[2] }; 229cabdff1aSopenharmony_ci const int stride[4] = { img->stride[0], img->stride[1], img->stride[2] }; 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci av_image_copy(picture->data, picture->linesize, planes, 232cabdff1aSopenharmony_ci stride, avctx->pix_fmt, img->d_w, img->d_h); 233cabdff1aSopenharmony_ci } 234cabdff1aSopenharmony_ci *got_frame = 1; 235cabdff1aSopenharmony_ci } 236cabdff1aSopenharmony_ci return avpkt->size; 237cabdff1aSopenharmony_ci} 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_cistatic av_cold int aom_free(AVCodecContext *avctx) 240cabdff1aSopenharmony_ci{ 241cabdff1aSopenharmony_ci AV1DecodeContext *ctx = avctx->priv_data; 242cabdff1aSopenharmony_ci aom_codec_destroy(&ctx->decoder); 243cabdff1aSopenharmony_ci return 0; 244cabdff1aSopenharmony_ci} 245cabdff1aSopenharmony_ci 246cabdff1aSopenharmony_cistatic av_cold int av1_init(AVCodecContext *avctx) 247cabdff1aSopenharmony_ci{ 248cabdff1aSopenharmony_ci return aom_init(avctx, aom_codec_av1_dx()); 249cabdff1aSopenharmony_ci} 250cabdff1aSopenharmony_ci 251cabdff1aSopenharmony_ciconst FFCodec ff_libaom_av1_decoder = { 252cabdff1aSopenharmony_ci .p.name = "libaom-av1", 253cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("libaom AV1"), 254cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 255cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_AV1, 256cabdff1aSopenharmony_ci .priv_data_size = sizeof(AV1DecodeContext), 257cabdff1aSopenharmony_ci .init = av1_init, 258cabdff1aSopenharmony_ci .close = aom_free, 259cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(aom_decode), 260cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, 261cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_AUTO_THREADS, 262cabdff1aSopenharmony_ci .p.profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles), 263cabdff1aSopenharmony_ci .p.wrapper_name = "libaom", 264cabdff1aSopenharmony_ci}; 265