1 /*****************************************************************************
2 * av1.c: AV1 video packetizer
3 *****************************************************************************
4 * Copyright (C) 2018 VideoLabs, VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 /*****************************************************************************
23 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_codec.h>
32 #include <vlc_block.h>
35 #include <vlc_block_helper.h>
40 //#define DEBUG_AV1_PACKETIZER
42 /****************************************************************************
44 ****************************************************************************/
50 block_t
**pp_chain_last
;
53 block_t
*p_sequence_header_block
;
54 av1_OBU_sequence_header_t
*p_sequence_header
;
57 bool b_has_visible_frame
;
61 block_t
**pp_chain_last
;
67 int i_next_block_flags
;
71 #define BLOCK_FLAG_DROP (1 << BLOCK_FLAG_PRIVATE_SHIFT)
73 /****************************************************************************
75 ****************************************************************************/
76 static inline void InitQueue(block_t
**pp_head
, block_t
***ppp_tail
)
82 static bool block_Differs(const block_t
*a
, const block_t
*b
)
84 return (a
->i_buffer
!= b
->i_buffer
||
85 memcmp(a
->p_buffer
, b
->p_buffer
, a
->i_buffer
));
88 #define INITQ(name) InitQueue(&p_sys->name.p_chain, &p_sys->name.pp_chain_last)
89 #define PUSHQ(name,b) \
91 block_ChainLastAppend(&p_sys->name.pp_chain_last, b);\
92 if(p_sys->tu.dts == VLC_TICK_INVALID)\
93 p_sys->tu.dts = b->i_dts; p_sys->tu.pts = b->i_pts;\
96 static void UpdateDecoderFormat(decoder_t
*p_dec
)
98 av1_sys_t
*p_sys
= p_dec
->p_sys
;
99 if(!p_sys
->p_sequence_header
)
102 if(p_dec
->fmt_in
.i_profile
< AV1_PROFILE_MAIN
)
105 AV1_get_profile_level(p_sys
->p_sequence_header
, &val
[0], &val
[1], &val
[2]);
106 if(p_dec
->fmt_out
.i_profile
!= val
[0] || p_dec
->fmt_out
.i_level
!= val
[1])
108 p_dec
->fmt_out
.i_profile
= val
[0];
109 p_dec
->fmt_out
.i_level
= val
[1];
114 AV1_get_frame_max_dimensions(p_sys
->p_sequence_header
, &wnum
, &hden
);
115 if((!p_dec
->fmt_in
.video
.i_visible_height
||
116 !p_dec
->fmt_in
.video
.i_visible_width
) &&
117 (p_dec
->fmt_out
.video
.i_visible_width
!= wnum
||
118 p_dec
->fmt_out
.video
.i_visible_width
!= hden
))
120 p_dec
->fmt_out
.video
.i_width
=
121 p_dec
->fmt_out
.video
.i_visible_width
= wnum
;
122 p_dec
->fmt_out
.video
.i_height
=
123 p_dec
->fmt_out
.video
.i_visible_height
= hden
;
126 if((!p_dec
->fmt_in
.video
.i_frame_rate
||
127 !p_dec
->fmt_in
.video
.i_frame_rate_base
) &&
128 AV1_get_frame_rate(p_sys
->p_sequence_header
, &wnum
, &hden
) &&
129 (p_dec
->fmt_out
.video
.i_frame_rate
!= wnum
||
130 p_dec
->fmt_out
.video
.i_frame_rate_base
!= hden
))
132 p_dec
->fmt_out
.video
.i_frame_rate
= wnum
;
133 p_dec
->fmt_out
.video
.i_frame_rate_base
= hden
;
136 video_color_primaries_t prim
;
137 video_color_space_t space
;
138 video_transfer_func_t xfer
;
139 video_color_range_t full
;
140 if(p_dec
->fmt_in
.video
.primaries
== COLOR_PRIMARIES_UNDEF
&&
141 AV1_get_colorimetry(p_sys
->p_sequence_header
, &prim
, &xfer
, &space
, &full
) &&
142 prim
!= COLOR_PRIMARIES_UNDEF
&&
143 (p_dec
->fmt_out
.video
.primaries
!= prim
||
144 p_dec
->fmt_out
.video
.transfer
!= xfer
||
145 p_dec
->fmt_out
.video
.space
!= space
))
147 p_dec
->fmt_out
.video
.primaries
= prim
;
148 p_dec
->fmt_out
.video
.transfer
= xfer
;
149 p_dec
->fmt_out
.video
.space
= space
;
150 p_dec
->fmt_out
.video
.color_range
= full
;
153 if(!p_dec
->fmt_in
.i_extra
&& !p_dec
->fmt_out
.i_extra
)
155 p_dec
->fmt_out
.i_extra
=
156 AV1_create_DecoderConfigurationRecord((uint8_t **)&p_dec
->fmt_out
.p_extra
,
157 p_sys
->p_sequence_header
,
159 (const uint8_t **)&p_sys
->p_sequence_header_block
->p_buffer
,
160 &p_sys
->p_sequence_header_block
->i_buffer
);
164 static block_t
* OutputQueues(decoder_t
*p_dec
, bool b_valid
)
166 av1_sys_t
*p_sys
= p_dec
->p_sys
;
167 block_t
*p_output
= NULL
;
168 block_t
**pp_output_last
= &p_output
;
169 uint32_t i_flags
= 0; /* Because block_ChainGather does not merge flags or times */
171 if(p_sys
->tu
.pre
.p_chain
)
173 block_ChainLastAppend(&pp_output_last
, p_sys
->tu
.pre
.p_chain
);
177 if(p_sys
->tu
.frame
.p_chain
)
179 i_flags
|= p_sys
->tu
.frame
.p_chain
->i_flags
;
180 block_ChainLastAppend(&pp_output_last
, p_sys
->tu
.frame
.p_chain
);
184 if(p_sys
->tu
.post
.p_chain
)
186 block_ChainLastAppend(&pp_output_last
, p_sys
->tu
.post
.p_chain
);
192 p_output
->i_dts
= p_sys
->tu
.dts
;
193 p_output
->i_pts
= p_sys
->tu
.pts
;
194 p_output
->i_flags
|= i_flags
;
196 p_output
->i_flags
|= BLOCK_FLAG_DROP
;
199 p_output
->i_flags
|= p_sys
->i_next_block_flags
;
200 p_sys
->i_next_block_flags
= 0;
204 p_sys
->tu
.b_has_visible_frame
= false;
205 p_sys
->tu
.dts
= VLC_TICK_INVALID
;
206 p_sys
->tu
.pts
= VLC_TICK_INVALID
;
212 /****************************************************************************
214 ****************************************************************************/
215 static block_t
*GatherAndValidateChain(decoder_t
*p_dec
, block_t
*p_outputchain
)
217 block_t
*p_output
= NULL
;
218 av1_sys_t
*p_sys
= p_dec
->p_sys
;
223 #ifdef DEBUG_AV1_PACKETIZER
224 msg_Dbg(p_dec
, "TU output %ld", p_outputchain
->i_dts
);
225 for(block_t
*p
= p_outputchain
; p
; p
=p
->p_next
)
227 enum av1_obu_type_e OBUtype
= AV1_OBUGetType(p
->p_buffer
);
228 if(OBUtype
== AV1_OBU_FRAME
|| OBUtype
== AV1_OBU_FRAME_HEADER
)
230 av1_OBU_frame_header_t
*p_fh
= NULL
;
231 if(AV1_OBUIsBaseLayer(p
->p_buffer
, p
->i_buffer
) && p_sys
->p_sequence_header
)
233 p_fh
= AV1_OBU_parse_frame_header(p
->p_buffer
, p
->i_buffer
,
234 p_sys
->p_sequence_header
);
237 msg_Dbg(p_dec
,"OBU TYPE %d sz %ld dts %ld type %d %d",
238 OBUtype
, p
->i_buffer
, p
->i_dts
,
239 AV1_get_frame_type(p_fh
),
240 AV1_get_frame_visibility(p_fh
));
242 AV1_release_frame_header(p_fh
);
245 else msg_Dbg(p_dec
, "OBU TYPE %d sz %ld dts %ld", OBUtype
, p
->i_buffer
, p
->i_dts
);
248 if(p_outputchain
->i_flags
& BLOCK_FLAG_DROP
)
249 p_output
= p_outputchain
; /* Avoid useless gather */
251 p_output
= block_ChainGather(p_outputchain
);
254 if(p_output
&& (p_output
->i_flags
& BLOCK_FLAG_DROP
))
256 block_ChainRelease(p_output
); /* Chain! see above */
263 static block_t
*ParseOBUBlock(decoder_t
*p_dec
, block_t
*p_obu
)
265 av1_sys_t
*p_sys
= p_dec
->p_sys
;
267 block_t
* p_output
= NULL
;
268 enum av1_obu_type_e OBUtype
= AV1_OBUGetType(p_obu
->p_buffer
);
269 const bool b_base_layer
= AV1_OBUIsBaseLayer(p_obu
->p_buffer
, p_obu
->i_buffer
);
273 case AV1_OBU_SEQUENCE_HEADER
:
275 if(p_sys
->tu
.frame
.p_chain
|| p_sys
->tu
.post
.p_chain
)
276 p_output
= OutputQueues(p_dec
, p_sys
->p_sequence_header
!= NULL
);
280 /* Save a copy for Extradata */
281 if(!p_sys
->p_sequence_header_block
||
282 block_Differs(p_sys
->p_sequence_header_block
, p_obu
))
284 if(p_sys
->p_sequence_header_block
)
285 block_Release(p_sys
->p_sequence_header_block
);
286 p_sys
->p_sequence_header_block
= block_Duplicate(p_obu
);
289 if(p_sys
->p_sequence_header
)
290 AV1_release_sequence_header(p_sys
->p_sequence_header
);
291 p_sys
->p_sequence_header
= AV1_OBU_parse_sequence_header(p_obu
->p_buffer
, p_obu
->i_buffer
);
293 PUSHQ(tu
.pre
, p_obu
);
296 case AV1_OBU_TEMPORAL_DELIMITER
:
298 p_output
= OutputQueues(p_dec
, p_sys
->p_sequence_header_block
!= NULL
);
299 PUSHQ(tu
.pre
, p_obu
);
303 case AV1_OBU_FRAME_HEADER
:
307 av1_OBU_frame_header_t
*p_fh
= NULL
;
308 if(p_sys
->p_sequence_header
)
310 p_fh
= AV1_OBU_parse_frame_header(p_obu
->p_buffer
, p_obu
->i_buffer
,
311 p_sys
->p_sequence_header
);
314 if((p_sys
->i_seen
& AV1_OBU_TEMPORAL_DELIMITER
) && p_sys
->tu
.b_has_visible_frame
)
315 p_output
= OutputQueues(p_dec
, p_sys
->p_sequence_header
!= NULL
);
317 switch(AV1_get_frame_type(p_fh
))
319 case AV1_FRAME_TYPE_KEY
:
320 case AV1_FRAME_TYPE_INTRA_ONLY
:
321 p_obu
->i_flags
|= BLOCK_FLAG_TYPE_I
;
323 case AV1_FRAME_TYPE_INTER
:
324 p_obu
->i_flags
|= BLOCK_FLAG_TYPE_P
;
330 p_sys
->tu
.b_has_visible_frame
|= AV1_get_frame_visibility(p_fh
);
331 AV1_release_frame_header(p_fh
);
333 else msg_Warn(p_dec
, "could not parse frame header");
337 if(!p_output
&& p_sys
->tu
.post
.p_chain
)
338 p_output
= OutputQueues(p_dec
, p_sys
->p_sequence_header
!= NULL
);
340 PUSHQ(tu
.frame
, p_obu
);
343 case AV1_OBU_METADATA
:
345 if(p_sys
->tu
.frame
.p_chain
|| p_sys
->tu
.post
.p_chain
)
346 p_output
= OutputQueues(p_dec
, p_sys
->p_sequence_header
!= NULL
);
347 PUSHQ(tu
.pre
, p_obu
);
350 case AV1_OBU_TILE_GROUP
:
351 case AV1_OBU_TILE_LIST
:
352 if(p_sys
->tu
.post
.p_chain
)
353 p_output
= OutputQueues(p_dec
, p_sys
->p_sequence_header
!= NULL
);
354 PUSHQ(tu
.frame
, p_obu
);
357 case AV1_OBU_REDUNDANT_FRAME_HEADER
:
358 case AV1_OBU_PADDING
:
360 block_Release(p_obu
);
365 p_sys
->i_seen
|= 1 << OBUtype
;
370 /****************************************************************************
372 ****************************************************************************/
373 static void PacketizeFlush(decoder_t
*p_dec
)
375 av1_sys_t
*p_sys
= p_dec
->p_sys
;
377 block_ChainRelease(OutputQueues(p_dec
, false));
379 if(p_sys
->p_sequence_header
)
381 AV1_release_sequence_header(p_sys
->p_sequence_header
);
382 p_sys
->p_sequence_header
= NULL
;
384 if(p_sys
->p_sequence_header_block
)
386 block_Release(p_sys
->p_sequence_header_block
);
387 p_sys
->p_sequence_header_block
= NULL
;
390 block_ChainRelease(p_sys
->obus
.p_chain
);
393 p_sys
->tu
.dts
= VLC_TICK_INVALID
;
394 p_sys
->tu
.pts
= VLC_TICK_INVALID
;
395 p_sys
->tu
.b_has_visible_frame
= false;
397 p_sys
->i_next_block_flags
= BLOCK_FLAG_DISCONTINUITY
;
400 /****************************************************************************
402 ****************************************************************************/
403 static block_t
*PacketizeOBU(decoder_t
*p_dec
, block_t
**pp_block
)
405 av1_sys_t
*p_sys
= p_dec
->p_sys
;
407 block_t
*p_block
= pp_block
? *pp_block
: NULL
;
410 if( p_block
->i_flags
& (BLOCK_FLAG_DISCONTINUITY
| BLOCK_FLAG_CORRUPTED
) )
412 /* First always drain complete blocks before discontinuity */
413 block_t
*p_drain
= PacketizeOBU( p_dec
, NULL
);
417 PacketizeFlush( p_dec
);
419 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
421 block_Release( p_block
);
426 if(!AV1_OBUIsValid(p_block
->p_buffer
, p_block
->i_buffer
))
428 msg_Warn(p_dec
,"fed with invalid OBU");
429 block_Release(p_block
);
433 block_ChainLastAppend(&p_sys
->obus
.pp_chain_last
, p_block
);
436 block_t
*p_output
= NULL
;
437 while(p_sys
->obus
.p_chain
)
439 block_t
*p_frag
= p_sys
->obus
.p_chain
;
441 AV1_OBU_iterator_ctx_t it
;
442 AV1_OBU_iterator_init(&it
, p_frag
->p_buffer
, p_frag
->i_buffer
);
443 const uint8_t *p_obu
; size_t i_obu
;
445 if(!AV1_OBU_iterate_next(&it
, &p_obu
, &i_obu
))
447 msg_Warn(p_dec
,"Invalid OBU header in sequence, discarding");
448 /* frag is not OBU, drop */
449 p_sys
->obus
.p_chain
= p_frag
->p_next
;
450 if(p_frag
->p_next
== NULL
)
451 p_sys
->obus
.pp_chain_last
= &p_sys
->obus
.p_chain
;
453 p_frag
->p_next
= NULL
;
454 block_Release(p_frag
);
459 if(i_obu
== p_frag
->i_buffer
)
461 p_sys
->obus
.p_chain
= p_frag
->p_next
;
462 if(p_frag
->p_next
== NULL
)
463 p_sys
->obus
.pp_chain_last
= &p_sys
->obus
.p_chain
;
465 p_frag
->p_next
= NULL
;
470 p_obublock
= block_Alloc(i_obu
);
471 memcpy(p_obublock
->p_buffer
, p_frag
->p_buffer
, i_obu
);
472 p_frag
->i_buffer
-= i_obu
;
473 p_frag
->p_buffer
+= i_obu
;
474 p_obublock
->i_dts
= p_frag
->i_dts
;
475 p_obublock
->i_pts
= p_frag
->i_pts
;
476 p_obublock
->i_flags
= p_frag
->i_flags
;
478 p_frag
->i_dts
= VLC_TICK_INVALID
;
479 p_frag
->i_pts
= VLC_TICK_INVALID
;
482 p_output
= ParseOBUBlock(p_dec
, p_obublock
);
488 if(!p_output
&& pp_block
== NULL
)
489 p_output
= OutputQueues(p_dec
, p_sys
->p_sequence_header_block
!= NULL
);
493 p_output
= GatherAndValidateChain(p_dec
, p_output
);
494 UpdateDecoderFormat(p_dec
);
500 /*****************************************************************************
502 *****************************************************************************/
503 static void Close(vlc_object_t
*p_this
)
505 decoder_t
*p_dec
= (decoder_t
*)p_this
;
506 av1_sys_t
*p_sys
= p_dec
->p_sys
;
508 PacketizeFlush(p_dec
);
513 /*****************************************************************************
515 *****************************************************************************/
516 static int Open(vlc_object_t
*p_this
)
518 decoder_t
*p_dec
= (decoder_t
*)p_this
;
521 if (p_dec
->fmt_in
.i_codec
!= VLC_CODEC_AV1
)
524 p_dec
->p_sys
= p_sys
= calloc(1, sizeof(av1_sys_t
));
529 p_sys
->p_sequence_header_block
= NULL
;
530 p_sys
->p_sequence_header
= NULL
;
531 p_sys
->tu
.b_has_visible_frame
= false;
532 p_sys
->tu
.dts
= VLC_TICK_INVALID
;
533 p_sys
->tu
.pts
= VLC_TICK_INVALID
;
535 p_sys
->i_next_block_flags
= 0;
540 /* Copy properties */
541 es_format_Copy(&p_dec
->fmt_out
, &p_dec
->fmt_in
);
542 p_dec
->fmt_out
.b_packetized
= true;
544 p_dec
->pf_packetize
= PacketizeOBU
;
545 p_dec
->pf_flush
= PacketizeFlush
;
550 /*****************************************************************************
552 *****************************************************************************/
555 set_category(CAT_SOUT
)
556 set_subcategory(SUBCAT_SOUT_PACKETIZER
)
557 set_description(N_("AV1 video packetizer"))
558 set_capability("packetizer", 50)
559 set_callbacks(Open
, Close
)