Packages
membrane_rtp_plugin
0.28.0
0.31.5
0.31.4
0.31.3
0.31.2
0.31.1
0.31.0
0.30.0
0.29.1
0.29.0
0.28.0
0.27.1
0.27.0
0.26.0
0.25.0
0.24.1
0.24.0
0.23.2
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
0.19.1
0.19.0
0.18.0
0.17.1
0.17.0
0.16.0
0.15.0
0.15.0-rc.1
0.14.0
0.13.0
0.12.2
0.12.1
0.12.0
0.11.0
0.10.0
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1-alpha.3
0.7.1-alpha.2
0.7.0-alpha.2
0.7.0-alpha.1
0.7.0-alpha
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0-alpha
Membrane Multimedia Framework plugin for RTP
Current section
Files
Jump to
Current section
Files
lib/membrane/rtp/rtsp_decapsulator.ex
defmodule Membrane.RTP.RTSP.Decapsulator do
@moduledoc """
This element provides functionality of decapsulating RTP Packets and redirecting RTSP messages
received in the same TCP stream established with RTSP. The encapsulation is described in
RFC 7826 Section 14.
Encapsulated RTP packets interleaved in the stream will have the following structure:
["$" = 36 :: 1 byte][Channel id :: 1 byte][Length :: 2 bytes][packet :: <Length> bytes]
RTSP Messages are not encapsulated this way, but can only be present between RTP packets.
"""
use Membrane.Filter
alias Membrane.{Buffer, RemoteStream, RTP, RTSP}
def_options rtsp_session: [
spec: pid() | nil,
default: nil,
description: """
PID of a RTSP Session (returned from Membrane.RTSP.start or Membrane.RTSP.start_link)
that received RTSP responses will be forwarded to. If nil the responses will be
discarded.
"""
]
def_input_pad :input, accepted_format: %RemoteStream{type: :bytestream}
def_output_pad :output, accepted_format: %RemoteStream{type: :packetized, content_format: RTP}
@impl true
def handle_init(_ctx, opts) do
state =
Map.from_struct(opts)
|> Map.merge(%{
unprocessed_data: <<>>
})
{[], state}
end
@impl true
def handle_playing(_ctx, state) do
stream_format = %RemoteStream{type: :packetized, content_format: RTP}
{[stream_format: {:output, stream_format}], state}
end
@impl true
def handle_stream_format(:input, _stream_format, _ctx, state) do
{[], state}
end
@impl true
def handle_buffer(:input, %Buffer{payload: payload, metadata: metadata}, _ctx, state) do
packets_binary = state.unprocessed_data <> payload
{unprocessed_data, complete_packets_binaries} =
get_complete_packets(packets_binary, state.rtsp_session)
packets_buffers =
Enum.map(complete_packets_binaries, &%Buffer{payload: &1, metadata: metadata})
{[buffer: {:output, packets_buffers}], %{state | unprocessed_data: unprocessed_data}}
end
@spec get_complete_packets(binary(), pid() | nil, [binary()]) ::
{unprocessed_data :: binary(), complete_packets :: [binary()]}
defp get_complete_packets(packets_binary, rtsp_session, complete_packets \\ [])
defp get_complete_packets(packets_binary, _rtsp_session, complete_packets)
when byte_size(packets_binary) <= 4 do
{packets_binary, Enum.reverse(complete_packets)}
end
defp get_complete_packets(
<<"$", _channel_id, payload_length::size(16), rest::binary>> = packets_binary,
rtsp_session,
complete_packets
) do
case rest do
<<complete_packet_binary::binary-size(payload_length), rest::binary>> ->
complete_packets = [complete_packet_binary | complete_packets]
get_complete_packets(rest, rtsp_session, complete_packets)
_incomplete_packet_binary ->
{packets_binary, Enum.reverse(complete_packets)}
end
end
defp get_complete_packets(
<<"RTSP", _rest::binary>> = rtsp_message_start,
rtsp_session,
complete_packets_binaries
) do
case RTSP.Response.verify_content_length(rtsp_message_start) do
{:ok, _expected_length, _actual_length} ->
if rtsp_session != nil do
{:ok, %RTSP.Response{status: 200}} =
RTSP.handle_response(rtsp_session, rtsp_message_start)
end
{<<>>, complete_packets_binaries}
{:error, expected_length, actual_length} when actual_length > expected_length ->
rest_length = actual_length - expected_length
rtsp_message_length = byte_size(rtsp_message_start) - rest_length
<<rtsp_message::binary-size(rtsp_message_length)-unit(8), rest::binary>> =
rtsp_message_start
if rtsp_session != nil do
{:ok, %RTSP.Response{status: 200}} = RTSP.handle_response(rtsp_session, rtsp_message)
end
get_complete_packets(rest, rtsp_session, complete_packets_binaries)
{:error, expected_length, actual_length} when actual_length <= expected_length ->
{rtsp_message_start, Enum.reverse(complete_packets_binaries)}
end
end
end