Skip to content

Commit 22e7ae8

Browse files
authored
store ctts table (#115)
* store ctts table on muxing * revert add_dts_offset option * fix typo * run mix format * upgrade deps
1 parent 10d4108 commit 22e7ae8

File tree

11 files changed

+97
-23
lines changed

11 files changed

+97
-23
lines changed

lib/membrane_mp4/demuxer/isom/samples_info.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ defmodule Membrane.MP4.Demuxer.ISOM.SamplesInfo do
106106
{dts, pts} =
107107
case samples_info.last_dts[track_id] do
108108
nil ->
109-
{0, 0}
109+
{0, scalify(sample_composition_offset, timescale)}
110110

111111
last_dts ->
112112
{last_dts + scalify(delta, timescale),

lib/membrane_mp4/movie_box/sample_table_box.ex

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ defmodule Membrane.MP4.MovieBox.SampleTableBox do
3535
}
3636
}
3737
] ++
38+
maybe_sample_composition_offsets(table) ++
3839
maybe_sample_sync ++
3940
[
4041
stsc: %{
@@ -197,6 +198,33 @@ defmodule Membrane.MP4.MovieBox.SampleTableBox do
197198
%{sample_count: count, sample_delta: Helper.timescalify(delta, timescale)}
198199
end)
199200

201+
defp maybe_sample_composition_offsets(%{composition_offsets: []}), do: []
202+
203+
defp maybe_sample_composition_offsets(%{composition_offsets: [%{sample_composition_offset: 0}]}),
204+
do: []
205+
206+
defp maybe_sample_composition_offsets(%{
207+
timescale: timescale,
208+
composition_offsets: composition_offsets
209+
}) do
210+
composition_offsets
211+
|> Enum.map(fn %{sample_count: count, sample_composition_offset: offset} ->
212+
%{sample_count: count, sample_composition_offset: Helper.timescalify(offset, timescale)}
213+
end)
214+
|> then(
215+
&[
216+
ctts: %{
217+
fields: %{
218+
version: 0,
219+
flags: 0,
220+
entry_count: length(&1),
221+
entry_list: &1
222+
}
223+
}
224+
]
225+
)
226+
end
227+
200228
defp maybe_sample_sync(%{sync_samples: []}), do: []
201229

202230
defp maybe_sample_sync(%{sync_samples: sync_samples}) do

lib/membrane_mp4/track/sample_table.ex

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ defmodule Membrane.MP4.Track.SampleTable do
6363
|> maybe_store_first_dts(buffer)
6464
|> do_store_sample(buffer)
6565
|> update_decoding_deltas(buffer)
66+
|> update_composition_offsets(buffer)
6667
|> maybe_store_sync_sample(buffer)
6768
|> store_last_dts(buffer)
6869
end
@@ -100,6 +101,7 @@ defmodule Membrane.MP4.Track.SampleTable do
100101
:sync_samples,
101102
:chunk_offsets,
102103
:decoding_deltas,
104+
:composition_offsets,
103105
:samples_per_chunk
104106
]
105107

@@ -148,6 +150,23 @@ defmodule Membrane.MP4.Track.SampleTable do
148150
end)
149151
end
150152

153+
defp update_composition_offsets(sample_table, %Buffer{dts: dts, pts: pts}) do
154+
Map.update!(sample_table, :composition_offsets, fn previous_offsets ->
155+
new_offset = pts - dts
156+
157+
case previous_offsets do
158+
[] ->
159+
[%{sample_count: 1, sample_composition_offset: new_offset}]
160+
161+
[%{sample_count: count, sample_composition_offset: ^new_offset} | rest] ->
162+
[%{sample_count: count + 1, sample_composition_offset: new_offset} | rest]
163+
164+
_different_delta_or_empty ->
165+
[%{sample_count: 1, sample_composition_offset: new_offset} | previous_offsets]
166+
end
167+
end)
168+
end
169+
151170
defp maybe_store_sync_sample(sample_table, %Buffer{metadata: %{h264: h264}})
152171
when h264.key_frame? do
153172
Map.update!(sample_table, :sync_samples, &[sample_table.sample_count | &1])

mix.lock

Lines changed: 22 additions & 22 deletions
Large diffs are not rendered by default.
48 Bytes
Binary file not shown.

test/fixtures/isom/ref_two_tracks.mp4

104 Bytes
Binary file not shown.
104 Bytes
Binary file not shown.

test/fixtures/isom/ref_video.mp4

104 Bytes
Binary file not shown.
104 Bytes
Binary file not shown.

test/fixtures/isom/ref_video_hevc.mp4

144 Bytes
Binary file not shown.

test/membrane_mp4/muxer/isom/integration_test.exs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,31 @@ defmodule Membrane.MP4.Muxer.ISOM.IntegrationTest do
237237
1_000
238238
end
239239
end
240+
241+
describe "ctts table" do
242+
test "should not be stored when dts and pts values are equal" do
243+
prepare_test("video")
244+
245+
structure = [
246+
child(:file, %Membrane.File.Source{location: "test/fixtures/in_video.h264"})
247+
|> child(:parser, %Membrane.H264.Parser{
248+
generate_best_effort_timestamps: %{framerate: {30, 1}, add_dts_offset: false},
249+
output_stream_structure: :avc1
250+
})
251+
|> child(:muxer, %Membrane.MP4.Muxer.ISOM{chunk_duration: Time.seconds(1)})
252+
|> child(:sink, %Membrane.File.Sink{location: out_path_for("video")})
253+
]
254+
255+
pid = Pipeline.start_link_supervised!(spec: structure)
256+
257+
assert_end_of_stream(pid, :sink, :input)
258+
refute_sink_buffer(pid, :sink, _buffer, 0)
259+
260+
assert :ok == Pipeline.terminate(pid)
261+
262+
assert {parsed_out, <<>>} = out_path_for("video") |> File.read!() |> Container.parse!()
263+
assert Container.get_box(parsed_out, [:moov, :trak, :mdia, :minf, :stbl, :stts])
264+
refute Container.get_box(parsed_out, [:moov, :trak, :mdia, :minf, :stbl, :ctts])
265+
end
266+
end
240267
end

0 commit comments

Comments
 (0)