| <chapter id="chapter-other-ntoone" |
| xreflabel="Writing a N-to-1 Element or Muxer"> |
| <title>Writing a N-to-1 Element or Muxer</title> |
| <para> |
| N-to-1 elements have been previously mentioned and discussed in both |
| <xref linkend="chapter-advanced-request"/> and in |
| <xref linkend="chapter-scheduling"/>. The main noteworthy thing |
| about N-to-1 elements is that each pad is push-based in its own thread, |
| and the N-to-1 element synchronizes those streams by |
| expected-timestamp-based logic. This means it lets all streams wait |
| except for the one that provides the earliest next-expected timestamp. |
| When that stream has passed one buffer, the next |
| earliest-expected-timestamp is calculated, and we start back where we |
| were, until all streams have reached EOS. There is a helper base class, |
| called <classname>GstCollectPads</classname>, that will help you to do |
| this. |
| </para> |
| <para> |
| Note, however, that this helper class will only help you with grabbing |
| a buffer from each input and giving you the one with earliest timestamp. |
| If you need anything more difficult, such as "don't-grab-a-new-buffer |
| until a given timestamp" or something like that, you'll need to do this |
| yourself. |
| </para> |
| |
| <!-- |
| Note: I'd like to have something like this in the final text, but since |
| the code below doesn't work and this is all 0.8'y, I commented it for now. |
| <sect1 id="section-muxer-negotiation" xreflabel="Negotiation"> |
| <title>Negotiation</title> |
| <para> |
| Most container formats will have a fair amount of issues with |
| changing content on an elementary stream. Therefore, you should |
| not allow caps to be changed once you've started using data from |
| them. The easiest way to achieve this is by using explicit caps, |
| which have been explained before. However, we're going to use them |
| in a slightly different way then what you're used to, having the |
| core do all the work for us. |
| </para> |
| <para> |
| The idea is that, as long as the stream/file headers have not been |
| written yet and no data has been processed yet, a stream is allowed |
| to renegotiate. After that point, the caps should be fixed, because |
| we can only use a stream once. Caps may then only change within an |
| allowed range (think MPEG, where changes in FPS are allowed), or |
| sometimes not at all (such as AVI audio). In order to do that, we |
| will, after data retrieval and header writing, set an explicit caps |
| on each sink pad, that is the minimal caps describing the properties |
| of the format that may not change. As an example, for MPEG audio |
| inside an MPEG system stream, this would mean a wide caps of |
| audio/mpeg with mpegversion=1 and layer=[1,2]. For the same audio type |
| in MPEG, though, the samplerate, bitrate, layer and number of channels |
| would become static, too. Since the (request) pads will be removed |
| when the stream ends, the static caps will cease to exist too, then. |
| While the explicit caps exist, the <function>_link ()</function>- |
| function will not be called, since the core will do all necessary |
| checks for us. Note that the property of using explicit caps should |
| be added along with the actual explicit caps, not any earlier. |
| </para> |
| <para> |
| Below here follows the simple example of an AVI muxer's audio caps |
| negotiation. The <function>_link ()</function>-function is fairly |
| normal, but the <function>-Loop ()</function>-function does some of |
| the tricks mentioned above. There is no <function>_getcaps ()</function>- |
| function since the pad template contains all that information already |
| (not shown). |
| </para> |
| <programlisting> |
| static GstPadLinkReturn |
| gst_avi_mux_audio_link (GstPad *pad, |
| const GstCaps *caps) |
| { |
| GstAviMux *mux = GST_AVI_MUX (gst_pad_get_parent (pad)); |
| GstStructure *str = gst_caps_get_structure (caps, 0); |
| const gchar *media = gst_structure_get_name (str); |
| |
| if (!strcmp (str, "audio/mpeg")) { |
| /* get version, make sure it's 1, get layer, make sure it's 1-3, |
| * then create the 2-byte audio tag (0x0055) and fill an audio |
| * stream structure (strh/strf). */ |
| [..] |
| return GST_PAD_LINK_OK; |
| } else if !strcmp (str, "audio/x-raw")) { |
| /* See above, but now with the raw audio tag (0x0001). */ |
| [..] |
| return GST_PAD_LINK_OK; |
| } else [..] |
| [..] |
| } |
| |
| static void |
| gst_avi_mux_loop (GstElement *element) |
| { |
| GstAviMux *mux = GST_AVI_MUX (element); |
| [..] |
| /* As we get here, we should have written the header if we hadn't done |
| * that before yet, and we're supposed to have an internal buffer from |
| * each pad, also from the audio one. So here, we check again whether |
| * this is the first run and if so, we set static caps. */ |
| if (mux->first_cycle) { |
| const GList *padlist = gst_element_get_pad_list (element); |
| GList *item; |
| |
| for (item = padlist; item != NULL; item = item->next) { |
| GstPad *pad = item->data; |
| GstCaps *caps; |
| |
| if (!GST_PAD_IS_SINK (pad)) |
| continue; |
| |
| /* set static caps here */ |
| if (!strncmp (gst_pad_get_name (pad), "audio_", 6)) { |
| /* the strf is the struct you filled in the _link () function. */ |
| switch (strf->format) { |
| case 0x0055: /* mp3 */ |
| caps = gst_caps_new_simple ("audio/mpeg", |
| "mpegversion", G_TYPE_INT, 1, |
| "layer", G_TYPE_INT, 3, |
| "bitrate", G_TYPE_INT, strf->av_bps, |
| "rate", G_TYPE_INT, strf->rate, |
| "channels", G_TYPE_INT, strf->channels, |
| NULL); |
| break; |
| case 0x0001: /* pcm */ |
| caps = gst_caps_new_simple ("audio/x-raw", |
| [..]); |
| break; |
| [..] |
| } |
| } else if (!strncmp (gst_pad_get_name (pad), "video_", 6)) { |
| [..] |
| } else { |
| g_warning ("oi!"); |
| continue; |
| } |
| |
| /* set static caps */ |
| gst_pad_use_explicit_caps (pad); |
| gst_pad_set_explicit_caps (pad, caps); |
| } |
| } |
| [..] |
| /* Next runs will never be the first again. */ |
| mux->first_cycle = FALSE; |
| } |
| </programlisting> |
| <para> |
| Note that there are other ways to achieve that, which might be useful |
| for more complex cases. This will do for the simple cases, though. |
| This method is provided to simplify negotiation and renegotiation in |
| muxers, it is not a complete solution, nor is it a pretty one. |
| </para> |
| </sect1> |
| --> |
| </chapter> |