432 lines
49 KiB
HTML
432 lines
49 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>The Be Book - System Overview - The Media Kit</title><link rel="stylesheet" href="be_book.css" type="text/css" media="all" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="./images/favicon.ico" /><!--[if IE]>
|
||
<link rel="stylesheet" type="text/css" href="be_book_ie.css" />
|
||
<![endif]--><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><meta name="keywords" content="Access, BeOS, BeBook, API" /><link rel="start" href="index.html" title="The Be Book" /><link rel="up" href="TheMediaKit_Overview.html" title="The Media Kit" /><link rel="prev" href="BMediaNode_Overview.html" title="BMediaNode" /><link rel="next" href="BMediaTheme_Overview.html" title="BMediaTheme" /></head><body><div id="header"><div id="headerT"><div id="headerTL"><a accesskey="p" href="BMediaNode_Overview.html" title="BMediaNode"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a accesskey="u" href="TheMediaKit_Overview.html" title="The Media Kit"><img src="./images/navigation/up.png" alt="Up" /></a> <a accesskey="n" href="BMediaTheme_Overview.html" title="BMediaTheme"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="headerTR"><div id="navigpeople"><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div><div class="navigboxed" id="navigindex"><a accesskey="i" href="ClassIndex.html" title="Index">I</a></div><div class="navigboxed" id="naviglang" title="English">en</div></div><div id="headerTC">The Be Book - System Overview - The Media Kit</div></div><div id="headerB">Prev: <a href="BMediaNode_Overview.html">BMediaNode</a> Up: <a href="TheMediaKit_Overview.html">The Media Kit</a> Next: <a href="BMediaTheme_Overview.html">BMediaTheme</a></div><hr /></div><div class="section"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="BMediaRoster_Overview"></a>BMediaRoster</h2></div></div></div><a id="id587191" class="indexterm"></a><p>The <a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a>
|
||
class comprises the functionality that applications that
|
||
use the Media Kit can access.</p><p>An application can only have a single instance of the
|
||
<a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a> class,
|
||
which is accessed by calling the static member function
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_Roster" title="Roster(), CurrentRoster()"><code class="methodname">BMediaRoster::Roster()</code></a>,
|
||
which creates the media roster, establishes the
|
||
connection to the Media Server, then returns a pointer to the roster.</p><p>The creation of the roster object is thread protected, so you can safely
|
||
call <a class="link" href="BMediaRoster.html#BMediaRoster_Roster" title="Roster(), CurrentRoster()"><code class="methodname">BMediaRoster::Roster()</code></a>
|
||
from multiple threads without
|
||
synchronization, and both threads will safely get the same instance. The
|
||
cost of this synchronization is low enough that there's no need to cache
|
||
the returned pointer, but it's perfectly safe to do so if you wish:</p><pre class="programlisting example cpp"><span class="type">BMediaRoster *</span><code class="varname">gMediaRoster</code>;
|
||
|
||
<span class="type">int</span> <code class="function">main</code>(<span class="type">void</span>) {
|
||
<span class="type">status_t</span> <code class="varname">err</code>;
|
||
|
||
<code class="classname">BApplication</code> <code class="varname">app</code>("application/x-vnd.me-myself");
|
||
<code class="varname">gMediaRoster</code> = <code class="classname">BMediaRoster</code>::<code class="methodname">Roster</code>(&<code class="varname">err</code>);
|
||
|
||
if (!<code class="varname">gMediaRoster</code> || (<code class="varname">err</code> != <code class="constant">B_OK</code>)) {
|
||
<span class="comment">/* the Media Server appears to be dead -- handle that here */</span>
|
||
}
|
||
|
||
<span class="comment">/* The Media Server connection is in place -- enjoy! */</span>
|
||
|
||
return 0;
|
||
}</pre><p>Because <a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a>
|
||
is derived from <a class="link" href="BLooper.html" title="BLooper"><code class="classname">BLooper</code></a>,
|
||
you should create your
|
||
<a class="link" href="BApplication.html" title="BApplication"><code class="classname">BApplication</code></a>
|
||
before calling
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_Roster" title="Roster(), CurrentRoster()"><code class="methodname">BMediaRoster::Roster()</code></a>,
|
||
although the
|
||
<a class="link" href="BApplication.html" title="BApplication"><code class="classname">BApplication</code></a>
|
||
doesn't have to be running yet.</p><p>You should never delete the
|
||
<a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a> returned to you by
|
||
<a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a>.
|
||
Also, you can't derive a class from
|
||
<a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a>.</p><p>If you want to receive notifications from the Media Server when specific
|
||
changes occur, such as nodes coming online or going offline, for example,
|
||
you can register to receive such notifications by calling
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_StartWatching" title="StartWatching(), StopWatching()"><code class="methodname">StartWatching()</code></a>.</p><div class="section"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><hr /><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id587420"></a>Playing Media from Disk</h3></div></div></div><p>To play a media file from disk, you would follow the following steps:</p><ul class="itemizedlist"><li><p>Create an
|
||
<a class="link" href="BEntry.html#entry_ref" title="entry_ref"><span class="type">entry_ref</span></a>
|
||
that refers to the file to be played.</p></li><li><p>Call
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_SniffRef" title="SniffRef(), SniffRefFor()"><code class="methodname">SniffRef()</code></a>
|
||
to obtain a
|
||
<a class="link" href="BMediaAddOn.html#dormant_node_info" title="dormant_node_info"><span class="type">dormant_node_info</span></a>
|
||
reference to the node that is best capable of playing back the media file.</p></li><li><p>Call
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_InstantiateDormantNode" title="InstantiateDormantNode()"><code class="methodname">InstantiateDormantNode()</code></a>
|
||
to instantiate the node; this returns a
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_node" title="media_node"><span class="type">media_node</span></a>
|
||
that you can use for other
|
||
<a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a> calls.</p></li><li><p>Use
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_SetRefFor" title="SetRefFor(), GetRefFor()"><code class="methodname">SetRefFor()</code></a>
|
||
to pass the <a class="link" href="BEntry.html#entry_ref" title="entry_ref"><span class="type">entry_ref</span></a>
|
||
of the file to be played to the node.</p></li><li><p>Call
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetFreeOutputsFor"><code class="methodname">GetFreeOutputsFor()</code></a>
|
||
to obtain a
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_output" title="media_output"><span class="type">media_output</span></a>
|
||
structure describing an available output on the producer node. This structure contains a
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_source" title="media_source"><span class="type">media_source</span></a>
|
||
you can pass to
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_Connect" title="Connect(), Disconnect()"><code class="methodname">Connect()</code></a>
|
||
as the source of the media data.</p></li><li><p>The
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_output" title="media_output"><span class="type">media_output</span></a>
|
||
structure returned by
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetFreeOutputsFor"><code class="methodname">GetFreeOutputsFor()</code></a>
|
||
contains a
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_format" title="media_format"><span class="type">media_format</span></a>
|
||
field that indicates the general type of media data
|
||
contained by the media file; if you don't already know what type of
|
||
data you're playing back (audio or video or whatever), this will let
|
||
you determine what you'll be playing.</p></li><li><p>You can use this value to determine what type of destination is
|
||
needed to output the data (for example, <code class="constant">B_MEDIA_RAW_AUDIO</code> would go to
|
||
an audio output, and <code class="constant">B_MEDIA_RAW_VIDEO</code> would go to a video output).</p></li><li><p>Call
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_StartWatching" title="StartWatching(), StopWatching()"><code class="methodname">GetAudioMixer()</code></a>
|
||
to get a <a class="link" href="TheMediaKit_DefinedTypes.html#media_node" title="media_node"><span class="type">media_node</span></a>
|
||
for the default audio mixer (if the media data is audio), or
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetVideoOutput"><code class="methodname">GetVideoOutput()</code></a>
|
||
to get a <a class="link" href="TheMediaKit_DefinedTypes.html#media_node" title="media_node"><span class="type">media_node</span></a>
|
||
for the default video output (if the media data is video).</p></li><li><p>Use
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetFreeInputsFor"><code class="methodname">GetFreeInputsFor()</code></a>
|
||
to obtain a <a class="link" href="TheMediaKit_DefinedTypes.html#media_input" title="media_input"><span class="type">media_input</span></a>
|
||
structure describing
|
||
an available input on the consumer node (the audio mixer or video
|
||
output); this structure contains a
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_destination" title="media_destination"><span class="type">media_destination</span></a>
|
||
you can pass to
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_Connect" title="Connect(), Disconnect()"><code class="methodname">Connect()</code></a>.</p></li><li><p>Call <a class="link" href="BMediaRoster.html#BMediaRoster_Connect" title="Connect(), Disconnect()"><code class="methodname">Connect()</code></a>
|
||
to connect the source to the destination.</p></li><li><p>Next, you need to set the time source for the media file's node.
|
||
Normally you'll set this to the preferred time source. The audio mixer
|
||
or video output is already slaved to an appropriate time source.</p></li><li><p>Finally, you can use
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_StartNode" title="StartNode(), StopNode()"><code class="methodname">StartNode()</code></a>
|
||
to start the producer, consumer, and
|
||
time source. The media file should begin playing back.</p></li></ul><p>Let's look at actual sample code that does this. This example is
|
||
particular to playing movie files; in particular, it assumes that the
|
||
video is encoded (<code class="constant">B_MEDIA_ENCODED_VIDEO</code>) and that the audio is in a raw
|
||
audio format (<code class="constant">B_MEDIA_RAW_AUDIO</code>). However, it demonstrates the principles
|
||
of playing both encoded and raw media formats, and you can easily
|
||
extrapolate from it any type of playback you need. First it's necessary
|
||
to identify an appropriate node to handle the file, and to instantiate
|
||
the node and configure it for the file we want to play:</p><pre class="programlisting example cpp"><span class="type">bigtime_t</span> <code class="varname">duration</code>;
|
||
<span class="type">media_node</span> <code class="varname">timeSourceNode</code>;
|
||
|
||
<span class="type">media_node</span> <code class="varname">mediaFileNode</code>;
|
||
<span class="type">media_output</span> <code class="varname">fileNodeOutput</code>;
|
||
<span class="type">int32</span> <code class="varname">fileOutputCount</code>;
|
||
|
||
<span class="type">media_output</span> <code class="varname">fileAudioOutput</code>;
|
||
<span class="type">int32</span> <code class="varname">fileAudioCount</code>;
|
||
|
||
<span class="type">media_node</span> <code class="varname">codecNode</code>;
|
||
<span class="type">media_output</span> <code class="varname">codecOutput</code>;
|
||
<span class="type">media_input</span> <code class="varname">codecInput</code>;
|
||
|
||
<span class="type">media_node</span> <code class="varname">videoNode</code>;
|
||
<span class="type">media_input</span> <code class="varname">videoInput</code>;
|
||
<span class="type">int32</span> <code class="varname">videoInputCount</code>;
|
||
|
||
<span class="type">media_node</span> <code class="varname">audioNode</code>;
|
||
<span class="type">media_input</span> <code class="varname">audioInput</code>;
|
||
<span class="type">int32</span> <code class="varname">audioInputCount</code>;
|
||
|
||
<span class="type">dormant_node_info</span> <code class="varname">nodeInfo</code>;
|
||
<span class="type">status_t</span> <code class="varname">err</code>;
|
||
|
||
<code class="varname">playingFlag</code> = <code class="constant">false</code>;
|
||
<code class="varname">roster</code> = <code class="classname">BMediaRoster</code>::<code class="methodname">Roster</code>();
|
||
|
||
<code class="varname">initStatus</code> = <code class="varname">roster</code>-><code class="methodname">SniffRef</code>(*<code class="varname">ref</code>, 0, &<code class="varname">nodeInfo</code>);
|
||
if (<code class="varname">initStatus</code>) {
|
||
return;
|
||
}
|
||
|
||
<code class="varname">initStatus</code> = <code class="varname">roster</code>-><code class="methodname">InstantiateDormantNode</code>(<code class="varname">nodeInfo</code>, &<code class="varname">mediaFileNode</code>);
|
||
if (<code class="varname">initStatus</code>) {
|
||
return;
|
||
}
|
||
|
||
<code class="varname">roster</code>-><code class="methodname">SetRefFor</code>(<code class="varname">mediaFileNode</code>, *<code class="varname">ref</code>, <code class="constant">false</code>, &<code class="varname">duration</code>);
|
||
if ((<code class="varname">err</code> = <code class="methodname">Setup</code>()) != <code class="constant">B_OK</code>) {
|
||
<code class="function">printf</code>("Error %08lX in Setup()\n", <code class="varname">err</code>);
|
||
}
|
||
else {
|
||
<code class="methodname">Start</code>();
|
||
}</pre><p>This code begins by obtaining a pointer to the media roster. It then
|
||
calls <a class="link" href="BMediaRoster.html#BMediaRoster_SniffRef" title="SniffRef(), SniffRefFor()"><code class="methodname">SniffRef()</code></a>
|
||
to get a
|
||
<a class="link" href="BMediaAddOn.html#dormant_node_info" title="dormant_node_info"><span class="type">dormant_node_info</span></a>
|
||
structure describing the
|
||
best-suited node for reading the media data from the file specified by
|
||
<code class="varname">ref</code>.</p><p>Once a dormant_node_info structure has been filled out, the
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_InstantiateDormantNode" title="InstantiateDormantNode()"><code class="methodname">InstantiateDormantNode()</code></a>
|
||
function is called to instantiate a node to
|
||
handle the file. A dormant node is a node whose code resides in an
|
||
add-on, instead of within the application itself. The
|
||
<code class="varname">nodeInfo</code> structure
|
||
is passed into the function, and on return, the <code class="varname">mediaFileNode</code> has been
|
||
set up for the appropriate node.</p><p>Since the
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_node" title="media_node"><span class="type">media_node</span></a>
|
||
<code class="varname">mediaFileNode</code> is a file handling node, the
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_SetRefFor" title="SetRefFor(), GetRefFor()"><code class="methodname">SetRefFor()</code></a>
|
||
function is then called to tell the newly-instantiated file
|
||
handler node what file it should handle. The inputs here are:</p><ul class="itemizedlist"><li><p><code class="varname">mediaFileNode</code> is the node whose file reference is to be set.</p></li><li><p><code class="varname">ref</code> is the file that the node should reference.</p></li><li><p><code class="constant">false</code> indicates that the file must already exist. If this flag were
|
||
<code class="constant">true</code>, and the file indicated by <code class="varname">ref</code> were nonexistent, the node would
|
||
create a new file. Since we're playing a file, we don't want to do that.</p></li><li><p><code class="varname">duration</code> is a <span class="type">bigtime_t</span> variable
|
||
that will receive the duration of the media file, in microseconds.</p></li></ul><p>Once this has been accomplished, it's time to instantiate the other nodes
|
||
needed to perform the media playback. Note that your code should check
|
||
the error results from each of these calls and only proceed if
|
||
<code class="constant">B_OK</code> is returned.</p><p>The <code class="methodname">Setup()</code>
|
||
and <code class="methodname">Start()</code>
|
||
functions used in the example above are given below.
|
||
<code class="methodname">Setup()</code>
|
||
actually sets up the connections and instantiates the
|
||
various other nodes (such as codecs and output nodes) required to play
|
||
back the media data. Let's take a look at
|
||
<code class="methodname">Setup()</code> next:</p><pre class="programlisting example cpp"><span class="type">status_t</span> <code class="classname">MediaPlayer</code>::<code class="methodname">Setup</code>(<span class="type">void</span>) {
|
||
<span class="type">status_t</span> <code class="varname">err</code>;
|
||
<span class="type">media_format</span> <code class="varname">tryFormat</code>;
|
||
<span class="type">dormant_node_info</span> <code class="varname">nodeInfo</code>;
|
||
<span class="type">int32</span> <code class="varname">nodeCount</code>;
|
||
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetAudioMixer</code>(&<code class="varname">audioNode</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetVideoOutput</code>(&<code class="varname">videoNode</code>);</pre><p>First, <a class="link" href="BMediaRoster.html#BMediaRoster_GetAudioMixer"><code class="methodname">GetAudioMixer()</code></a>
|
||
and <a class="link" href="BMediaRoster.html#BMediaRoster_GetVideoOutput"><code class="methodname">GetVideoOutput()</code></a>
|
||
are called to obtain an audio
|
||
mixer node and a video output node. The nodes returned by this function
|
||
are based on the user's preferences in the Audio and Video preference
|
||
applications. By default, video is output to a simple video output
|
||
consumer that creates a window to contain the video display.</p><div class="admonition note"><div class="title">Note</div><div class="graphic"><img class="icon" alt="Note" width="32" src="./images/admonitions/Info_32.png" /><div class="text"><p>The VideoConsumer node will be available with R4.5; it's not provided
|
||
in R4. In addition, there are no video producer nodes in R4; media
|
||
add-ons for a variety of movie file formats will also be available
|
||
beginning with R4.5.</p></div></div></div><pre class="programlisting example cpp"> <code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetTimeSource</code>(&<code class="varname">timeSourceNode</code>);
|
||
<code class="varname">b_timesource</code> = <code class="varname">roster</code>-><code class="methodname">MakeTimeSourceFor</code>(<code class="varname">timeSourceNode</code>);</pre><p>This code obtains a
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_node" title="media_node"><span class="type">media_node</span></a>
|
||
for the preferred time source, and then creates a
|
||
<a class="link" href="BTimeSource.html" title="BTimeSource"><code class="classname">BTimeSource</code></a>
|
||
object that refers to the same node; we'll need to be able to make some
|
||
<a class="link" href="BTimeSource.html" title="BTimeSource"><code class="classname">BTimeSource</code></a>
|
||
calls to obtain some specific timing information later.</p><p>A time source is a node that can be used to synchronize other nodes. By
|
||
default, nodes are slaved to the system time source, which is the
|
||
computer's internal clock. However, this time source, while very precise,
|
||
isn't good for synchronizing media data, since its concept of time has
|
||
nothing to do with actual media being performed. For this reason, you
|
||
typically will want to change nodes' time sources to the preferred time
|
||
source.</p><p>You can think of a media node (represented by the
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_node" title="media_node"><span class="type">media_node</span></a> structure)
|
||
as a component in a home theater system you might have at home. It has
|
||
inputs for audio and video (possibly multiple inputs for each), and
|
||
outputs to pass that audio and video along to other components in the
|
||
system. To use the component, you have to connect wires from the outputs
|
||
of some other components into the component's inputs, and the outputs
|
||
into the inputs of other components.</p><p>The Media Kit works the same way. We need to locate audio outputs from
|
||
the <code class="varname">mediaFileNode</code> and find corresponding audio
|
||
inputs on the <code class="varname">audioNode</code>.
|
||
This is analogous to choosing an audio output from your new DVD player
|
||
and matching it to an audio input jack on your stereo receiver. Since you
|
||
can't use ports that are already in use, we call
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetFreeOutputsFor"><code class="methodname">GetFreeOutputsFor()</code></a>
|
||
to find free output ports on the <code class="varname">mediaFileNode</code>, and
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetFreeInputsFor"><code class="methodname">GetFreeInputsFor()</code></a>
|
||
to locate free input ports on the <code class="varname">audioNode</code>.</p><pre class="programlisting example cpp"> <code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetFreeOutputsFor</code>(<code class="varname">mediaFileNode</code>, &<code class="varname">fileAudioOutput</code>, 1,
|
||
&<code class="varname">fileAudioCount</code>, <code class="constant">B_MEDIA_RAW_AUDIO</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetFreeInputsFor</code>(<code class="varname">audioNode</code>, &<code class="varname">audioInput</code>, <code class="varname">fileAudioCount</code>,
|
||
&<code class="varname">audioInputCount</code>, <code class="constant">B_MEDIA_RAW_AUDIO</code>);</pre><p>We only want a single audio connection between the two nodes (a
|
||
single connection can carry stereo sound), and the connection is of type
|
||
<code class="constant">B_MEDIA_RAW_AUDIO</code>. On return,
|
||
<code class="varname">fileAudioOutput</code> and <code class="varname">audioInput</code>
|
||
describe the output from the <code class="varname">mediaFlieNode</code> and the input
|
||
into the <code class="varname">audioNode</code> that will eventually be connected to
|
||
play the movie's sound.</p><p>We likewise have to find a video output from the
|
||
<code class="varname">mediaFileNode</code> and an input into the
|
||
<code class="varname">videoNode</code>. In this case, though, we expect the video
|
||
output from the <code class="varname">mediaFileNode</code> to be encoded, and the
|
||
<code class="varname">videoNode</code> will want to receive raw, uncompressed video.
|
||
We'll work that out in a minute; for now, let's just find the two
|
||
ports:</p><pre class="programlisting example cpp"> <code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetFreeOutputsFor</code>(<code class="varname">mediaFileNode</code>, &<code class="varname">fileNodeOutput</code>, 1,
|
||
&<code class="varname">fileOutputCount</code>, <code class="constant">B_MEDIA_ENCODED_VIDEO</code>)
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetFreeInputsFor</code>(<code class="varname">videoNode</code>, &<code class="varname">videoInput</code>, <code class="varname">fileOutputCount</code>,
|
||
&<code class="varname">videoInputCount</code>, <code class="constant">B_MEDIA_RAW_VIDEO</code>);</pre><p>The problem we have now is that the <code class="varname">mediaFileNode</code> is outputting video
|
||
that's encoded somehow (like in Cinepak format, for instance). The
|
||
<code class="varname">videoNode</code>, on the other hand, wants to display raw video. Another node
|
||
must be placed between these to decode the video (much like having an
|
||
adapter to convert <acronym class="acronym">PAL</acronym> video into <acronym class="acronym">NTSC</acronym>, for example). This node will be
|
||
the codec that handles decompressing the video into raw form.</p><p>We need to locate a codec node that can handle the video format being
|
||
output by the <code class="varname">mediaFileNode</code>. This is accomplished like this:</p><pre class="programlisting example cpp"> <code class="varname">nodeCount</code> = 1;
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetDormantNodes</code>(&<code class="varname">nodeInfo</code>, &<code class="varname">nodeCount</code>,
|
||
&<code class="varname">fileNodeOutput</code>.<code class="varname">format</code>);
|
||
if (!<code class="varname">nodeCount</code>) {
|
||
return -1;
|
||
}</pre><p>This call to
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetDormantNodes" title="GetDormantNodes()"><code class="methodname">GetDormantNodes()</code></a>
|
||
looks for a dormant node that can handle the media format specified by the
|
||
<code class="varname">mediaFileNode</code>'s output
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_format" title="media_format"><span class="type">media_format</span></a>
|
||
structure. Information about the node is returned in <code class="varname">nodeInfo</code>.
|
||
<code class="varname">nodeCount</code> indicates the number of matching nodes that
|
||
were found. If it's zero, an error is returned.</p><p>Note that in real life you should ask for several nodes, and search
|
||
through them, looking at the formats until you find one that best meets
|
||
your needs.</p><p>Then we use
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_InstantiateDormantNode" title="InstantiateDormantNode()"><code class="methodname">InstantiateDormantNode()</code></a>
|
||
to instantiate the codec node, and
|
||
locate inputs into the node (that accept encoded video) and outputs from
|
||
the node (that output raw video):</p><pre class="programlisting example cpp"> <code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">InstantiateDormantNode</code>(<code class="varname">nodeInfo</code>, &<code class="varname">codecNode</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetFreeInputsFor</code>(<code class="varname">codecNode</code>, &<code class="varname">codecInput</code>, 1, &<code class="varname">nodeCount</code>,
|
||
<code class="constant">B_MEDIA_ENCODED_VIDEO</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetFreeOutputsFor</code>(<code class="varname">codecNode</code>, &<code class="varname">codecOutput</code>, 1,
|
||
&<code class="varname">nodeCount</code>, <code class="constant">B_MEDIA_RAW_VIDEO</code>);</pre><p>Now we're ready to start connecting these nodes together. If we were
|
||
setting up a home theater system, right about now we'd be getting rug
|
||
burns on our knees and skinned knuckles on our hands, trying to reach
|
||
behind the entertainment center to run wires. The Media Kit is way easier
|
||
than that, and doesn't involve salespeople telling you to get expensive
|
||
gold-plated cables.</p><p>We begin by connecting the file node's video output to the codec's input:</p><pre class="programlisting example cpp"> <code class="varname">tryFormat</code> = <code class="varname">fileNodeOutput</code>.<code class="varname">format</code>;
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">Connect</code>(<code class="varname">fileNodeOutput</code>.<code class="varname">source</code>, <code class="varname">codecInput</code>.<code class="varname">destination</code>,
|
||
&<code class="varname">tryFormat</code>, &<code class="varname">fileNodeOutput</code>, &<code class="varname">codecInput</code>);</pre><p><code class="varname">tryFormat</code> indicates the format of the encoded video that will be output
|
||
by the <code class="varname">mediaFileNode</code>.
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_Connect" title="Connect(), Disconnect()"><code class="methodname">Connect()</code></a>,
|
||
in essense, runs a wire between the
|
||
output from the media node's video output (<code class="varname">fileNodeOutput</code>) to the codec
|
||
node's input.</p><p>You may wonder what's up with the <code class="varname">fileNodeOutput</code>.<code class="varname">source</code> and
|
||
<code class="varname">codecInput</code>.<code class="varname">destination</code> structures. These
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_source" title="media_source"><span class="type">media_source</span></a> and
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_destination" title="media_destination"><span class="type">media_destination</span></a>
|
||
structures are simplified descriptors of the two ends
|
||
of the connection. They contain only the data absolutely needed for the
|
||
Media Kit to establish the connection. This saves some time when issuing
|
||
the
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_Connect" title="Connect(), Disconnect()"><code class="methodname">Connect()</code></a>
|
||
call (and time is money, especially in the media business).</p><p>Next it's necessary to connect the codec to the video output node. This
|
||
begins by setting up <code class="varname">tryFormat</code> to describe raw video of the same width
|
||
and height as the encoded video being fed into the codec, then calling
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_Connect" title="Connect(), Disconnect()"><code class="methodname">Connect()</code></a>
|
||
to establish the connection:</p><pre class="programlisting example cpp"> <code class="varname">tryFormat</code>.<code class="varname">type</code> = <code class="constant">B_MEDIA_RAW_VIDEO</code>;
|
||
<code class="varname">tryFormat</code>.<code class="varname">u</code>.<code class="varname">raw_video</code> = <span class="type">media_raw_video_format</span>::<code class="varname">wildcard</code>;
|
||
<code class="varname">tryFormat</code>.<code class="varname">u</code>.<code class="varname">raw_video</code>.<code class="varname">display</code>.<code class="varname">line_width</code> =
|
||
<code class="varname">codecInput</code>.<code class="varname">format</code>.<code class="varname">u</code>.<code class="varname">encoded_video</code>.<code class="varname">output</code>.<code class="varname">display</code>.<code class="varname">line_width</code>;
|
||
<code class="varname">tryFormat</code>.<code class="varname">u</code>.<code class="varname">raw_video</code>.<code class="varname">display</code>.<code class="varname">line_count</code> =
|
||
<code class="varname">codecInput</code>.<code class="varname">format</code>.<code class="varname">u</code>.<code class="varname">encoded_video</code>.<code class="varname">output</code>.<code class="varname">display</code>.<code class="varname">line_count</code>;
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">Connect</code>(<code class="varname">codecOutput</code>.<code class="varname">source</code>, <code class="varname">videoInput</code>.<code class="varname">destination</code>,
|
||
&<code class="varname">tryFormat</code>, &<code class="varname">codecOutput</code>, &<code class="varname">videoInput</code>);</pre><p>Now we connect the audio from the media file to the audio mixer node. We
|
||
just copy the
|
||
<a class="link" href="TheMediaKit_DefinedTypes.html#media_format" title="media_format"><span class="type">media_format</span></a>
|
||
from the file's audio output, since both ends of the connection should exactly match.</p><pre class="programlisting example cpp"> <code class="varname">tryFormat</code> = <code class="varname">fileAudioOutput</code>.<code class="varname">format</code>;
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">Connect</code>(<code class="varname">fileAudioOutput</code>.<code class="varname">source</code>, <code class="varname">audioInput</code>.<code class="varname">destination</code>,
|
||
&<code class="varname">tryFormat</code>, &<code class="varname">fileAudioOutput</code>, &<code class="varname">audioInput</code>);</pre><p>The last step of configuring the connections is to ensure that all the
|
||
nodes are slaved to the preferred time source. This will keep them
|
||
synchronized with the preferred time source (and by association, with
|
||
each other):</p><pre class="programlisting example cpp"> <code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">SetTimeSourceFor</code>(<code class="varname">mediaFileNode</code>.<code class="varname">node</code>,
|
||
<code class="varname">timeSourceNode</code>.<code class="varname">node</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">SetTimeSourceFor</code>(<code class="varname">videoNode</code>.<code class="varname">node</code>, <code class="varname">timeSourceNode</code>.<code class="varname">node</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">SetTimeSourceFor</code>(<code class="varname">codecOutput</code>.<code class="varname">node</code>.<code class="varname">node</code>,
|
||
<code class="varname">timeSourceNode</code>.<code class="varname">node</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">SetTimeSourceFor</code>(<code class="varname">audioNode</code>.<code class="varname">node</code>, <code class="varname">timeSourceNode</code>.<code class="varname">node</code>);
|
||
return <code class="constant">B_OK</code>;
|
||
}</pre><p>Finally, we return <code class="constant">B_OK</code> to the caller. Note that this code should be
|
||
enhanced to check the results of each
|
||
<a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a>
|
||
call, and to return the result code if it's not <code class="constant">B_OK</code>.
|
||
This has been left out of this example for brevity.</p><p>The <code class="methodname">Start()</code>
|
||
function actually starts the movie playback. Starting
|
||
playback involves starting, one at a time, all the nodes involved in
|
||
playing back the audio. This includes the audio mixer (<code class="varname">audioNode</code>), the
|
||
media file's node (<code class="varname">mediaFileNode</code>), the codec, and the video node.</p><pre class="programlisting example cpp"><span class="type">status_t</span> <code class="classname">MediaPlayer</code>::<code class="methodname">Start</code>(<span class="type">void</span>) {
|
||
<span class="type">status_t</span> <code class="varname">err</code>;
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">GetStartLatencyFor</code>(<code class="varname">timeSourceNode</code>, &<code class="varname">startTime</code>);
|
||
<code class="varname">startTime</code> += <code class="varname">b_timesource</code>-><code class="methodname">PerformanceTimeFor</code>(<code class="classname">BTimeSource</code>::<code class="methodname">RealTime</code>()
|
||
+ 1000000 / 50);
|
||
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">StartNode</code>(<code class="varname">mediaFileNode</code>, <code class="varname">startTime</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">StartNode</code>(<code class="varname">codecNode</code>, <code class="varname">startTime</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">StartNode</code>(<code class="varname">videoNode</code>, <code class="varname">startTime</code>);
|
||
|
||
return <code class="constant">B_OK</code>;
|
||
}</pre><p>Because there's lag time between starting each of these nodes, we pick a
|
||
time a few moments in the future for playback to begin, and schedule each
|
||
node to start playing at that time. So we begin by computing that time in
|
||
the future.</p><p>The
|
||
<a class="link" href="BTimeSource.html#BTimeSource_RealTime" title="RealTime()"><code class="methodname">BTimeSource::RealTime()</code></a>
|
||
static member function is called to obtain
|
||
the current real system time. We add a fiftieth of a second to that time,
|
||
and convert it into performance time units. This is the time at which the
|
||
performance of the movie will begin (basically a fiftieth of a second
|
||
from "now"). This value is saved in <code class="varname">startTime</code>. These are added to the
|
||
value returned by
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetStartLatencyFor" title="GetStartLatencyFor()"><code class="methodname">GetStartLatencyFor()</code></a>,
|
||
which returns the time required
|
||
to actually start the time source and all the nodes slaved to it.</p><p>Then we simply call
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_StartNode" title="StartNode(), StopNode()"><code class="methodname">BMediaRoster::StartNode()</code></a>
|
||
for each node, specifying
|
||
<code class="varname">startTime</code> as the performance time at which playback should begin.</p><p>Again, error handling should be added to actually return the error code
|
||
from these functions.</p><p>Stopping playback of the movie is even simpler:</p><pre class="programlisting example cpp"> <code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">StopNode</code>(<code class="varname">mediaFileNode</code>, 0, <code class="constant">true</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">StopNode</code>(<code class="varname">codecNode</code>, 0, <code class="constant">true</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">StopNode</code>(<code class="varname">videoNode</code>, 0, <code class="constant">true</code>);</pre><p>This tells the media file, video codec, and video output nodes to stop
|
||
immediately. If we wanted them to stop together at some time in the
|
||
future, we could compute an appropriate performance time and pass that
|
||
instead of 0. In this case, we would need to specify <code class="constant">false</code> for the last
|
||
argument; when this value is <code class="constant">true</code>,
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_StopNode"><code class="methodname">StopNode()</code></a>
|
||
stops the node immediately.
|
||
We could use this ability to schedule all three nodes to stop at the same
|
||
time, so that video and audio playback would halt simultaneously.</p><p>Note that we don't stop the audio mixer node. You should never stop the
|
||
mixer node, because other applications are probably using it.</p><p>Once you're done playing the movie, and have stopped playback, you should
|
||
disconnect the nodes from each other:</p><pre class="programlisting example cpp"> <code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">Disconnect</code>(<code class="varname">mediaFileNode</code>.<code class="varname">node</code>, <code class="varname">fileNodeOutput</code>.<code class="varname">source</code>,
|
||
<code class="varname">codecNode</code>.<code class="varname">node</code>, <code class="varname">codecInput</code>.<code class="varname">destination</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">Disconnect</code>(<code class="varname">codecNode</code>.<code class="varname">node</code>, <code class="varname">codecOutput</code>.<code class="varname">source</code>,
|
||
<code class="varname">videoNode</code>.<code class="varname">node</code>, <code class="varname">videoInput</code>.<code class="varname">destination</code>);
|
||
<code class="varname">err</code> = <code class="varname">roster</code>-><code class="methodname">Disconnect</code>(<code class="varname">mediaFileNode</code>.<code class="varname">node</code>, <code class="varname">fileAudioOutput</code>.<code class="varname">source</code>,
|
||
<code class="varname">audioNode</code>.<code class="varname">node</code>, <code class="varname">audioInput</code>.<code class="varname">destination</code>);</pre><p>This will close out the connections between the media file node and the
|
||
video codec, the codec and the video output, and between the file node
|
||
and the audio mixer. You should always stop playback before
|
||
disconnecting; although nodes aren't allowed to crash if you disconnect
|
||
them while running, their behavior isn't specified, and may not be what
|
||
you expect.</p><p>Once the connections are severed, you should release any dormant nodes
|
||
you instantiated. This includes not only nodes instantiated using
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_InstantiateDormantNode" title="InstantiateDormantNode()"><code class="methodname">InstantiateDormantNode()</code></a>,
|
||
but also default nodes (those obtained using functions like
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetAudioInput" title="GetAudioInput(), GetVideoInput()"><code class="methodname">GetAudioInput()</code></a> and
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_GetVideoOutput"><code class="methodname">GetVideoOutput)</code></a>,
|
||
for example):</p><pre class="programlisting example cpp"> <code class="varname">roster</code>-><code class="methodname">ReleaseNode</code>(<code class="varname">codecNode</code>);
|
||
<code class="varname">roster</code>-><code class="methodname">ReleaseNode</code>(<code class="varname">mediaFileNode</code>);
|
||
<code class="varname">roster</code>-><code class="methodname">ReleaseNode</code>(<code class="varname">videoNode</code>);
|
||
<code class="varname">roster</code>-><code class="methodname">ReleaseNode</code>(<code class="varname">audioNode</code>);</pre><p>If you want to play audio, you may find it much easier to use the
|
||
<span class="deprecated"><code class="classname">BSound</code></span> and
|
||
<a class="link" href="BSoundPlayer.html" title="BSoundPlayer"><code class="classname">BSoundPlayer</code></a>
|
||
classes to do so. As of R4.5, there are no
|
||
Be-provided nodes for producing audio from a disk file.</p><div class="section"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id589903"></a>Detecting When Playback Is Complete</h4></div></div></div><p>There isn't a Media Kit function that can directly tell you whether or
|
||
not the media has reached the end of the data during playback. However,
|
||
the following easy-to-implement code can do the job for you:</p><pre class="programlisting example cpp"><span class="type">bigtime_t</span> <code class="varname">currentTime</code>;
|
||
<span class="type">bool</span> <code class="varname">isPlaying</code> = <code class="constant">true</code>;
|
||
|
||
<code class="varname">currentTime</code> = <code class="varname">b_timesource</code>-><code class="methodname">PerformanceTimeFor</code>(<code class="classname">BTimeSource</code>::<code class="methodname">RealTime</code>());
|
||
if (<code class="varname">currentTime</code> >= <code class="varname">startTime</code>+<code class="varname">duration</code>) {
|
||
<code class="varname">isPlaying</code> = <code class="constant">false</code>;
|
||
}</pre><p>This works by obtaining the time source's performance time and comparing
|
||
it to the time at which playback of the movie was begun plus the movie's
|
||
duration (both of which were saved when we initially set up and began
|
||
playback of the movie, as seen in the code in the previous section above).</p><p>If the current performance time is equal to or greater than the sum of
|
||
the starting time and the movie's duration, then playback is finished,
|
||
and we set <code class="varname">isPlaying</code> to <code class="constant">false</code>;
|
||
otherwise, this value remains <code class="constant">true</code>.</p></div><div class="section"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id590007"></a>Using BMediaRoster Functions from Nodes</h4></div></div></div><p>You can issue
|
||
<a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a>
|
||
function calls from within your own node, however, as a general rule, you
|
||
shouldn't call <a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a> functions
|
||
from within your control thread, or while the control thread is blocked.
|
||
Many <a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a>
|
||
functions use synchronous turnarounds, and will
|
||
deadlock in this situation. You should assume, for safety's sake, that
|
||
all <a class="link" href="BMediaRoster.html" title="BMediaRoster"><code class="classname">BMediaRoster</code></a>
|
||
functions will deadlock if used in these cases.</p><p>For example, if you have an application that's playing video into a
|
||
window, and you call
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_StopNode"><code class="classname">StopNode()</code></a>
|
||
from the window's
|
||
<a class="link" href="BWindow.html#BWindow_MessageReceived" title="MessageReceived()"><code class="classname">MessageReceived()</code></a>
|
||
function, a deadlock would occur if the video player node blocks waiting
|
||
on the window to be unlocked, and the
|
||
<a class="link" href="BMediaRoster.html#BMediaRoster_StopNode"><code class="classname">StopNode()</code></a>
|
||
function is keeping the
|
||
window locked while it waits for the video producer node, which is
|
||
blocked waiting on the consumer node, and so forth. Deadlock results, and
|
||
that's a bad thing.</p><p>Instead, you should consider creating a seperate
|
||
<a class="link" href="BLooper.html" title="BLooper"><code class="classname">BLooper</code></a>
|
||
that manages
|
||
your nodes. Future versions of the Media Kit will provide convenience
|
||
classes to do some of this for you.</p></div></div></div><div id="footer"><hr /><div id="footerT">Prev: <a href="BMediaNode_Overview.html">BMediaNode</a> Up: <a href="TheMediaKit_Overview.html">The Media Kit</a> Next: <a href="BMediaTheme_Overview.html">BMediaTheme</a> </div><div id="footerB"><div id="footerBL"><a href="BMediaNode_Overview.html" title="BMediaNode"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a href="TheMediaKit_Overview.html" title="The Media Kit"><img src="./images/navigation/up.png" alt="Up" /></a> <a href="BMediaTheme_Overview.html" title="BMediaTheme"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="footerBR"><div><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div></div><div id="footerBC"><a href="http://www.access-company.com/home.html" title="ACCESS Co."><img alt="Access Company" src="./images/access_logo.png" /></a></div></div></div><div id="licenseFooter"><div id="licenseFooterBL"><a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/" title="Creative Commons License"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by-nc-nd/3.0/88x31.png" /></a></div><div id="licenseFooterBR"><a href="./LegalNotice.html">Legal Notice</a></div><div id="licenseFooterBC"><span id="licenseText">This work is licensed under a
|
||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Creative
|
||
Commons Attribution-Non commercial-No Derivative Works 3.0 License</a>.</span></div></div></body></html>
|