Skip to content

Commit db94f61

Browse files
authored
Fix skipping parameters (#44)
* Stopped skipping parameter sets when receiving non-idr nalus * Update fixture_generator
1 parent a014381 commit db94f61

26 files changed

+49
-84
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The package can be installed by adding `membrane_h264_plugin` to your list of de
2222
```elixir
2323
def deps do
2424
[
25-
{:membrane_h264_plugin, "~> 0.7.2"}
25+
{:membrane_h264_plugin, "~> 0.7.3"}
2626
]
2727
end
2828
```

lib/membrane_h264_plugin/parser.ex

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,6 @@ defmodule Membrane.H264.Parser do
287287
{nalus, nalu_parser} = NALuParser.parse_nalus(nalus_payloads, timestamps, state.nalu_parser)
288288
is_au_aligned = state.mode == :au_aligned
289289
{access_units, au_splitter} = AUSplitter.split(nalus, is_au_aligned, state.au_splitter)
290-
{access_units, state} = skip_improper_aus(access_units, state)
291290
{actions, state} = prepare_actions_for_aus(access_units, ctx, state)
292291

293292
state = %{
@@ -305,8 +304,7 @@ defmodule Membrane.H264.Parser do
305304
{last_nalu_payload, nalu_splitter} = NALuSplitter.split(<<>>, true, state.nalu_splitter)
306305
{last_nalu, nalu_parser} = NALuParser.parse_nalus(last_nalu_payload, state.nalu_parser)
307306
{maybe_improper_aus, au_splitter} = AUSplitter.split(last_nalu, true, state.au_splitter)
308-
{aus, state} = skip_improper_aus(maybe_improper_aus, state)
309-
{actions, state} = prepare_actions_for_aus(aus, ctx, state)
307+
{actions, state} = prepare_actions_for_aus(maybe_improper_aus, ctx, state)
310308

311309
actions = if stream_format_sent?(actions, ctx), do: actions, else: []
312310

@@ -395,22 +393,17 @@ defmodule Membrane.H264.Parser do
395393
{avc, nalu_length_size}
396394
end
397395

398-
defp skip_improper_aus(aus, state) do
399-
Enum.flat_map_reduce(aus, state, fn au, state ->
400-
has_seen_keyframe? =
401-
Enum.all?(au, &(&1.status == :valid)) and Enum.any?(au, &(&1.type == :idr))
396+
@spec skip_au?(AUSplitter.access_unit(), state()) :: {boolean(), state()}
397+
defp skip_au?(au, state) do
398+
has_seen_keyframe? =
399+
Enum.all?(au, &(&1.status == :valid)) and Enum.any?(au, &(&1.type == :idr))
402400

403-
state = %{
404-
state
405-
| skip_until_keyframe: state.skip_until_keyframe and not has_seen_keyframe?
406-
}
401+
state = %{
402+
state
403+
| skip_until_keyframe: state.skip_until_keyframe and not has_seen_keyframe?
404+
}
407405

408-
if Enum.any?(au, &(&1.status == :error)) or state.skip_until_keyframe do
409-
{[], state}
410-
else
411-
{[au], state}
412-
end
413-
end)
406+
{Enum.any?(au, &(&1.status == :error)) or state.skip_until_keyframe, state}
414407
end
415408

416409
@spec prepare_actions_for_aus(
@@ -424,11 +417,17 @@ defmodule Membrane.H264.Parser do
424417

425418
{{pts, dts}, state} = prepare_timestamps(au, state)
426419

427-
buffers_actions = [
428-
buffer:
429-
{:output,
430-
wrap_into_buffer(au, pts, dts, state.output_alignment, state.output_stream_structure)}
431-
]
420+
{should_skip_au, state} = skip_au?(au, state)
421+
422+
buffers_actions =
423+
if should_skip_au do
424+
[]
425+
else
426+
buffers =
427+
wrap_into_buffer(au, pts, dts, state.output_alignment, state.output_stream_structure)
428+
429+
[buffer: {:output, buffers}]
430+
end
432431

433432
{stream_format_actions ++ buffers_actions, state}
434433
end)
@@ -559,19 +558,14 @@ defmodule Membrane.H264.Parser do
559558
Membrane.Time.t(),
560559
:au | :nalu,
561560
stream_structure()
562-
) :: Buffer.t()
561+
) :: Buffer.t() | [Buffer.t()]
563562
defp wrap_into_buffer(access_unit, pts, dts, :au, output_stream_structure) do
564-
metadata = prepare_au_metadata(access_unit)
565-
566-
buffer =
567-
Enum.reduce(access_unit, <<>>, fn nalu, acc ->
568-
acc <> NALuParser.get_prefixed_nalu_payload(nalu, output_stream_structure)
569-
end)
570-
|> then(fn payload ->
571-
%Buffer{payload: payload, metadata: metadata, pts: pts, dts: dts}
572-
end)
573-
574-
buffer
563+
Enum.reduce(access_unit, <<>>, fn nalu, acc ->
564+
acc <> NALuParser.get_prefixed_nalu_payload(nalu, output_stream_structure)
565+
end)
566+
|> then(fn payload ->
567+
%Buffer{payload: payload, metadata: prepare_au_metadata(access_unit), pts: pts, dts: dts}
568+
end)
575569
end
576570

577571
defp wrap_into_buffer(access_unit, pts, dts, :nalu, output_stream_structure) do

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule Membrane.H264.Plugin.Mixfile do
22
use Mix.Project
33

4-
@version "0.7.2"
4+
@version "0.7.3"
55
@github_url "https://github.com/membraneframework-labs/membrane_h264_plugin"
66

77
def project do

mix.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
"coerce": {:hex, :coerce, "1.0.1", "211c27386315dc2894ac11bc1f413a0e38505d808153367bd5c6e75a4003d096", [:mix], [], "hexpm", "b44a691700f7a1a15b4b7e2ff1fa30bebd669929ac8aa43cffe9e2f8bf051cf1"},
55
"credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"},
66
"dialyxir": {:hex, :dialyxir, "1.4.1", "a22ed1e7bd3a3e3f197b68d806ef66acb61ee8f57b3ac85fc5d57354c5482a93", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "84b795d6d7796297cca5a3118444b80c7d94f7ce247d49886e7c291e1ae49801"},
7-
"earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"},
7+
"earmark_parser": {:hex, :earmark_parser, "1.4.35", "437773ca9384edf69830e26e9e7b2e0d22d2596c4a6b17094a3b29f01ea65bb8", [:mix], [], "hexpm", "8652ba3cb85608d0d7aa2d21b45c6fad4ddc9a1f9a1f1b30ca3a246f0acc33f6"},
88
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
99
"ex_doc": {:hex, :ex_doc, "0.30.6", "5f8b54854b240a2b55c9734c4b1d0dd7bdd41f71a095d42a70445c03cf05a281", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "bd48f2ddacf4e482c727f9293d9498e0881597eae6ddc3d9562bd7923375109f"},
1010
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
1111
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
1212
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
1313
"makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
1414
"makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"},
15-
"membrane_core": {:hex, :membrane_core, "0.12.8", "59fdd10a1c1c6757302748d029fba4936257e53c93ac49fddd094962c08180f9", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:qex, "~> 0.3", [hex: :qex, repo: "hexpm", optional: false]}, {:ratio, "~> 2.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d48ab1adc13d5820182b016cc397692ed5568d4064b5765c343b4d64c7f119e7"},
15+
"membrane_core": {:hex, :membrane_core, "0.12.9", "b80239deacf98f24cfd2e0703b632e92ddded8b989227cd6e724140f433b0aac", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:qex, "~> 0.3", [hex: :qex, repo: "hexpm", optional: false]}, {:ratio, "~> 2.0", [hex: :ratio, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "389b4b22da0e35d5b053ec2fa87bf36882e0ab88f8fb841af895982fb4abe504"},
1616
"membrane_file_plugin": {:hex, :membrane_file_plugin, "0.14.0", "87f19f5f5afbfbaf2219b8f1d8496534cb9ad01fca74687910bf3f7aa866e244", [:mix], [{:membrane_core, "~> 0.12.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "28956f8d5d87735d499c57f1c24f62aeab71e0211863759e7e695ead966eb433"},
17-
"membrane_h264_format": {:hex, :membrane_h264_format, "0.6.0", "8f3b920c3c7d73c24dce1e39b636b660645e43ab5d3e5913ac022cfad6c7b6b8", [:mix], [], "hexpm", "d3cc012bec8c70d4a5483429da75c4c1fc9b079d8816721763bb98d9fcb44fd6"},
17+
"membrane_h264_format": {:hex, :membrane_h264_format, "0.6.1", "44836cd9de0abe989b146df1e114507787efc0cf0da2368f17a10c47b4e0738c", [:mix], [], "hexpm", "4b79be56465a876d2eac2c3af99e115374bbdc03eb1dea4f696ee9a8033cd4b0"},
1818
"membrane_stream_plugin": {:hex, :membrane_stream_plugin, "0.3.1", "265f327dad815a8ef18f8872bdebc6c1aa1fea3d059446c937b76ff067c166e6", [:mix], [{:membrane_core, "~> 0.12.0", [hex: :membrane_core, repo: "hexpm", optional: false]}], "hexpm", "b504296b9f5a78b43c0d46ad66202a1f0f93d4c122949c27ad4c04f67f3c5907"},
1919
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
2020
"numbers": {:hex, :numbers, "5.2.4", "f123d5bb7f6acc366f8f445e10a32bd403c8469bdbce8ce049e1f0972b607080", [:mix], [{:coerce, "~> 1.0", [hex: :coerce, repo: "hexpm", optional: false]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "eeccf5c61d5f4922198395bf87a465b6f980b8b862dd22d28198c5e6fab38582"},

test/fixtures/ms/ref_video-avc1-au.ms

-67.5 KB
Binary file not shown.
-67 KB
Binary file not shown.

test/fixtures/ms/ref_video-avc3-au.ms

-67.5 KB
Binary file not shown.
-67 KB
Binary file not shown.
-67.5 KB
Binary file not shown.
Binary file not shown.
-67.5 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
65.4 KB
Binary file not shown.
64.3 KB
Binary file not shown.
65.4 KB
Binary file not shown.
64.3 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

test/parser/stream_structure_conversion_test.exs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ defmodule Membrane.H264.StreamStructureConversionTest do
1515
|> Path.wildcard()
1616
|> Enum.reject(&String.contains?(&1, ["no-sps", "no-pps", "sps-pps-non-idr"]))
1717

18-
@avc1_au_fixtures "../fixtures/ms/*-avc1-au.ms" |> Path.expand(__DIR__) |> Path.wildcard()
19-
@avc1_nalu_fixtures "../fixtures/ms/*-avc1-nalu.ms" |> Path.expand(__DIR__) |> Path.wildcard()
20-
@avc3_au_fixtures "../fixtures/ms/*-avc3-au.ms" |> Path.expand(__DIR__) |> Path.wildcard()
21-
@avc3_nalu_fixtures "../fixtures/ms/*-avc3-nalu.ms" |> Path.expand(__DIR__) |> Path.wildcard()
18+
@avc1_au_fixtures "../fixtures/msr/*-avc1-au.msr" |> Path.expand(__DIR__) |> Path.wildcard()
19+
@avc1_nalu_fixtures "../fixtures/msr/*-avc1-nalu.msr" |> Path.expand(__DIR__) |> Path.wildcard()
20+
@avc3_au_fixtures "../fixtures/msr/*-avc3-au.msr" |> Path.expand(__DIR__) |> Path.wildcard()
21+
@avc3_nalu_fixtures "../fixtures/msr/*-avc3-nalu.msr" |> Path.expand(__DIR__) |> Path.wildcard()
2222

2323
defp make_annexb_pipeline(alignment, parsers) do
2424
parser_chain = make_parser_chain(parsers)

test/support/fixture_generator.exs

Lines changed: 12 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,20 @@
11
Mix.install([
2-
{:membrane_file_plugin, "~> 0.14.0"},
3-
{:membrane_hackney_plugin, "~> 0.10.0"},
4-
{:membrane_mp4_plugin, "~> 0.25.0"},
5-
{:membrane_mp4_format, ">= 0.0.0"},
6-
{:membrane_stream_plugin, "~> 0.3.1"},
7-
{:membrane_aac_plugin, ">= 0.0.0"},
8-
{:membrane_h264_format,
9-
github: "membraneframework/membrane_h264_format", ref: "ea5a3d2", override: true},
10-
{:membrane_h264_plugin,
11-
github: "membraneframework/membrane_h264_plugin",
12-
branch: "stream-type-conversion",
13-
override: true}
2+
{:membrane_file_plugin, "~> 0.15.0"},
3+
{:membrane_mp4_plugin, "~> 0.29.0"},
4+
{:membrane_stream_plugin, "~> 0.3.1"}
145
])
156

167
alias Membrane.H264.Parser.{NALuSplitter, DecoderConfigurationRecord}
178

18-
defmodule Membrane.H264.RemoteStream do
19-
@moduledoc false
20-
21-
defstruct []
22-
end
23-
24-
defmodule MP4ToH264Filter do
9+
defmodule Aligner do
2510
@moduledoc false
2611

2712
use Membrane.Filter
2813

2914
def_input_pad :input,
3015
demand_unit: :buffers,
3116
demand_mode: :auto,
32-
accepted_format: Membrane.MP4.Payload
17+
accepted_format: Membrane.H264
3318

3419
def_output_pad :output,
3520
demand_mode: :auto,
@@ -43,23 +28,10 @@ defmodule MP4ToH264Filter do
4328
spec: {:avc1 | :avc3, pos_integer()}
4429
]
4530

46-
@impl true
47-
def handle_init(_ctx, opts) do
48-
{[],
49-
%{
50-
output_alignment: opts.output_alignment,
51-
output_stream_structure: opts.output_stream_structure
52-
}}
53-
end
54-
5531
@impl true
5632
def handle_stream_format(
5733
:input,
58-
%Membrane.MP4.Payload{
59-
width: width,
60-
height: height,
61-
content: %Membrane.MP4.Payload.AVC1{avcc: dcr}
62-
},
34+
%Membrane.H264{stream_structure: {:avc1, dcr}} = stream_format,
6335
_ctx,
6436
%{output_stream_structure: {avc, nalu_length_size}} = state
6537
) do
@@ -73,10 +45,9 @@ defmodule MP4ToH264Filter do
7345
stream_format:
7446
{:output,
7547
%Membrane.H264{
76-
width: width,
77-
height: height,
78-
alignment: state.output_alignment,
79-
stream_structure: {avc, dcr}
48+
stream_format
49+
| alignment: state.output_alignment,
50+
stream_structure: {avc, dcr}
8051
}}
8152
], state}
8253
end
@@ -117,7 +88,7 @@ defmodule FixtureGeneratorPipeline do
11788
child(:video_source, %Membrane.File.Source{location: options.input_location})
11889
|> child(:demuxer, Membrane.MP4.Demuxer.ISOM)
11990
|> via_out(Pad.ref(:output, 1))
120-
|> child(:filter, %MP4ToH264Filter{
91+
|> child(:filter, %Aligner{
12192
output_alignment: options.output_alignment,
12293
output_stream_structure: options.stream_structure
12394
})
@@ -172,10 +143,10 @@ defmodule AVCFixtureGenerator do
172143
output_location =
173144
input_location
174145
|> Path.split()
175-
|> List.replace_at(-2, "ms")
146+
|> List.replace_at(-2, "msr")
176147
|> List.update_at(-1, fn file ->
177148
[name, "mp4"] = String.split(file, ".")
178-
"#{name}-#{avc}-#{output_alignment}.ms"
149+
"#{name}-#{avc}-#{output_alignment}.msr"
179150
end)
180151
|> Path.join()
181152

0 commit comments

Comments
 (0)