Skip to content

Commit

Permalink
store ctts table (#115)
Browse files Browse the repository at this point in the history
* store ctts table on muxing

* revert add_dts_offset option

* fix typo

* run mix format

* upgrade deps
  • Loading branch information
gBillal authored Jul 29, 2024
1 parent 10d4108 commit 22e7ae8
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 23 deletions.
2 changes: 1 addition & 1 deletion lib/membrane_mp4/demuxer/isom/samples_info.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ defmodule Membrane.MP4.Demuxer.ISOM.SamplesInfo do
{dts, pts} =
case samples_info.last_dts[track_id] do
nil ->
{0, 0}
{0, scalify(sample_composition_offset, timescale)}

last_dts ->
{last_dts + scalify(delta, timescale),
Expand Down
28 changes: 28 additions & 0 deletions lib/membrane_mp4/movie_box/sample_table_box.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ defmodule Membrane.MP4.MovieBox.SampleTableBox do
}
}
] ++
maybe_sample_composition_offsets(table) ++
maybe_sample_sync ++
[
stsc: %{
Expand Down Expand Up @@ -197,6 +198,33 @@ defmodule Membrane.MP4.MovieBox.SampleTableBox do
%{sample_count: count, sample_delta: Helper.timescalify(delta, timescale)}
end)

defp maybe_sample_composition_offsets(%{composition_offsets: []}), do: []

defp maybe_sample_composition_offsets(%{composition_offsets: [%{sample_composition_offset: 0}]}),
do: []

defp maybe_sample_composition_offsets(%{
timescale: timescale,
composition_offsets: composition_offsets
}) do
composition_offsets
|> Enum.map(fn %{sample_count: count, sample_composition_offset: offset} ->
%{sample_count: count, sample_composition_offset: Helper.timescalify(offset, timescale)}
end)
|> then(
&[
ctts: %{
fields: %{
version: 0,
flags: 0,
entry_count: length(&1),
entry_list: &1
}
}
]
)
end

defp maybe_sample_sync(%{sync_samples: []}), do: []

defp maybe_sample_sync(%{sync_samples: sync_samples}) do
Expand Down
19 changes: 19 additions & 0 deletions lib/membrane_mp4/track/sample_table.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ defmodule Membrane.MP4.Track.SampleTable do
|> maybe_store_first_dts(buffer)
|> do_store_sample(buffer)
|> update_decoding_deltas(buffer)
|> update_composition_offsets(buffer)
|> maybe_store_sync_sample(buffer)
|> store_last_dts(buffer)
end
Expand Down Expand Up @@ -100,6 +101,7 @@ defmodule Membrane.MP4.Track.SampleTable do
:sync_samples,
:chunk_offsets,
:decoding_deltas,
:composition_offsets,
:samples_per_chunk
]

Expand Down Expand Up @@ -148,6 +150,23 @@ defmodule Membrane.MP4.Track.SampleTable do
end)
end

defp update_composition_offsets(sample_table, %Buffer{dts: dts, pts: pts}) do
Map.update!(sample_table, :composition_offsets, fn previous_offsets ->
new_offset = pts - dts

case previous_offsets do
[] ->
[%{sample_count: 1, sample_composition_offset: new_offset}]

[%{sample_count: count, sample_composition_offset: ^new_offset} | rest] ->
[%{sample_count: count + 1, sample_composition_offset: new_offset} | rest]

_different_delta_or_empty ->
[%{sample_count: 1, sample_composition_offset: new_offset} | previous_offsets]
end
end)
end

defp maybe_store_sync_sample(sample_table, %Buffer{metadata: %{h264: h264}})
when h264.key_frame? do
Map.update!(sample_table, :sync_samples, &[sample_table.sample_count | &1])
Expand Down
44 changes: 22 additions & 22 deletions mix.lock

Large diffs are not rendered by default.

Binary file modified test/fixtures/demuxed_and_depayloaded_video.ms
Binary file not shown.
Binary file modified test/fixtures/isom/ref_two_tracks.mp4
Binary file not shown.
Binary file modified test/fixtures/isom/ref_two_tracks_fast_start.mp4
Binary file not shown.
Binary file modified test/fixtures/isom/ref_video.mp4
Binary file not shown.
Binary file modified test/fixtures/isom/ref_video_fast_start.mp4
Binary file not shown.
Binary file modified test/fixtures/isom/ref_video_hevc.mp4
Binary file not shown.
27 changes: 27 additions & 0 deletions test/membrane_mp4/muxer/isom/integration_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,31 @@ defmodule Membrane.MP4.Muxer.ISOM.IntegrationTest do
1_000
end
end

describe "ctts table" do
test "should not be stored when dts and pts values are equal" do
prepare_test("video")

structure = [
child(:file, %Membrane.File.Source{location: "test/fixtures/in_video.h264"})
|> child(:parser, %Membrane.H264.Parser{
generate_best_effort_timestamps: %{framerate: {30, 1}, add_dts_offset: false},
output_stream_structure: :avc1
})
|> child(:muxer, %Membrane.MP4.Muxer.ISOM{chunk_duration: Time.seconds(1)})
|> child(:sink, %Membrane.File.Sink{location: out_path_for("video")})
]

pid = Pipeline.start_link_supervised!(spec: structure)

assert_end_of_stream(pid, :sink, :input)
refute_sink_buffer(pid, :sink, _buffer, 0)

assert :ok == Pipeline.terminate(pid)

assert {parsed_out, <<>>} = out_path_for("video") |> File.read!() |> Container.parse!()
assert Container.get_box(parsed_out, [:moov, :trak, :mdia, :minf, :stbl, :stts])
refute Container.get_box(parsed_out, [:moov, :trak, :mdia, :minf, :stbl, :ctts])
end
end
end

0 comments on commit 22e7ae8

Please sign in to comment.