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
38 typedef struct AV1DecodeContext {
39 struct aom_codec_ctx decoder;
40 } AV1DecodeContext;
41
aom_init(AVCodecContext *avctx, const struct aom_codec_iface *iface)42 static 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
image_copy_16_to_8(AVFrame *pic, struct aom_image *img)63 static 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
set_pix_fmt(AVCodecContext *avctx, struct aom_image *img)88 static 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
aom_decode(AVCodecContext *avctx, AVFrame *picture, int *got_frame, AVPacket *avpkt)159 static 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
aom_free(AVCodecContext *avctx)239 static 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
av1_init(AVCodecContext *avctx)246 static av_cold int av1_init(AVCodecContext *avctx)
247 {
248 return aom_init(avctx, aom_codec_av1_dx());
249 }
250
251 const 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