Skip to content

Commit

Permalink
Add custom sample rate support to aac payloader and depayloader
Browse files Browse the repository at this point in the history
  • Loading branch information
Noarkhh committed Aug 22, 2023
1 parent b4a2924 commit 6808b4a
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 19 deletions.
4 changes: 3 additions & 1 deletion examples/muxer_isom.exs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ defmodule Example do
})
|> child(:audio_parser, %Membrane.AAC.Parser{out_encapsulation: :none})
|> child(:audio_payloader, Membrane.MP4.Payloader.AAC),
child(:muxer, Membrane.MP4.Muxer.ISOM)
child(:muxer, %Membrane.MP4.Muxer.ISOM{
fast_start: true
})
|> child(:sink, %Membrane.File.Sink{location: @output_file}),
get_child(:audio_payloader) |> get_child(:muxer),
get_child(:video_payloader) |> get_child(:muxer)
Expand Down
9 changes: 7 additions & 2 deletions lib/membrane_mp4/depayloader/aac.ex
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,13 @@ defmodule Membrane.MP4.Depayloader.AAC do
depends_on_core_coder = 0
extension_flag = 0

<<aot_id::5, _frequency_id::4, _channel_config_id::4, frame_length_id::1,
^depends_on_core_coder::1, ^extension_flag::1>> = section_5
<<aot_id::5, frequency_id::4, section_5_rest::bitstring>> = section_5

custom_frequency_length = if frequency_id == 15, do: 24, else: 0

<<_maybe_custom_frequency::integer-size(custom_frequency_length), _channel_config_id::4,
frame_length_id::1, ^depends_on_core_coder::1, ^extension_flag::1>> = section_5_rest


%{
profile: AAC.aot_id_to_profile(aot_id),
Expand Down
37 changes: 21 additions & 16 deletions lib/membrane_mp4/payloader/aac.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,25 @@ defmodule Membrane.MP4.Payloader.AAC do
"""
use Membrane.Filter

def_input_pad :input,
def_input_pad(:input,
demand_unit: :buffers,
accepted_format: %Membrane.AAC{encapsulation: :none}

def_output_pad :output, accepted_format: Membrane.MP4.Payload

def_options avg_bit_rate: [
spec: non_neg_integer(),
default: 0,
description: "Average stream bitrate. Should be set to 0 if unknown."
],
max_bit_rate: [
spec: non_neg_integer(),
default: 0,
description: "Maximal stream bitrate. Should be set to 0 if unknown."
]
)

def_output_pad(:output, accepted_format: Membrane.MP4.Payload)

def_options(
avg_bit_rate: [
spec: non_neg_integer(),
default: 0,
description: "Average stream bitrate. Should be set to 0 if unknown."
],
max_bit_rate: [
spec: non_neg_integer(),
default: 0,
description: "Maximal stream bitrate. Should be set to 0 if unknown."
]
)

@impl true
def handle_stream_format(:input, stream_format, _ctx, state) do
Expand Down Expand Up @@ -59,9 +62,11 @@ defmodule Membrane.MP4.Payloader.AAC do
depends_on_core_coder = 0
extension_flag = 0

custom_frequency = if frequency_id == 15, do: <<stream_format.sample_rate::24>>, else: <<>>

section5 =
<<aot_id::5, frequency_id::4, channel_config_id::4, frame_length_id::1,
depends_on_core_coder::1, extension_flag::1>>
<<aot_id::5, frequency_id::4, custom_frequency::binary, channel_config_id::4,
frame_length_id::1, depends_on_core_coder::1, extension_flag::1>>
|> make_esds_section(5)

# 64 = mpeg4-audio
Expand Down
Binary file not shown.
52 changes: 52 additions & 0 deletions test/membrane_mp4/transmuxing_transpayloading_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
defmodule Membrane.MP4.TransmuxingTranspayloadingTest do
@moduledoc false

use ExUnit.Case, async: true

import Membrane.ChildrenSpec
import Membrane.Testing.Assertions

require Membrane.Pad

alias Membrane.MP4.Container
alias Membrane.Pad

alias Membrane.Testing.Pipeline

@tag :tmp_dir
test "an AAC track with custom sample rate after demuxing, depayloading, payloading and muxing is identical to the original one",
%{tmp_dir: dir} do
in_path = "test/fixtures/isom/ref_aac_fast_start_sr_20000.mp4"
out_path = Path.join(dir, "ref_aac_fast_start_sr_20000.mp4")

structure = [
child(:file, %Membrane.File.Source{location: in_path})
|> child(:demuxer, Membrane.MP4.Demuxer.ISOM)
|> via_out(Pad.ref(:output, 1))
|> child(:depayloader, Membrane.MP4.Depayloader.AAC)
|> child(:payloader, Membrane.MP4.Payloader.AAC)
|> child(:muxer, %Membrane.MP4.Muxer.ISOM{
chunk_duration: Membrane.Time.seconds(1),
fast_start: true
})
|> child(:sink, %Membrane.File.Sink{location: out_path})
]

pipeline = Pipeline.start_link_supervised!(structure: structure)

assert_end_of_stream(pipeline, :sink, :input, 6000)
refute_sink_buffer(pipeline, :sink, _buffer, 0)

assert :ok == Pipeline.terminate(pipeline)

{in_mp4, <<>>} = File.read!(in_path) |> Container.parse!()
{out_mp4, <<>>} = File.read!(out_path) |> Container.parse!()

assert out_mp4[:moov].children[:mvhd] == in_mp4[:moov].children[:mvhd]

assert out_mp4[:moov].children[:trak].children[:thkd] ==
in_mp4[:moov].children[:trak].children[:thkd]

assert out_mp4[:mdat] == in_mp4[:mdat]
end
end

0 comments on commit 6808b4a

Please sign in to comment.