1 /*****************************************************************************
2 * aom.c: libaom decoder (AV1) module
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
6 * Authors: Tristan Matthews <tmatth@videolan.org>
7 * Based on vpx.c by: Rafaël Carré <funman@videolan.org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
35 #include <aom/aom_decoder.h>
36 #include <aom/aomdx.h>
39 # include <aom/aomcx.h>
40 # include <aom/aom_image.h>
43 /****************************************************************************
45 ****************************************************************************/
46 static int OpenDecoder(vlc_object_t
*);
47 static void CloseDecoder(vlc_object_t
*);
49 static int OpenEncoder(vlc_object_t
*);
50 static void CloseEncoder(vlc_object_t
*);
51 static block_t
*Encode(encoder_t
*p_enc
, picture_t
*p_pict
);
54 /*****************************************************************************
56 *****************************************************************************/
60 set_description(N_("AOM video decoder"))
61 set_capability("video decoder", 100)
62 set_callbacks(OpenDecoder
, CloseDecoder
)
63 set_category(CAT_INPUT
)
64 set_subcategory(SUBCAT_INPUT_VCODEC
)
68 set_capability("encoder", 60)
69 set_description(N_("AOM video encoder"))
70 set_callbacks(OpenEncoder
, CloseEncoder
)
74 static void aom_err_msg(vlc_object_t
*this, aom_codec_ctx_t
*ctx
,
77 const char *error
= aom_codec_error(ctx
);
78 const char *detail
= aom_codec_error_detail(ctx
);
80 detail
= "no specific information";
81 msg_Err(this, msg
, error
, detail
);
84 #define AOM_ERR(this, ctx, msg) aom_err_msg(VLC_OBJECT(this), ctx, msg ": %s (%s)")
86 /*****************************************************************************
87 * decoder_sys_t: libaom decoder descriptor
88 *****************************************************************************/
96 vlc_fourcc_t i_chroma
;
97 enum aom_img_fmt i_chroma_id
;
103 { VLC_CODEC_I420
, AOM_IMG_FMT_I420
, 8, 0 },
104 { VLC_CODEC_I422
, AOM_IMG_FMT_I422
, 8, 0 },
105 { VLC_CODEC_I444
, AOM_IMG_FMT_I444
, 8, 0 },
106 { VLC_CODEC_I440
, AOM_IMG_FMT_I440
, 8, 0 },
108 { VLC_CODEC_YV12
, AOM_IMG_FMT_YV12
, 8, 0 },
109 { VLC_CODEC_YUVA
, AOM_IMG_FMT_444A
, 8, 0 },
110 { VLC_CODEC_YUYV
, AOM_IMG_FMT_YUY2
, 8, 0 },
111 { VLC_CODEC_UYVY
, AOM_IMG_FMT_UYVY
, 8, 0 },
112 { VLC_CODEC_YVYU
, AOM_IMG_FMT_YVYU
, 8, 0 },
114 { VLC_CODEC_RGB15
, AOM_IMG_FMT_RGB555
, 8, 0 },
115 { VLC_CODEC_RGB16
, AOM_IMG_FMT_RGB565
, 8, 0 },
116 { VLC_CODEC_RGB24
, AOM_IMG_FMT_RGB24
, 8, 0 },
117 { VLC_CODEC_RGB32
, AOM_IMG_FMT_RGB32
, 8, 0 },
119 { VLC_CODEC_ARGB
, AOM_IMG_FMT_ARGB
, 8, 0 },
120 { VLC_CODEC_BGRA
, AOM_IMG_FMT_ARGB_LE
, 8, 0 },
122 { VLC_CODEC_GBR_PLANAR
, AOM_IMG_FMT_I444
, 8, 1 },
123 { VLC_CODEC_GBR_PLANAR_10L
, AOM_IMG_FMT_I44416
, 10, 1 },
125 { VLC_CODEC_I420_10L
, AOM_IMG_FMT_I42016
, 10, 0 },
126 { VLC_CODEC_I422_10L
, AOM_IMG_FMT_I42216
, 10, 0 },
127 { VLC_CODEC_I444_10L
, AOM_IMG_FMT_I44416
, 10, 0 },
129 { VLC_CODEC_I420_12L
, AOM_IMG_FMT_I42016
, 12, 0 },
130 { VLC_CODEC_I422_12L
, AOM_IMG_FMT_I42216
, 12, 0 },
131 { VLC_CODEC_I444_12L
, AOM_IMG_FMT_I44416
, 12, 0 },
133 { VLC_CODEC_I444_16L
, AOM_IMG_FMT_I44416
, 16, 0 },
136 static vlc_fourcc_t
FindVlcChroma( struct aom_image
*img
)
138 uint8_t hack
= (img
->fmt
& AOM_IMG_FMT_I444
) && (img
->cs
== AOM_CS_SRGB
);
140 for( unsigned int i
= 0; i
< ARRAY_SIZE(chroma_table
); i
++ )
141 if( chroma_table
[i
].i_chroma_id
== img
->fmt
&&
142 chroma_table
[i
].i_bitdepth
== img
->bit_depth
&&
143 chroma_table
[i
].i_needs_hack
== hack
)
144 return chroma_table
[i
].i_chroma
;
149 /****************************************************************************
150 * Decode: the whole thing
151 ****************************************************************************/
152 static int Decode(decoder_t
*dec
, block_t
*block
)
154 aom_codec_ctx_t
*ctx
= &dec
->p_sys
->ctx
;
156 if (!block
) /* No Drain */
157 return VLCDEC_SUCCESS
;
159 if (block
->i_flags
& (BLOCK_FLAG_CORRUPTED
)) {
160 block_Release(block
);
161 return VLCDEC_SUCCESS
;
164 /* Associate packet PTS with decoded frame */
165 mtime_t
*pkt_pts
= malloc(sizeof(*pkt_pts
));
167 block_Release(block
);
168 return VLCDEC_SUCCESS
;
171 *pkt_pts
= block
->i_pts
;
174 err
= aom_codec_decode(ctx
, block
->p_buffer
, block
->i_buffer
, pkt_pts
, 0);
176 block_Release(block
);
178 if (err
!= AOM_CODEC_OK
) {
180 AOM_ERR(dec
, ctx
, "Failed to decode frame");
181 return VLCDEC_SUCCESS
;
184 const void *iter
= NULL
;
185 struct aom_image
*img
= aom_codec_get_frame(ctx
, &iter
);
188 return VLCDEC_SUCCESS
;
191 /* fetches back the PTS */
192 pkt_pts
= img
->user_priv
;
193 mtime_t pts
= *pkt_pts
;
196 dec
->fmt_out
.i_codec
= FindVlcChroma(img
);
197 if (dec
->fmt_out
.i_codec
== 0) {
198 msg_Err(dec
, "Unsupported output colorspace %d", img
->fmt
);
199 return VLCDEC_SUCCESS
;
202 video_format_t
*v
= &dec
->fmt_out
.video
;
204 if (img
->d_w
!= v
->i_visible_width
|| img
->d_h
!= v
->i_visible_height
) {
205 v
->i_visible_width
= img
->d_w
;
206 v
->i_visible_height
= img
->d_h
;
209 if( !dec
->fmt_out
.video
.i_sar_num
|| !dec
->fmt_out
.video
.i_sar_den
)
211 dec
->fmt_out
.video
.i_sar_num
= 1;
212 dec
->fmt_out
.video
.i_sar_den
= 1;
215 v
->b_color_range_full
= img
->range
== AOM_CR_FULL_RANGE
;
221 v
->space
= COLOR_SPACE_BT709
;
224 case AOM_CS_SMPTE_170
:
225 case AOM_CS_SMPTE_240
:
226 v
->space
= COLOR_SPACE_BT601
;
228 case AOM_CS_BT_2020_CL
:
229 case AOM_CS_BT_2020_NCL
:
230 v
->space
= COLOR_SPACE_BT2020
;
236 if (decoder_UpdateVideoFormat(dec
))
237 return VLCDEC_SUCCESS
;
238 picture_t
*pic
= decoder_NewPicture(dec
);
240 return VLCDEC_SUCCESS
;
242 for (int plane
= 0; plane
< pic
->i_planes
; plane
++ ) {
243 uint8_t *src
= img
->planes
[plane
];
244 uint8_t *dst
= pic
->p
[plane
].p_pixels
;
245 int src_stride
= img
->stride
[plane
];
246 int dst_stride
= pic
->p
[plane
].i_pitch
;
248 int size
= __MIN( src_stride
, dst_stride
);
249 for( int line
= 0; line
< pic
->p
[plane
].i_visible_lines
; line
++ ) {
250 memcpy( dst
, src
, size
);
256 pic
->b_progressive
= true; /* codec does not support interlacing */
259 decoder_QueueVideo(dec
, pic
);
260 return VLCDEC_SUCCESS
;
263 /*****************************************************************************
264 * OpenDecoder: probe the decoder
265 *****************************************************************************/
266 static int OpenDecoder(vlc_object_t
*p_this
)
268 decoder_t
*dec
= (decoder_t
*)p_this
;
269 const aom_codec_iface_t
*iface
;
272 if (dec
->fmt_in
.i_codec
!= VLC_CODEC_AV1
)
275 iface
= &aom_codec_av1_dx_algo
;
278 decoder_sys_t
*sys
= malloc(sizeof(*sys
));
283 struct aom_codec_dec_cfg deccfg
= {
284 .threads
= __MIN(vlc_GetCPUCount(), 16),
285 .allow_lowbitdepth
= 1
288 msg_Dbg(p_this
, "AV%d: using libaom version %s (build options %s)",
289 av_version
, aom_codec_version_str(), aom_codec_build_config());
291 if (aom_codec_dec_init(&sys
->ctx
, iface
, &deccfg
, 0) != AOM_CODEC_OK
) {
292 AOM_ERR(p_this
, &sys
->ctx
, "Failed to initialize decoder");
294 return VLC_EGENERIC
;;
297 dec
->pf_decode
= Decode
;
299 dec
->fmt_out
.video
.i_width
= dec
->fmt_in
.video
.i_width
;
300 dec
->fmt_out
.video
.i_height
= dec
->fmt_in
.video
.i_height
;
301 dec
->fmt_out
.i_codec
= VLC_CODEC_I420
;
306 /*****************************************************************************
307 * CloseDecoder: decoder destruction
308 *****************************************************************************/
309 static void CloseDecoder(vlc_object_t
*p_this
)
311 decoder_t
*dec
= (decoder_t
*)p_this
;
312 decoder_sys_t
*sys
= dec
->p_sys
;
315 const void *iter
= NULL
;
317 struct aom_image
*img
= aom_codec_get_frame(&sys
->ctx
, &iter
);
320 free(img
->user_priv
);
323 aom_codec_destroy(&sys
->ctx
);
330 /*****************************************************************************
331 * encoder_sys_t: libaom encoder descriptor
332 *****************************************************************************/
335 struct aom_codec_ctx ctx
;
338 /*****************************************************************************
339 * OpenEncoder: probe the encoder
340 *****************************************************************************/
341 static int OpenEncoder(vlc_object_t
*p_this
)
343 encoder_t
*p_enc
= (encoder_t
*)p_this
;
344 encoder_sys_t
*p_sys
;
346 if (p_enc
->fmt_out
.i_codec
!= VLC_CODEC_AV1
)
349 /* Allocate the memory needed to store the encoder's structure */
350 p_sys
= malloc(sizeof(*p_sys
));
354 p_enc
->p_sys
= p_sys
;
356 const struct aom_codec_iface
*iface
= &aom_codec_av1_cx_algo
;
358 struct aom_codec_enc_cfg enccfg
= {};
359 aom_codec_enc_config_default(iface
, &enccfg
, 0);
360 enccfg
.g_threads
= __MIN(vlc_GetCPUCount(), 4);
361 enccfg
.g_w
= p_enc
->fmt_in
.video
.i_visible_width
;
362 enccfg
.g_h
= p_enc
->fmt_in
.video
.i_visible_height
;
365 switch (p_enc
->fmt_in
.i_codec
) {
366 case VLC_CODEC_I420_10L
:
367 enc_flags
= AOM_CODEC_USE_HIGHBITDEPTH
;
368 /* Profile 1: 10-bit and 12-bit color only, with 4:2:0 sampling. */
369 enccfg
.g_profile
= 2;
370 enccfg
.g_bit_depth
= 10;
374 /* Profile 0: 8-bit 4:2:0 only. */
375 enccfg
.g_profile
= 0;
376 enccfg
.g_bit_depth
= 8;
379 msg_Err(p_this
, "Unsupported input format %s",
380 vlc_fourcc_GetDescription(VIDEO_ES
, p_enc
->fmt_in
.i_codec
));
385 msg_Dbg(p_this
, "AV1: using libaom version %s (build options %s)",
386 aom_codec_version_str(), aom_codec_build_config());
388 struct aom_codec_ctx
*ctx
= &p_sys
->ctx
;
389 if (aom_codec_enc_init(ctx
, iface
, &enccfg
, enc_flags
) != AOM_CODEC_OK
)
391 AOM_ERR(p_this
, ctx
, "Failed to initialize encoder");
396 p_enc
->pf_encode_video
= Encode
;
401 /****************************************************************************
402 * Encode: the whole thing
403 ****************************************************************************/
404 static block_t
*Encode(encoder_t
*p_enc
, picture_t
*p_pict
)
406 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
407 struct aom_codec_ctx
*ctx
= &p_sys
->ctx
;
409 if (!p_pict
) return NULL
;
411 aom_image_t img
= {};
412 unsigned i_w
= p_enc
->fmt_in
.video
.i_visible_width
;
413 unsigned i_h
= p_enc
->fmt_in
.video
.i_visible_height
;
414 const aom_img_fmt_t img_fmt
= p_enc
->fmt_in
.i_codec
== VLC_CODEC_I420_10L
?
415 AOM_IMG_FMT_I42016
: AOM_IMG_FMT_I420
;
417 /* Create and initialize the aom_image */
418 if (!aom_img_alloc(&img
, img_fmt
, i_w
, i_h
, 16))
420 AOM_ERR(p_enc
, ctx
, "Failed to allocate image");
424 for (int plane
= 0; plane
< p_pict
->i_planes
; plane
++) {
425 uint8_t *src
= p_pict
->p
[plane
].p_pixels
;
426 uint8_t *dst
= img
.planes
[plane
];
427 int src_stride
= p_pict
->p
[plane
].i_pitch
;
428 int dst_stride
= img
.stride
[plane
];
430 int size
= __MIN(src_stride
, dst_stride
);
431 for (int line
= 0; line
< p_pict
->p
[plane
].i_visible_lines
; line
++)
433 /* FIXME: do this in-place */
434 memcpy(dst
, src
, size
);
440 aom_codec_err_t res
= aom_codec_encode(ctx
, &img
, p_pict
->date
, 1, 0,
441 AOM_DL_GOOD_QUALITY
);
442 if (res
!= AOM_CODEC_OK
) {
443 AOM_ERR(p_enc
, ctx
, "Failed to encode frame");
448 const aom_codec_cx_pkt_t
*pkt
= NULL
;
449 aom_codec_iter_t iter
= NULL
;
450 block_t
*p_out
= NULL
;
451 while ((pkt
= aom_codec_get_cx_data(ctx
, &iter
)) != NULL
)
453 if (pkt
->kind
== AOM_CODEC_CX_FRAME_PKT
)
455 int keyframe
= pkt
->data
.frame
.flags
& AOM_FRAME_IS_KEY
;
456 block_t
*p_block
= block_Alloc(pkt
->data
.frame
.sz
);
457 if (unlikely(p_block
== NULL
)) {
458 block_ChainRelease(p_out
);
463 /* FIXME: do this in-place */
464 memcpy(p_block
->p_buffer
, pkt
->data
.frame
.buf
, pkt
->data
.frame
.sz
);
465 p_block
->i_dts
= p_block
->i_pts
= pkt
->data
.frame
.pts
;
467 p_block
->i_flags
|= BLOCK_FLAG_TYPE_I
;
468 block_ChainAppend(&p_out
, p_block
);
475 /*****************************************************************************
476 * CloseEncoder: encoder destruction
477 *****************************************************************************/
478 static void CloseEncoder(vlc_object_t
*p_this
)
480 encoder_t
*p_enc
= (encoder_t
*)p_this
;
481 encoder_sys_t
*p_sys
= p_enc
->p_sys
;
482 if (aom_codec_destroy(&p_sys
->ctx
))
483 AOM_ERR(p_this
, &p_sys
->ctx
, "Failed to destroy codec");
487 #endif /* ENABLE_SOUT */