Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/membraneframework-labs/membrane_mpegts_plugin
MPEG-TS demuxer
https://github.com/membraneframework-labs/membrane_mpegts_plugin
Last synced: 24 days ago
JSON representation
MPEG-TS demuxer
- Host: GitHub
- URL: https://github.com/membraneframework-labs/membrane_mpegts_plugin
- Owner: membraneframework-labs
- License: apache-2.0
- Created: 2019-03-29T17:41:58.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2021-11-22T15:56:58.000Z (about 3 years ago)
- Last Synced: 2024-03-14T18:02:41.987Z (10 months ago)
- Language: Elixir
- Homepage: https://membrane.stream
- Size: 161 KB
- Stars: 0
- Watchers: 3
- Forks: 1
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Membrane Multimedia Framework: MPEG-TS
[![Hex.pm](https://img.shields.io/hexpm/v/membrane_mpegts_plugin.svg)](https://hex.pm/packages/membrane_mpegts_plugin)
[![CircleCI](https://circleci.com/gh/membraneframework/membrane_mpegts_plugin.svg?style=svg)](https://circleci.com/gh/membraneframework/membrane_mpegts_plugin)This package provides an element that can be used for demuxing MPEG-TS.
It is part of [Membrane Multimedia Framework](https://membraneframework.org).
## Installation
The package can be installed by adding `membrane_mpegts_plugin` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:membrane_mpegts_plugin, "~> 0.4.0"}
]
end
```The docs can be found at [HexDocs](https://hexdocs.pm/membrane_mpegts_plugin).
## Abbreviations
PAT - Program Association Table
PMT - Program Mapping Table## Usage
Demuxer is an element that has one `:input` and variable amount of outputs depending on the stream.
In this particular example we are demuxing a file that contains MPEG1 audio and H264 video.```elixir
@impl true
def handle_init(path) do
children = [
source_file: %File.Source{location: path, chunk_size: 64_000},
demuxer: MPEG.TS.Demuxer,
video_parser: %H264.Parser{framerate: {24, 1}},
video_decoder: H264.Decoder,
player: SDL.Player,
audio_decoder: Mad.Decoder,
audio_converter: %SWResample.Converter{
output_caps: %Raw{channels: 2, format: :s16le, sample_rate: 48_000}
},
portaudio: PortAudio.Sink
]links = [
link(:source_file) |> to(:demuxer),
link(:demuxer) |> via_out(Pad.ref(:output, 256)) |> to(:video_parser),
link(:demuxer) |> via_out(Pad.ref(:output, 257)) |> to(:audio_decoder),
link(:video_parser) |> to(:video_decoder),
link(:video_decoder) |> to(:player),
link(:audio_decoder) |> to(:audio_converter),
link(:audio_converter) |> to(:portaudio)
]spec = %Spec{
children: children,
links: links,
stream_sync: :sinks
}{{:ok, spec: spec}, %{}}
end
```Upon successful parsing of MPEG Transport stream specific information, demuxer will notify
its parent (usally a pipeline). When the parent receives `{:mpeg_ts_stream_info, prog_map_tables}` message it will need to
link the demuxer outputs. The demuxer will continue its work when either every stream will have its
corresponding pad linked or after receiving `:pads_ready` message. If demuxer receives
`:pads_ready` it will continue its work even though some pads might not be linked.`prog_map_tables` that is received by pipeline has following format:
```
%{
program_id => %Membrane.MPEG.TS.ProgramMapTable{
streams: %{
packet_identifier => %{
type: atom,
type_id: 0..255
}
}
}
}
```So, far example, if we wanted to have as simple behaviour as use first stream with matching type
we would do it like this:```elixir
@impl true
def handle_notification({:mpeg_ts_stream_info, pmt}, _from, state) do
{audio_pid, video_pid} = parse_mapping(pmt)children = [
audio: An.Audio.Element,
video: A.Video.Element
]links = [
link(:demuxer) |> via_out(Pad.ref(:output, audio_pid)) |> to(:audio),
link(:demuxer) |> via_out(Pad.ref(:output, video_pid)) |> to(:video)
]spec = %Spec{
children: children,
links: links,
}{{:ok, spec: spec}, state}
enddefp parse_mapping(mapping) do
mapping = mapping[1]with {:ok, audio_pid} <- first_matching_stream(mapping.streams, :MPEG1_AUDIO),
{:ok, video_pid} <- first_matching_stream(mapping.streams, :H264) do
{audio_pid, video_pid}
end
enddef first_matching_stream(streams, type) do
streams
|> Enum.find(fn {_, value} -> value.type == type end)
|> case do
nil -> {:error, :no_stream}
{pid, _stream_spec} -> {:ok, pid}
end
end
```## Copyright and License
Copyright 2019, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane_mpegts_plugin)
[![Software Mansion](https://logo.swmansion.com/logo?color=white&variant=desktop&width=200&tag=membrane-github)](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane_mpegts_plugin)
Licensed under the [Apache License, Version 2.0](https://github.com/membraneframework/membrane_mpegts_plugin/blob/master/LICENSE)