Skip to content

Commit

Permalink
fix conversion from annexb to elementary stream (#509)
Browse files Browse the repository at this point in the history
* fix conversion from annexb to elementray stream

* update version
  • Loading branch information
gBillal authored Nov 23, 2024
1 parent de9826d commit 7d34bec
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 18 deletions.
2 changes: 1 addition & 1 deletion rtsp/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule ExNvrRtsp.MixProject do
def project do
[
app: :ex_nvr_rtsp,
version: "0.16.1",
version: "0.16.2",
elixir: "~> 1.15",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
Expand Down
4 changes: 2 additions & 2 deletions ui/assets/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ui/assets/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ex_nvr",
"version": "0.16.1",
"version": "0.16.2",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion ui/lib/ex_nvr/pipeline/output/storage.ex
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ defmodule ExNVR.Pipeline.Output.Storage do
dts: ExMP4.Helper.timescalify(Buffer.get_dts_or_pts(last_buffer), :nanosecond, timescale),
pts: ExMP4.Helper.timescalify(last_buffer.pts, :nanosecond, timescale),
sync?: Utils.keyframe(last_buffer),
payload: convert_annexb_to_elementary_stream(last_buffer),
payload: convert_annexb_to_elementary_stream(last_buffer, state.track.media),
duration: ExMP4.Helper.timescalify(duration, :nanosecond, timescale)
})

Expand Down
29 changes: 18 additions & 11 deletions ui/lib/ex_nvr/pipeline/output/storage/media_utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ defmodule ExNVR.Pipeline.Output.Storage.MediaUtils do
"""
@spec get_priv_data(Buffer.t()) :: ExMP4.Box.t()
def get_priv_data(buffer) do
codec = if Map.has_key?(buffer.metadata, :h264), do: :h264, else: :h265

{vpss, spss, ppss} =
:binary.split(buffer.payload, @nalu_prefixes, [:global])
|> Enum.reject(&(&1 == ""))
|> Enum.zip(get_nalu_types(buffer.metadata))
|> Enum.reject(&(&1 == "" or not pss?(codec, &1)))
|> Enum.map(&{&1, pss_type(codec, &1)})
|> Enum.reduce({[], [], []}, fn
{data, :vps}, {vpss, spss, ppss} -> {[data | vpss], spss, ppss}
{data, :sps}, {vpss, spss, ppss} -> {vpss, [data | spss], ppss}
Expand All @@ -25,23 +27,28 @@ defmodule ExNVR.Pipeline.Output.Storage.MediaUtils do
{Enum.reverse(vpss), Enum.reverse(spss), Enum.reverse(ppss)}
end)

if Map.has_key?(buffer.metadata, :h264),
if codec == :h264,
do: ExMP4.Box.Avcc.new(spss, ppss),
else: get_hevc_dcr(vpss, spss, ppss)
end

@spec convert_annexb_to_elementary_stream(Buffer.t()) :: binary()
def convert_annexb_to_elementary_stream(buffer) do
@spec convert_annexb_to_elementary_stream(Buffer.t(), :h264 | :h265) :: binary()
def convert_annexb_to_elementary_stream(buffer, codec) do
:binary.split(buffer.payload, @nalu_prefixes, [:global])
|> Stream.reject(&(&1 == ""))
|> Stream.zip(get_nalu_types(buffer.metadata))
|> Stream.reject(fn {_data, type} -> type in [:vps, :sps, :pps] end)
|> Stream.map(fn {data, _type} -> <<byte_size(data)::32, data::binary>> end)
|> Stream.reject(&(&1 == "" or pss?(codec, &1)))
|> Stream.map(&<<byte_size(&1)::32, &1::binary>>)
|> Enum.join()
end

defp get_nalu_types(%{h264: %{nalus: nalus}}), do: nalus
defp get_nalu_types(%{h265: %{nalus: nalus}}), do: nalus
defp pss?(:h264, <<_prefix::3, type::5, _rest::binary>>) when type == 7 or type == 8, do: true
defp pss?(:h265, <<0::1, type::6, _rest::bitstring>>) when type in 32..34, do: true
defp pss?(_codec, _nalu), do: false

defp pss_type(:h264, <<_prefix::3, 7::5, _rest::binary>>), do: :sps
defp pss_type(:h264, <<_prefix::3, 8::5, _rest::binary>>), do: :pps
defp pss_type(:h265, <<0::1, 32::6, _rest::bitstring>>), do: :vps
defp pss_type(:h265, <<0::1, 33::6, _rest::bitstring>>), do: :sps
defp pss_type(:h265, <<0::1, 34::6, _rest::bitstring>>), do: :pps

defp get_hevc_dcr(vpss, spss, ppss) do
{sps, _nalu_parser} = NALuParser.parse(<<0, 0, 1, List.last(spss)::binary>>, NALuParser.new())
Expand Down
2 changes: 1 addition & 1 deletion ui/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule ExNVR.MixProject do
use Mix.Project

@app :ex_nvr
@version "0.16.1"
@version "0.16.2"

def project do
[
Expand Down
2 changes: 1 addition & 1 deletion ui/priv/static/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ openapi: 3.0.0
info:
title: ExNVR API
description: Manage ExNVR via API endpoints
version: 0.16.1
version: 0.16.2
servers:
- url: '{protocol}://{host}:{port}'
variables:
Expand Down

0 comments on commit 7d34bec

Please sign in to comment.