Skip to content

Commit f66c2e4

Browse files
committed
Changes after review
1 parent 0274c1a commit f66c2e4

File tree

4 files changed

+31
-18
lines changed

4 files changed

+31
-18
lines changed

Diff for: basic_pipeline/03_Source.md

+12-7
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ defmodule Basic.Elements.Source do
114114
end
115115
```
116116

117-
When the setup is complete, the element goes into `playing` state. It can then demand buffers from previous elements and send its `:stream_format` to receiving elements. Since we are implementing a sink we do not have anything to demand from, but we can specify the format. We can do this, for example, in `handle_playing/2`:
117+
When the setup is complete, the element goes into `:playing` state. It can then demand buffers from previous elements and send its `:stream_format` to subsequent elements. Since we are implementing a sink we do not have any previous element to demand from, but we can specify the format. We can do this, for example, in `handle_playing/2`:
118118

119119
**_`lib/elements/source.ex`_**
120120

@@ -129,7 +129,7 @@ defmodule Basic.Elements.Source do
129129
end
130130
```
131131

132-
The `:stream_format` action means that we want to transmit the information about the supported [formats](../glossary/glossary.md#stream-format-formerly-caps) through the `output` pad, to the next element in the pipeline. In [chapter 4](../basic_pipeline/04_Caps.md) you will find out more about stream formats and learn why it is required to do so.
132+
The `:stream_format` action means that we want to transmit the information about the supported [formats](../glossary/glossary.md#stream-format-formerly-caps) through the `output` pad, to the next element in the pipeline. In [chapter 4](../basic_pipeline/04_StreamFormat.md) you will find out more about stream formats and learn why it is required to do so.
133133

134134
## Demands
135135

@@ -162,11 +162,16 @@ defmodule Basic.Elements.Source do
162162
end
163163
```
164164

165-
The callback's body describes the situation in which some buffers were requested. Then we are checking if we have any packets left in the list persisting in the state of the element. If that list is empty, we are sending an `end_of_stream` action, indicating that there will be no more buffers sent through the `:output` pad and that is why there is no point in requesting more buffers.
166-
However, in case of the `content` list of packets being non-empty, we are taking the head of that list, and storing the remaining tail of the list in the state of the element. Later on, we are defining the actions we want to take - that is, we want to return a buffer with the head packet from the original list. We make use of the [`buffer:` action](https://hexdocs.pm/membrane_core/Membrane.Element.Action.html#t:buffer_t/0), and specify that we want to transmit the [`%Buffer`](https://hexdocs.pm/membrane_core/Membrane.Buffer.html#t:t/0) structure through the `:output` pad. Note the fields available in the `%Buffer` structure - in our case, we make use of only the `:payload` field, which, according to the documentation, can be of `any` type - however, in almost all cases you will need to send binary data within this field. Any structured data (just like timestamps etc.) should be passed in the other fields available in the `%Buffer`, designed especially for that cases.
167-
However, there is the other action that is taken - the `:redemand` action, queued to take place on the `:output` pad. This action will simply invoke the `handle_demand/4` callback once again, which is helpful when the whole demand cannot be completely fulfilled in the single `handle_demand` invocation we are just processing. The great thing here is that the `size` of the demand will be automatically determined by the element and we do not need to specify it anyhow. Redemanding, in the context of sources, helps us simplify the logic of the `handle_demand` callback since all we need to do in that callback is to supply a single piece of data and in case this is not enough, take a [`:redemand`](https://hexdocs.pm/membrane_core/Membrane.Element.Action.html#t:redemand_t/0) action and invoke that callback once again. As you will see later, the process of redemanding is even more powerful in the context of [filter elements](../glossary/glossary.md#filter).
168-
But don't give up if you don't grasp demands just yet! :) Membrane also supports `:auto` flow control, which takes care of demands and should be enough for 90% of use cases.
165+
The callback's body describes the situation in which some buffers were requested. Then we are checking if we have any packets left in the list persisting in the state of the element. If that list is empty, we are sending an `end_of_stream` action, indicating that there will be no more buffers sent through the `:output` pad and that is why there is no point in requesting more buffers.
169166

170-
By now you should have created a `Basic.Element.Source` element, with options and output pads defined and its `handle_init/2`, `handle_setup/2`, `handle_playing/2` and `handle_demand/5` callbacks implemented.
167+
However, in case of the `content` list of packets being non-empty, we are taking the head of that list, and storing the remaining tail of the list in the state of the element. Later on, we are defining the actions we want to take - that is, we want to return a buffer with the head packet from the original list. We make use of the [`buffer:` action](https://hexdocs.pm/membrane_core/Membrane.Element.Action.html#t:buffer_t/0), and specify that we want to transmit the [`%Buffer`](https://hexdocs.pm/membrane_core/Membrane.Buffer.html#t:t/0) structure through the `:output` pad. Note the fields available in the `%Buffer` structure - in our case, we make use of only the `:payload` field, which, according to the documentation, can be of `any` type - however, in almost all cases you will need to send binary data within this field. Any structured data (just like timestamps etc.) should be passed in the other fields available in the `%Buffer`, designed especially for that cases.
168+
169+
Then there's the other action that is taken - the `:redemand` action, queued to take place on the `:output` pad. This action will simply invoke the `handle_demand/4` callback once again, which is helpful when the whole demand cannot be completely fulfilled in the single `handle_demand` invocation we are just processing. The great thing here is that the `size` of the demand will be automatically determined by the element and we do not need to specify it anyhow. Redemanding, in the context of sources, helps us simplify the logic of the `handle_demand` callback since all we need to do in that callback is to supply a single piece of data and in case this is not enough, take a [`:redemand`](https://hexdocs.pm/membrane_core/Membrane.Element.Action.html#t:redemand_t/0) action and invoke that callback once again. As you will see later, the process of redemanding is even more powerful in the context of [filter elements](../glossary/glossary.md#filter).
170+
171+
> ### TIP
172+
>
173+
> Membrane also supports `:auto` demand mode, which should cover 90% of use cases.
174+
>
175+
> You can learn more about demand modes [here](https://membrane.stream/learn/get_started_with_membrane/6).
171176
172177
In the next chapter we will explore what stream formats are in Membrane.

Diff for: basic_pipeline/04_StreamFormat.md

+8-6
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,15 @@ Module name defines the type of the format, however it is possible to pass some
4444
2. We specify the pad of the element with the format we have just defined, using the `:accepted_format` option. For the purpose of an example, let it be the `:input` pad:
4545

4646
```elixir
47-
def_input_pad(:input,
47+
def_input_pad :input,
4848
demand_unit: :buffers,
49-
accepted_format: [
50-
{Format.Raw, pixel_format: one_of([:I420, :I422]), framerate: range(30, 60), width: 480, height: 300},
51-
{Format.Raw, pixel_format: one_of([:I420, :I422]), framerate: range(30, 60), width: 720, height: 480}
52-
]
53-
)
49+
accepted_format:
50+
any_of([
51+
%Format.Raw{pixel_format: pixel_format, framerate: framerate, width: 480, height: 300}
52+
when pixel_format in [:I420, :I422] and framerate >= 30 and framerate <= 60,
53+
%Format.Raw{pixel_format: pixel_format, framerate: range(30, 60), width: 720, height: 480}
54+
when pixel_format in [:I420, :I422] and framerate >= 30 and framerate <= 60
55+
])
5456
```
5557

5658
As you can see, we pass a list of compatible formats, each described with the tuple, consisting of our module name, and the keywords list fulfilling the

Diff for: basic_pipeline/05_Formats.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ end
3232

3333
Same as in the case of the previous format - we are defining a structure with a single field, called `:encoding`, and the default value of that field - `:utf8`.
3434

35-
That's it! Format modules are really simple - the more complicated thing is to make use of them - which we will do in the subsequent chapters while defining the specs!
35+
That's it! Format modules are really simple, and using them is not that hard either, as you will see in the subsequent chapters - defining the accepted stream formats and sending stream format actions!
3636

3737
Before advancing you can test the `Source` [element](../glossary/glossary.md/#source), using the tests provided in `/test` directory.
3838

Diff for: basic_pipeline/11_Pipeline.md

+10-4
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,23 @@ defmodule Basic.Pipeline do
8282
Remember to pass the desired file paths in the `:location` option!
8383

8484
Now... that's it! :)
85-
The spec list using Membrane's DSL is enough to describe our pipeline's topology. The child keywords spawn components of the specified type and we can use the `|>` operator to link them together. When the pads that should be linked are unamibiguous this is straightforward but for links like those with `Mixer` we can specify the pads using `via_in/1`. There also exists a `via_out/1` keyword which works in a similar way.
86-
As you can see the first argument to `child/2` is a component identifier, but it's also possible to have anonymous children using `child/1`, which just has Membrane generate a unique id under the hood.
85+
The spec list using Membrane's DSL is enough to describe our pipeline's topology. The child keywords spawn components of the specified type and we can use the `|>` operator to link them together. When the pads that should be linked are unamibiguous this is straightforward but for links like those with `Mixer` we can specify the pads using `via_in/1`. There also exists a `via_out/1` keyword which works similarly for output pads.
86+
87+
As you can see the first argument to `child/2` is a component identifier. If we had omitted it Membrane would generate a unique identifier under the hood. For more about the `child` functions please refer to [the docs](https://hexdocs.pm/membrane_core/Membrane.ChildrenSpec.html#child/1).
8788

8889
Our pipeline is ready! Let's try to launch it.
8990
We will do so by starting the pipeline, and then playing it. For the ease of use we will do it in a script.
9091

9192
**_`start.exs`_**
9293

9394
```elixir
94-
{:ok, _sup, _pipeline} = Membrane.Pipeline.start_link(Basic.Pipeline)
95-
Process.sleep(500)
95+
{:ok, _sup, pipeline} = Membrane.Pipeline.start_link(Basic.Pipeline)
96+
Process.monitor(pipeline)
97+
98+
# Wait for the pipeline to terminate
99+
receive do
100+
{:DOWN, _monitor, :process, ^pipeline, _reason} -> :ok
101+
end
96102
```
97103

98104
You can execute it by running `mix run start.exs` in the terminal.

0 commit comments

Comments
 (0)