Skip to content

Commit 51965be

Browse files
authored
Merge pull request #21 from membraneframework/timestamps
add timestamps to buffers
2 parents b397a37 + 07bfacf commit 51965be

File tree

4 files changed

+43
-49
lines changed

4 files changed

+43
-49
lines changed

README.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ It is part of [Membrane Multimedia Framework](https://membraneframework.org).
1313
Add the following line to your `deps` in `mix.exs`. Run `mix deps.get`.
1414

1515
```elixir
16-
{:membrane_camera_capture_plugin, "~> 0.7.0"}
16+
{:membrane_camera_capture_plugin, "~> 0.7.1"}
1717
```
1818

1919
This package depends on the [ffmpeg](https://www.ffmpeg.org) libraries. The precompiled builds will be pulled and linked automatically. However, should there be any problems, consider installing it manually.
2020

21-
### Manual instalation of dependencies
21+
### Manual installation of dependencies
2222
#### Ubuntu
2323

2424
```bash
@@ -39,34 +39,35 @@ brew install ffmpeg
3939

4040
## Sample Usage
4141

42-
Dependencies:
42+
This example displays the stream from your camera on the screen:
4343

4444
```elixir
45-
def deps do
46-
[
47-
{:membrane_camera_capture_plugin, "~> 0.7.0"}
48-
{:membrane_h264_ffmpeg_plugin, "~> 0.21"},
49-
{:membrane_file_plugin, "~> 0.10"},
50-
{:membrane_ffmpeg_swscale_plugin, "~> 0.10"}
51-
]
52-
end
53-
```
45+
Logger.configure(level: :info)
46+
47+
Mix.install([
48+
{:membrane_camera_capture_plugin, "~> 0.7.1"},
49+
:membrane_h264_ffmpeg_plugin,
50+
:membrane_ffmpeg_swscale_plugin,
51+
:membrane_sdl_plugin
52+
])
5453

55-
```elixir
5654
defmodule Example do
5755
use Membrane.Pipeline
5856

5957
@impl true
6058
def handle_init(_ctx, _options) do
61-
structure =
62-
child(:source, Membrane.CameraCapture)
63-
|> child(:converter, %Membrane.FFmpeg.SWScale.PixelFormatConverter{format: :I420})
64-
|> child(:encoder, Membrane.H264.FFmpeg.Encoder)
65-
|> child(:sink, %Membrane.File.Sink{location: "output.h264"})
59+
spec =
60+
child(Membrane.CameraCapture)
61+
|> child(%Membrane.FFmpeg.SWScale.PixelFormatConverter{format: :I420})
62+
|> child(Membrane.SDL.Player)
6663

67-
{[spec: structure], %{}}
64+
{[spec: spec], %{}}
6865
end
6966
end
67+
68+
Membrane.Pipeline.start_link(Example)
69+
70+
Process.sleep(:infinity)
7071
```
7172

7273
## Testing

lib/membrane_camera_capture_plugin/camera.ex renamed to lib/membrane_camera_capture.ex

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ defmodule Membrane.CameraCapture do
2323
@impl true
2424
def handle_init(_ctx, %__MODULE__{} = options) do
2525
with {:ok, native} <- Native.open(options.device, options.framerate) do
26-
state = %{native: native, provider: nil, framerate: options.framerate}
26+
state = %{native: native, provider: nil, init_time: nil, framerate: options.framerate}
2727
{[], state}
28+
else
29+
{:error, reason} -> raise "Failed to initialize camera, reason: #{reason}"
2830
end
2931
end
3032

@@ -40,46 +42,37 @@ defmodule Membrane.CameraCapture do
4042
framerate: {state.framerate, 1}
4143
}
4244

43-
my_pid = self()
44-
pid = spawn_link(fn -> frame_provider(state.native, my_pid) end)
45+
element_pid = self()
4546

46-
Membrane.ResourceGuard.register(
47-
ctx.resource_guard,
48-
fn -> send(pid, :stop) end
49-
)
47+
{:ok, provider} =
48+
Membrane.UtilitySupervisor.start_link_child(
49+
ctx.utility_supervisor,
50+
# The call to Supervisor.child_spec can be removed after
51+
# https://github.com/membraneframework/membrane_core/pull/681 is merged and released.
52+
Supervisor.child_spec({Task, fn -> frame_provider(state.native, element_pid) end}, [])
53+
)
5054

51-
state = %{state | provider: pid}
55+
state = %{state | provider: provider}
5256
actions = [stream_format: {:output, stream_format}]
5357
{actions, state}
5458
end
5559

5660
defp frame_provider(native, target) do
57-
receive do
58-
:stop -> :ok
59-
after
60-
0 ->
61-
with {:ok, frame} <- Native.read_packet(native) do
62-
buffer = %Buffer{payload: frame}
63-
send(target, {:frame_provider, buffer})
64-
frame_provider(native, target)
65-
else
66-
{:error, reason} ->
67-
raise "Error when reading packet from camera: #{inspect(reason)}"
68-
end
61+
with {:ok, frame} <- Native.read_packet(native) do
62+
send(target, {:frame, frame})
63+
frame_provider(native, target)
64+
else
65+
{:error, reason} ->
66+
raise "Error when reading packet from camera: #{inspect(reason)}"
6967
end
7068
end
7169

7270
@impl true
73-
def handle_info({:frame_provider, buffer}, %{playback: :playing} = _ctx, state) do
74-
{[buffer: {:output, buffer}], state}
75-
end
76-
77-
# This callback is called only when
78-
# element is not in state playing and frame provider is not
79-
# terminated yet (and sending a frame to us, so we ignore it)
80-
@impl true
81-
def handle_info({:frame_provider, _buffer}, _ctx, state) do
82-
{[], state}
71+
def handle_info({:frame, frame}, _ctx, state) do
72+
time = Membrane.Time.monotonic_time()
73+
init_time = state.init_time || time
74+
buffer = %Buffer{payload: frame, pts: time - init_time}
75+
{[buffer: {:output, buffer}], %{state | init_time: init_time}}
8376
end
8477

8578
defp pixel_format_to_atom("yuv420p"), do: :I420
File renamed without changes.

test/membrane_media_capture_plugin/camera_capture_plugin_test.exs renamed to test/membrane_camera_capture_test.exs

File renamed without changes.

0 commit comments

Comments
 (0)