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