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