11defmodule ExWebRTC.RTP.Depayloader.H264 do
2- @ moduledoc """
3- Extracts H264 NAL Units from RTP packets.
2+ @ moduledoc false
3+ # Extracts H264 NAL Units from RTP packets.
4+ #
5+ # Based on [RFC 6184](https://tools.ietf.org/html/rfc6184).
6+ #
7+ # Supported types: Single NALU, FU-A, STAP-A.
48
5- Based on [RFC 6184](https://tools.ietf.org/html/rfc6184).
6-
7- Supported types: Single NALU, FU-A, STAP-A.
8- """
99 @ behaviour ExWebRTC.RTP.Depayloader.Behaviour
1010
1111 require Logger
@@ -15,11 +15,11 @@ defmodule ExWebRTC.RTP.Depayloader.H264 do
1515 @ annexb_prefix << 1 :: 32 >>
1616
1717 @ type t ( ) :: % __MODULE__ {
18- current_timestamp: nil ,
19- fu_parser_acc: nil
18+ current_timestamp: non_neg_integer ( ) | nil ,
19+ fu_parser_acc: [ binary ( ) ]
2020 }
2121
22- defstruct [ : current_timestamp, : fu_parser_acc]
22+ defstruct current_timestamp: nil , fu_parser_acc: [ ]
2323
2424 @ impl true
2525 def new ( ) do
@@ -33,7 +33,7 @@ defmodule ExWebRTC.RTP.Depayloader.H264 do
3333 with { :ok , { header , _payload } = nal } <- NAL.Header . parse_unit_header ( packet . payload ) ,
3434 unit_type = NAL.Header . decode_type ( header ) ,
3535 { :ok , { nal , depayloader } } <-
36- handle_unit_type ( unit_type , depayloader , packet , nal ) do
36+ do_depayload ( unit_type , depayloader , packet , nal ) do
3737 { nal , depayloader }
3838 else
3939 { :error , reason } ->
@@ -42,54 +42,60 @@ defmodule ExWebRTC.RTP.Depayloader.H264 do
4242 Resetting depayloader state. Payload: #{ inspect ( packet . payload ) } .\
4343 """ )
4444
45- { nil , % { depayloader | current_timestamp: nil , fu_parser_acc: nil } }
45+ { nil , % { depayloader | current_timestamp: nil , fu_parser_acc: [ ] } }
4646 end
4747 end
4848
49- defp handle_unit_type ( :single_nalu , depayloader , packet , { _header , payload } ) do
49+ defp do_depayload ( :single_nalu , depayloader , packet , { _header , payload } ) do
5050 { :ok ,
5151 { prefix_annexb ( payload ) , % __MODULE__ { depayloader | current_timestamp: packet . timestamp } } }
5252 end
5353
54- defp handle_unit_type (
54+ defp do_depayload (
5555 :fu_a ,
5656 % { current_timestamp: current_timestamp , fu_parser_acc: fu_parser_acc } ,
5757 packet ,
58+ { _header , _payload }
59+ )
60+ when fu_parser_acc != [ ] and current_timestamp != packet . timestamp do
61+ Logger . warning ( """
62+ received packet with fu-a type payload that is not a start of fragmentation unit with timestamp \
63+ different than last start and without finishing the previous fu. dropping fu.\
64+ """ )
65+
66+ { :error , "invalid timestamp inside fu-a" }
67+ end
68+
69+ defp do_depayload (
70+ :fu_a ,
71+ % { fu_parser_acc: fu_parser_acc } ,
72+ packet ,
5873 { header , payload }
5974 ) do
60- if fu_parser_acc != nil and current_timestamp != packet . timestamp do
61- Logger . warning ( """
62- Received packet with FU-A type payload that is not a start of Fragmentation Unit with timestamp \
63- different than last start and without finishing the previous FU. Dropping FU.\
64- """ )
65-
66- { :error , "Invalid timestamp inside FU-A" }
67- else
68- case FU . parse ( payload , fu_parser_acc || % FU { } ) do
69- { :ok , { data , type } } ->
70- data = NAL.Header . add_header ( data , 0 , header . nal_ref_idc , type )
75+ case FU . parse ( payload , fu_parser_acc || [ ] ) do
76+ { :ok , { data , type } } ->
77+ data = NAL.Header . add_header ( data , 0 , header . nal_ref_idc , type )
7178
72- { :ok ,
73- { prefix_annexb ( data ) ,
74- % __MODULE__ { current_timestamp: packet . timestamp , fu_parser_acc: nil } } }
79+ { :ok ,
80+ { prefix_annexb ( data ) ,
81+ % __MODULE__ { current_timestamp: packet . timestamp , fu_parser_acc: [ ] } } }
7582
76- { :incomplete , fu } ->
77- { :ok , { nil , % __MODULE__ { fu_parser_acc: fu , current_timestamp: packet . timestamp } } }
83+ { :incomplete , fu } ->
84+ { :ok , { nil , % __MODULE__ { fu_parser_acc: fu , current_timestamp: packet . timestamp } } }
7885
79- { :error , _reason } = error ->
80- error
81- end
86+ { :error , _reason } = error ->
87+ error
8288 end
8389 end
8490
85- defp handle_unit_type ( :stap_a , depayloader , packet , { _header , payload } ) do
91+ defp do_depayload ( :stap_a , depayloader , packet , { _header , payload } ) do
8692 with { :ok , result } <- StapA . parse ( payload ) do
87- nals = Enum . reduce ( result , << >> , fn nal , acc -> acc <> prefix_annexb ( nal ) end )
93+ nals = result |> Stream . map ( & prefix_annexb / 1 ) |> Enum . join ( )
8894 { :ok , { nals , % __MODULE__ { depayloader | current_timestamp: packet . timestamp } } }
8995 end
9096 end
9197
92- defp handle_unit_type ( unsupported_type , _depayloader , _packet , _nal ) do
98+ defp do_depayload ( unsupported_type , _depayloader , _packet , _nal ) do
9399 Logger . warning ( """
94100 Received packet with unsupported NAL type: #{ unsupported_type } . Supported types are: Single NALU, STAP-A, FU-A. Dropping packet.
95101 """ )
0 commit comments