@@ -3,7 +3,7 @@ defmodule Membrane.MP4.MovieBox.SampleTableBox do
33
44 require Membrane.H264
55 require Membrane.Logger
6- alias Membrane . { AAC , H264 , H265 , Opus }
6+ alias Membrane . { AAC , AV1 , H264 , H265 , Opus }
77 alias Membrane.MP4 . { Container , Helper , Track.SampleTable }
88
99 @ spec assemble ( SampleTable . t ( ) ) :: Container . t ( )
@@ -184,6 +184,79 @@ defmodule Membrane.MP4.MovieBox.SampleTableBox do
184184 ]
185185 end
186186
187+ defp assemble_sample_description ( % AV1 { width: width , height: height } = format ) do
188+ av1c_content = build_av1c ( format )
189+
190+ [
191+ { :av01 ,
192+ % {
193+ children: [
194+ av1C: % {
195+ content: av1c_content
196+ } ,
197+ pasp: % {
198+ children: [ ] ,
199+ fields: % { h_spacing: 1 , v_spacing: 1 }
200+ }
201+ ] ,
202+ fields: % {
203+ compressor_name: << 0 :: size ( 32 ) - unit ( 8 ) >> ,
204+ depth: 24 ,
205+ flags: 0 ,
206+ frame_count: 1 ,
207+ height: height || 0 ,
208+ horizresolution: { 0 , 0 } ,
209+ num_of_entries: 1 ,
210+ version: 0 ,
211+ vertresolution: { 0 , 0 } ,
212+ width: width || 0
213+ }
214+ } }
215+ ]
216+ end
217+
218+ # Build av1C (AV1CodecConfigurationRecord) per ISO/IEC 14496-15
219+ defp build_av1c ( % AV1 { } = format ) do
220+ config = av1c_config ( format )
221+
222+ <<
223+ # Byte 0: marker (1) | version (7)
224+ 1 :: 1 ,
225+ 1 :: 7 ,
226+ # Byte 1: seq_profile (3) | seq_level_idx_0 (5)
227+ config . profile :: 3 ,
228+ config . level_idx :: 5 ,
229+ # Byte 2: seq_tier_0 (1) | high_bitdepth (1) | twelve_bit (1) | monochrome (1) |
230+ # chroma_subsampling_x (1) | chroma_subsampling_y (1) | chroma_sample_position (2)
231+ config . tier :: 1 ,
232+ config . high_bitdepth :: 1 ,
233+ config . twelve_bit :: 1 ,
234+ config . monochrome :: 1 ,
235+ config . chroma_subsampling_x :: 1 ,
236+ config . chroma_subsampling_y :: 1 ,
237+ config . chroma_sample_position :: 2 ,
238+ # Byte 3: reserved (3) | initial_presentation_delay_present (1) | reserved (4)
239+ 0 :: 3 ,
240+ 0 :: 1 ,
241+ 0 :: 4
242+ >>
243+ end
244+
245+ defp av1c_config ( % AV1 { } = format ) do
246+ % {
247+ profile: AV1 . profile_to_seq_profile ( format . profile || :main ) ,
248+ level_idx: AV1 . level_to_seq_level_idx ( format . level || :"4.0" ) ,
249+ tier: AV1 . tier_to_seq_tier ( format . tier || :main ) ,
250+ # Defaults for 8-bit, 4:2:0
251+ high_bitdepth: 0 ,
252+ twelve_bit: 0 ,
253+ monochrome: 0 ,
254+ chroma_subsampling_x: 1 ,
255+ chroma_subsampling_y: 1 ,
256+ chroma_sample_position: 0
257+ }
258+ end
259+
187260 defp assemble_sample_deltas ( % { timescale: timescale , decoding_deltas: decoding_deltas } ) ,
188261 do:
189262 Enum . map ( decoding_deltas , fn % { sample_count: count , sample_delta: delta } ->
@@ -343,6 +416,20 @@ defmodule Membrane.MP4.MovieBox.SampleTableBox do
343416 % Opus { channels: boxes [ :dOps ] . fields . output_channel_count , self_delimiting?: false }
344417 end
345418
419+ defp unpack_sample_description ( % { children: [ { :av01 , % { children: boxes , fields: fields } } ] } ) do
420+ << _marker :: 1 , _version :: 7 , seq_profile :: 3 , seq_level_idx :: 5 , seq_tier :: 1 , _rest :: bitstring >> =
421+ boxes [ :av1C ] . content
422+
423+ % AV1 {
424+ alignment: :tu ,
425+ width: fields . width ,
426+ height: fields . height ,
427+ profile: AV1 . seq_profile_to_profile ( seq_profile ) ,
428+ level: AV1 . seq_level_idx_to_level ( seq_level_idx ) ,
429+ tier: AV1 . seq_tier_to_tier ( seq_tier )
430+ }
431+ end
432+
346433 defp unpack_sample_description ( % { children: [ { sample_type , _sample_metadata } ] } ) do
347434 Membrane.Logger . warning ( "Unknown sample type: #{ inspect ( sample_type ) } " )
348435 nil
0 commit comments