1 /*****************************************************************************
2 * aom.c: libaom decoder (AV1) module
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
5 *
6 * Authors: Tristan Matthews <tmatth@videolan.org>
7 * Based on vpx.c by: Rafaël Carré <funman@videolan.org>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
34
35 #include <aom/aom_decoder.h>
36 #include <aom/aomdx.h>
37
38 #include "../packetizer/iso_color_tables.h"
39
40 /****************************************************************************
41 * Local prototypes
42 ****************************************************************************/
43 static int OpenDecoder(vlc_object_t *);
44 static void CloseDecoder(vlc_object_t *);
45
46 /*****************************************************************************
47 * Module descriptor
48 *****************************************************************************/
49
50 vlc_module_begin ()
51 set_shortname("aom")
52 set_description(N_("AOM video decoder"))
53 set_capability("video decoder", 100)
set_callbacks(OpenDecoder,CloseDecoder)54 set_callbacks(OpenDecoder, CloseDecoder)
55 set_category(CAT_INPUT)
56 set_subcategory(SUBCAT_INPUT_VCODEC)
57 vlc_module_end ()
58
59 static void aom_err_msg(vlc_object_t *this, aom_codec_ctx_t *ctx,
60 const char *msg)
61 {
62 const char *error = aom_codec_error(ctx);
63 const char *detail = aom_codec_error_detail(ctx);
64 if (!detail)
65 detail = "no specific information";
66 msg_Err(this, msg, error, detail);
67 }
68
69 #define AOM_ERR(this, ctx, msg) aom_err_msg(VLC_OBJECT(this), ctx, msg ": %s (%s)")
70 #define AOM_MAX_FRAMES_DEPTH 64
71
72 /*****************************************************************************
73 * decoder_sys_t: libaom decoder descriptor
74 *****************************************************************************/
75 struct frame_priv_s
76 {
77 mtime_t pts;
78 };
79
80 struct decoder_sys_t
81 {
82 aom_codec_ctx_t ctx;
83 struct frame_priv_s frame_priv[AOM_MAX_FRAMES_DEPTH];
84 unsigned i_next_frame_priv;
85 };
86
87 static const struct
88 {
89 vlc_fourcc_t i_chroma;
90 enum aom_img_fmt i_chroma_id;
91 uint8_t i_bitdepth;
92 uint8_t i_needs_hack;
93
94 } chroma_table[] =
95 {
96 { VLC_CODEC_I420, AOM_IMG_FMT_I420, 8, 0 },
97 { VLC_CODEC_I422, AOM_IMG_FMT_I422, 8, 0 },
98 { VLC_CODEC_I444, AOM_IMG_FMT_I444, 8, 0 },
99
100 { VLC_CODEC_YV12, AOM_IMG_FMT_YV12, 8, 0 },
101
102 { VLC_CODEC_GBR_PLANAR, AOM_IMG_FMT_I444, 8, 1 },
103 { VLC_CODEC_GBR_PLANAR_10L, AOM_IMG_FMT_I44416, 10, 1 },
104
105 { VLC_CODEC_I420_10L, AOM_IMG_FMT_I42016, 10, 0 },
106 { VLC_CODEC_I422_10L, AOM_IMG_FMT_I42216, 10, 0 },
107 { VLC_CODEC_I444_10L, AOM_IMG_FMT_I44416, 10, 0 },
108
109 { VLC_CODEC_I420_12L, AOM_IMG_FMT_I42016, 12, 0 },
110 { VLC_CODEC_I422_12L, AOM_IMG_FMT_I42216, 12, 0 },
111 { VLC_CODEC_I444_12L, AOM_IMG_FMT_I44416, 12, 0 },
112
113 { VLC_CODEC_I444_16L, AOM_IMG_FMT_I44416, 16, 0 },
114 };
115
FindVlcChroma(struct aom_image * img)116 static vlc_fourcc_t FindVlcChroma( struct aom_image *img )
117 {
118 uint8_t hack = (img->fmt & AOM_IMG_FMT_I444) && (img->tc == AOM_CICP_TC_SRGB);
119
120 for( unsigned int i = 0; i < ARRAY_SIZE(chroma_table); i++ )
121 if( chroma_table[i].i_chroma_id == img->fmt &&
122 chroma_table[i].i_bitdepth == img->bit_depth &&
123 chroma_table[i].i_needs_hack == hack )
124 return chroma_table[i].i_chroma;
125
126 return 0;
127 }
128
CopyPicture(const struct aom_image * img,picture_t * pic)129 static void CopyPicture(const struct aom_image *img, picture_t *pic)
130 {
131 for (int plane = 0; plane < pic->i_planes; plane++ ) {
132 plane_t src_plane = pic->p[plane];
133 src_plane.p_pixels = img->planes[plane];
134 src_plane.i_pitch = img->stride[plane];
135 plane_CopyPixels(&pic->p[plane], &src_plane);
136 }
137 }
138
PushFrame(decoder_t * dec,block_t * block)139 static int PushFrame(decoder_t *dec, block_t *block)
140 {
141 decoder_sys_t *p_sys = dec->p_sys;
142 aom_codec_ctx_t *ctx = &p_sys->ctx;
143 const uint8_t *p_buffer;
144 size_t i_buffer;
145
146 /* Associate packet PTS with decoded frame */
147 uintptr_t priv_index = p_sys->i_next_frame_priv++ % AOM_MAX_FRAMES_DEPTH;
148
149 if(likely(block))
150 {
151 p_buffer = block->p_buffer;
152 i_buffer = block->i_buffer;
153 p_sys->frame_priv[priv_index].pts = (block->i_pts != VLC_TS_INVALID) ? block->i_pts : block->i_dts;
154 }
155 else
156 {
157 p_buffer = NULL;
158 i_buffer = 0;
159 }
160
161 aom_codec_err_t err;
162 err = aom_codec_decode(ctx, p_buffer, i_buffer, (void*)priv_index);
163
164 if(block)
165 block_Release(block);
166
167 if (err != AOM_CODEC_OK) {
168 AOM_ERR(dec, ctx, "Failed to decode frame");
169 if (err == AOM_CODEC_UNSUP_BITSTREAM)
170 return VLCDEC_ECRITICAL;
171 }
172 return VLCDEC_SUCCESS;
173 }
174
OutputFrame(decoder_t * dec,const struct aom_image * img)175 static void OutputFrame(decoder_t *dec, const struct aom_image *img)
176 {
177 video_format_t *v = &dec->fmt_out.video;
178
179 if (img->d_w != v->i_visible_width || img->d_h != v->i_visible_height)
180 {
181 v->i_visible_width = dec->fmt_out.video.i_width = img->d_w;
182 v->i_visible_height = dec->fmt_out.video.i_height = img->d_h;
183 }
184
185 if( !dec->fmt_out.video.i_sar_num || !dec->fmt_out.video.i_sar_den )
186 {
187 dec->fmt_out.video.i_sar_num = 1;
188 dec->fmt_out.video.i_sar_den = 1;
189 }
190
191 if(dec->fmt_in.video.primaries == COLOR_PRIMARIES_UNDEF)
192 {
193 v->primaries = iso_23001_8_cp_to_vlc_primaries(img->cp);
194 v->transfer = iso_23001_8_tc_to_vlc_xfer(img->tc);
195 v->space = iso_23001_8_mc_to_vlc_coeffs(img->mc);
196 v->b_color_range_full = img->range == AOM_CR_FULL_RANGE;
197 }
198
199 dec->fmt_out.video.projection_mode = dec->fmt_in.video.projection_mode;
200 dec->fmt_out.video.multiview_mode = dec->fmt_in.video.multiview_mode;
201 dec->fmt_out.video.pose = dec->fmt_in.video.pose;
202
203 if (decoder_UpdateVideoFormat(dec) == VLC_SUCCESS)
204 {
205 picture_t *pic = decoder_NewPicture(dec);
206 if (pic)
207 {
208 decoder_sys_t *p_sys = dec->p_sys;
209 CopyPicture(img, pic);
210
211
212 pic->b_progressive = true; /* codec does not support interlacing */
213 pic->date = p_sys->frame_priv[(uintptr_t)img->user_priv].pts;
214
215 decoder_QueueVideo(dec, pic);
216 }
217 }
218 }
219
PopFrames(decoder_t * dec,void (* pf_output)(decoder_t *,const struct aom_image *))220 static int PopFrames(decoder_t *dec,
221 void(*pf_output)(decoder_t *, const struct aom_image *))
222 {
223 decoder_sys_t *p_sys = dec->p_sys;
224 aom_codec_ctx_t *ctx = &p_sys->ctx;
225
226 for(const void *iter = NULL;; )
227 {
228 struct aom_image *img = aom_codec_get_frame(ctx, &iter);
229 if (!img)
230 break;
231
232 dec->fmt_out.i_codec = FindVlcChroma(img);
233 if (dec->fmt_out.i_codec == 0) {
234 msg_Err(dec, "Unsupported output colorspace %d", img->fmt);
235 continue;
236 }
237
238 pf_output(dec, img);
239 }
240
241 return VLCDEC_SUCCESS;
242 }
243
244 /****************************************************************************
245 * Flush: clears decoder between seeks
246 ****************************************************************************/
DropFrame(decoder_t * dec,const struct aom_image * img)247 static void DropFrame(decoder_t *dec, const struct aom_image *img)
248 {
249 VLC_UNUSED(dec);
250 VLC_UNUSED(img);
251 /* do nothing for now */
252 }
253
FlushDecoder(decoder_t * dec)254 static void FlushDecoder(decoder_t *dec)
255 {
256 decoder_sys_t *p_sys = dec->p_sys;
257 aom_codec_ctx_t *ctx = &p_sys->ctx;
258
259 if(PushFrame(dec, NULL) != VLCDEC_SUCCESS)
260 AOM_ERR(dec, ctx, "Failed to flush decoder");
261 else
262 PopFrames(dec, DropFrame);
263 }
264
265 /****************************************************************************
266 * Decode: the whole thing
267 ****************************************************************************/
Decode(decoder_t * dec,block_t * block)268 static int Decode(decoder_t *dec, block_t *block)
269 {
270 if (block && block->i_flags & (BLOCK_FLAG_CORRUPTED))
271 {
272 block_Release(block);
273 return VLCDEC_SUCCESS;
274 }
275
276 int i_ret = PushFrame(dec, block);
277
278 PopFrames(dec, OutputFrame);
279
280 return i_ret;
281 }
282
283 /*****************************************************************************
284 * OpenDecoder: probe the decoder
285 *****************************************************************************/
OpenDecoder(vlc_object_t * p_this)286 static int OpenDecoder(vlc_object_t *p_this)
287 {
288 decoder_t *dec = (decoder_t *)p_this;
289 const aom_codec_iface_t *iface;
290 int av_version;
291
292 if (dec->fmt_in.i_codec != VLC_CODEC_AV1)
293 return VLC_EGENERIC;
294
295 iface = &aom_codec_av1_dx_algo;
296 av_version = 1;
297
298 decoder_sys_t *sys = malloc(sizeof(*sys));
299 if (!sys)
300 return VLC_ENOMEM;
301 dec->p_sys = sys;
302
303 sys->i_next_frame_priv = 0;
304
305 struct aom_codec_dec_cfg deccfg = {
306 .threads = __MIN(vlc_GetCPUCount(), 16),
307 .allow_lowbitdepth = 1
308 };
309
310 msg_Dbg(p_this, "AV%d: using libaom version %s (build options %s)",
311 av_version, aom_codec_version_str(), aom_codec_build_config());
312
313 if (aom_codec_dec_init(&sys->ctx, iface, &deccfg, 0) != AOM_CODEC_OK) {
314 AOM_ERR(p_this, &sys->ctx, "Failed to initialize decoder");
315 free(sys);
316 return VLC_EGENERIC;;
317 }
318
319 dec->pf_decode = Decode;
320 dec->pf_flush = FlushDecoder;
321
322 dec->fmt_out.video.i_width = dec->fmt_in.video.i_width;
323 dec->fmt_out.video.i_height = dec->fmt_in.video.i_height;
324 dec->fmt_out.i_codec = VLC_CODEC_I420;
325
326 if (dec->fmt_in.video.i_sar_num > 0 && dec->fmt_in.video.i_sar_den > 0) {
327 dec->fmt_out.video.i_sar_num = dec->fmt_in.video.i_sar_num;
328 dec->fmt_out.video.i_sar_den = dec->fmt_in.video.i_sar_den;
329 }
330 dec->fmt_out.video.primaries = dec->fmt_in.video.primaries;
331 dec->fmt_out.video.transfer = dec->fmt_in.video.transfer;
332 dec->fmt_out.video.space = dec->fmt_in.video.space;
333 dec->fmt_out.video.b_color_range_full = dec->fmt_in.video.b_color_range_full;
334
335 return VLC_SUCCESS;
336 }
337
338 /*****************************************************************************
339 * CloseDecoder: decoder destruction
340 *****************************************************************************/
CloseDecoder(vlc_object_t * p_this)341 static void CloseDecoder(vlc_object_t *p_this)
342 {
343 decoder_t *dec = (decoder_t *)p_this;
344 decoder_sys_t *sys = dec->p_sys;
345
346 /* Flush decoder */
347 FlushDecoder(dec);
348
349 aom_codec_destroy(&sys->ctx);
350
351 free(sys);
352 }
353