Skip to content

Commit

Permalink
refactor passing ts generation config
Browse files Browse the repository at this point in the history
  • Loading branch information
mat-hek committed Aug 16, 2023
1 parent c4d069b commit a91eaf1
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 17 deletions.
9 changes: 6 additions & 3 deletions lib/membrane_h264_plugin/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,17 @@ defmodule Membrane.H264.Parser do
def handle_init(_ctx, opts) do
{sps, opts} = Map.pop!(opts, :sps)
{pps, opts} = Map.pop!(opts, :pps)
{ts_generation_config, opts} = Map.pop!(opts, :generate_best_effort_timestamps)

au_timestamp_generator =
if ts_generation_config, do: AUTimestampGenerator.new(ts_generation_config), else: nil

state =
%{
nalu_splitter: NALuSplitter.new(maybe_add_prefix(sps) <> maybe_add_prefix(pps)),
nalu_parser: NALuParser.new(),
au_splitter: AUSplitter.new(),
au_timestamp_generator: AUTimestampGenerator.new(),
au_timestamp_generator: au_timestamp_generator,
mode: nil,
profile: nil,
previous_buffer_timestamps: nil,
Expand Down Expand Up @@ -301,11 +305,10 @@ defmodule Membrane.H264.Parser do
end

defp prepare_timestamps(au, state) do
if state.mode == :bytestream and state.generate_best_effort_timestamps do
if state.mode == :bytestream and state.au_timestamp_generator do
{timestamps, timestamp_generator} =
AUTimestampGenerator.generate_ts_with_constant_framerate(
au,
state.generate_best_effort_timestamps,
state.au_timestamp_generator
)

Expand Down
37 changes: 24 additions & 13 deletions lib/membrane_h264_plugin/parser/au_timestamp_generator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,49 @@ defmodule Membrane.H264.Parser.AUTimestampGenerator do

alias Membrane.H264.Parser.NALu

@type framerate :: {frames :: pos_integer(), seconds :: pos_integer()}

@type t :: %{
framerate: framerate,
max_frame_reorder: 0..15,
au_counter: non_neg_integer(),
key_frame_au_idx: non_neg_integer(),
prev_pic_first_vcl_nalu: NALu.t() | nil,
prev_pic_order_cnt_msb: integer()
}

@spec new() :: t
def new() do
@spec new(config :: %{:framerate => framerate, optional(:add_dts_offset) => boolean()}) :: t
def new(config) do
# To make sure that PTS >= DTS at all times, we take maximal possible frame
# reorder (which is 15) and subtract `max_frame_reorder * frame_duration`
# from each frame's DTS.
# This behaviour can be disabled by setting `add_dts_offset: false`.
max_frame_reorder = if Map.get(config, :add_dts_offset, true), do: 15, else: 0

%{
framerate: config.framerate,
max_frame_reorder: max_frame_reorder,
au_counter: 0,
key_frame_au_idx: 0,
prev_pic_first_vcl_nalu: nil,
prev_pic_order_cnt_msb: 0
}
end

@spec generate_ts_with_constant_framerate(
[NALu.t()],
config :: %{
:framerate => {frames :: pos_integer(), seconds :: pos_integer()},
optional(:add_dts_offset) => boolean()
},
t
) :: {{pts :: non_neg_integer(), dts :: non_neg_integer()}, t}
def generate_ts_with_constant_framerate(au, %{framerate: {frames, seconds}} = config, state) do
%{au_counter: au_counter, key_frame_au_idx: key_frame_au_idx} = state
@spec generate_ts_with_constant_framerate([NALu.t()], t) ::
{{pts :: non_neg_integer(), dts :: non_neg_integer()}, t}
def generate_ts_with_constant_framerate(au, state) do
%{
au_counter: au_counter,
key_frame_au_idx: key_frame_au_idx,
max_frame_reorder: max_frame_reorder,
framerate: {frames, seconds}
} = state

first_vcl_nalu = Enum.find(au, &NALuTypes.is_vcl_nalu_type(&1.type))
{poc, state} = calculate_poc(first_vcl_nalu, state)
key_frame_au_idx = if poc == 0, do: au_counter, else: key_frame_au_idx
pts = div((key_frame_au_idx + poc) * seconds * Membrane.Time.second(), frames)
max_frame_reorder = if Map.get(config, :add_dts_offset, true), do: 15, else: 0
dts = div((au_counter - max_frame_reorder) * seconds * Membrane.Time.second(), frames)

state = %{
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ defmodule Membrane.H264.Plugin.Mixfile do
{:dialyxir, ">= 0.0.0", only: :dev, runtime: false},
{:credo, ">= 0.0.0", only: :dev, runtime: false},
{:membrane_file_plugin, "~> 0.13.0", only: :test},
{:membrane_h264_ffmpeg_plugin, only: :test}
{:membrane_h264_ffmpeg_plugin, "~> 0.27.0", only: :test}
]
end

Expand Down

0 comments on commit a91eaf1

Please sign in to comment.