GStreamer based tutorial 06-- get media information

Summary

In a typical media file typically contains some data (e.g.: artist, album, encoding type, etc.), for describing the media file. These data are usually referred to as metadata (Metadata: data that provides information about other data). We can categorize media through metadata, and can be displayed on the screen during playback. This article describes how to quickly get GStreamer is metadata.

 

Metadata GStreamer

GStream metadata divided into two categories:

  • Stream information (Stream-info): used to describe the flow properties. For example: coding type, resolution and sample rate.

Stream-info can be obtained through all Pipeline GstCap, in the use of media Pad type described herein will not be repeated.

  • Flow label (Stream-tag): used to describe non-technical information. For example: author, title, album and so on.

Stream-tag can GstBus, listening GST_MESSAGE_TAG message, extract the appropriate information from the message.
Note that, the Gstreamer may trigger multiple GST_MESSAGE_TAG message, the application program may () combining a plurality of tags, and then displayed at the appropriate time by gst_tag_list_merge, when switching the media file, the cache needs to be cleared.
When using this function, you need GST_TAG_MERGE_PREPEND, so that subsequent updates metadata have higher priority.

 

Sample Code

#include <gst/gst.h>

static void
print_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
{
  int i, num;

  num = gst_tag_list_get_tag_size (list, tag);
  for (i = 0; i < num; ++i) {
    const GValue *val;

    /* Note: when looking for specific tags, use the gst_tag_list_get_xyz() API,
     * we only use the GValue approach here because it is more generic */
    val = gst_tag_list_get_value_index (list, tag, i);
    if (G_VALUE_HOLDS_STRING (val)) {
      g_print ("\t%20s : %s\n", tag, g_value_get_string (val));
    } else if (G_VALUE_HOLDS_UINT (val)) {
      g_print ("\t%20s : %u\n", tag, g_value_get_uint (val));
    } else if (G_VALUE_HOLDS_DOUBLE (val)) {
      g_print ("\t%20s : %g\n", tag, g_value_get_double (val));
    } else if (G_VALUE_HOLDS_BOOLEAN (val)) {
      g_print ("\t%20s : %s\n", tag,
          (g_value_get_boolean (val)) ? "true" : "false");
    } else if (GST_VALUE_HOLDS_BUFFER (val)) {
      GstBuffer *buf = gst_value_get_buffer (val);
      guint buffer_size = gst_buffer_get_size (buf);

      g_print ("\t%20s : buffer of size %u\n", tag, buffer_size);
    } else if (GST_VALUE_HOLDS_DATE_TIME (val)) {
      GstDateTime *dt = g_value_get_boxed (val);
      gchar *dt_str = gst_date_time_to_iso8601_string (dt);

      g_print ("\t%20s : %s\n", tag, dt_str);
      g_free (dt_str);
    } else {
      g_print ("\t%20s : tag of type '%s'\n", tag, G_VALUE_TYPE_NAME (val));
    }
  }
}

static void
on_new_pad (GstElement * dec, GstPad * pad, GstElement * fakesink)
{
  GstPad *sinkpad;

  sinkpad = gst_element_get_static_pad (fakesink, "sink");
  if (!gst_pad_is_linked (sinkpad)) {
    if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
      g_error ("Failed to link pads!");
  }
  gst_object_unref (sinkpad);
}

int
main (int argc, char ** argv)
{
  GstElement *pipe, *dec, *sink;
  GstMessage *msg;
  gchar *uri;

  gst_init (&argc, &argv);

  if (argc < 2)
    g_error ("Usage: %s FILE or URI", argv[0]);

  if (gst_uri_is_valid (argv[1])) {
    uri = g_strdup (argv[1]);
  } else {
    uri = gst_filename_to_uri (argv[1], NULL);
  }

  pipe = gst_pipeline_new ("pipeline");

  dec = gst_element_factory_make ("uridecodebin", NULL);
  g_object_set (dec, "uri", uri, NULL);
  gst_bin_add (GST_BIN (pipe), dec);

  sink = gst_element_factory_make ("fakesink", NULL);
  gst_bin_add (GST_BIN (pipe), sink);

  g_signal_connect (dec, "pad-added", G_CALLBACK (on_new_pad), sink);

  gst_element_set_state (pipe, GST_STATE_PAUSED);

  while (TRUE) {
    GstTagList *tags = NULL;

    msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe),
        GST_CLOCK_TIME_NONE,
        GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_TAG | GST_MESSAGE_ERROR);

    if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_TAG) /* error or async_done */
      break;

    gst_message_parse_tag (msg, &tags);

    g_print ("Got tags from element %s:\n", GST_OBJECT_NAME (msg->src));
    gst_tag_list_foreach (tags, print_one_tag, NULL);
    g_print ("\n");
    gst_tag_list_unref (tags);

    gst_message_unref (msg);
  }

  if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
    GError *err = NULL;

    gst_message_parse_error (msg, &err, NULL);
    g_printerr ("Got error: %s\n", err->message);
    g_error_free (err);
  }

  gst_message_unref (msg);
  gst_element_set_state (pipe, GST_STATE_NULL);
  gst_object_unref (pipe);
  g_free (uri);
  return 0;
}

Save the source code for basic-tutorial-6.c, execute the following command to compile the results obtained:

gcc basic-tutorial-6.c -o basic-tutorial-6 `pkg-config --cflags --libs gstreamer-1.0`

Sample output

$ ./basic-tutorial-6 sintel_trailer-480p.ogv
Got tags from element fakesink0:
                       title : Sintel Trailer
                      artist : Durian Open Movie Team
                   copyright : (c) copyright Blender Foundation | durian.blender.org
                     license : Creative Commons Attribution 3.0 license
            application-name : ffmpeg2theora-0.24
                     encoder : Xiph.Org libtheora 1.1 20090822 (Thusnelda)
                 video-codec : Theora
             encoder-version : 3

Got tags from element fakesink0:
            container-format : Ogg

 

Source code analysis

This example uses uridecodebin parse a media file, configured the same as the other examples Pipeline, described below Tag associated processing logic.

static void
print_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
{
  int i, num;

  num = gst_tag_list_get_tag_size (list, tag);
  for (i = 0; i < num; ++i) {
    const GValue *val;

    /* Note: when looking for specific tags, use the gst_tag_list_get_xyz() API,
     * we only use the GValue approach here because it is more generic */
    val = gst_tag_list_get_value_index (list, tag, i);
    if (G_VALUE_HOLDS_STRING (val)) {
      g_print ("\t%20s : %s\n", tag, g_value_get_string (val));
    } 
...
}    

  This function is used to output the value of a tag. GStreamer will more tags are placed in the same GstTagList. Each label may comprise a plurality of values, the value of which the number is first acquired by gst_tag_list_get_tag_size () interface, and name tag (Tag), and then obtain the corresponding values.
  This example uses GValue to general process, it is necessary to determine the type of data, then the interface obtained by GValue. When actual processing tag can be obtained according to a specification (e.g. ID3Tag) type label value, obtained by direct GstTagList interface, for example: when the tag named title, we can directly use gst_tag_list_get_string () to obtain the title character string, you do not need to pass GValue conversion, detail description refer to GstTagList document .

 

static void
on_new_pad (GstElement * dec, GstPad * pad, GstElement * fakesink)
{
  GstPad *sinkpad;

  sinkpad = gst_element_get_static_pad (fakesink, "sink");
  if (!gst_pad_is_linked (sinkpad)) {
    if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
      g_error ("Failed to link pads!");
  }
  gst_object_unref (sinkpad);
}
...
  sink = gst_element_factory_make ("fakesink", NULL);
  gst_bin_add (GST_BIN (pipe), sink);
  g_signal_connect (dec, "pad-added", G_CALLBACK (on_new_pad), sink);

  Since we only need to extract the appropriate information media, need not concern specific data, it is used here fakesink, fakesink discards all received data directly out of. Here while listening for "pad-added" signals, for dynamically connecting Pipeline, this approach has a dynamic connection Pipeline detail in the introduction.

 

  while (TRUE) {
    GstTagList *tags = NULL;

    msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe),
        GST_CLOCK_TIME_NONE,
        GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_TAG | GST_MESSAGE_ERROR);

    if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_TAG) /* error or async_done */
      break;

    gst_message_parse_tag (msg, &tags);

    g_print ("Got tags from element %s:\n", GST_OBJECT_NAME (msg->src));
    gst_tag_list_foreach (tags, print_one_tag, NULL);
    g_print ("\n");
    gst_tag_list_unref (tags);

    gst_message_unref (msg);
  }

  Other examples of the same, this case also gst_bus_timed_pop_filtered () Get Bus GST_MESSAGE_TAG on, then through gst_message_parse_tag () will be copied from the tag message to GstTagList, and then by gst_tag_list_foreach () sequentially outputs all of the labels, and then release GstTagList.
  Note that if GstTagList does not contain any tag information, gst_tag_list_foreach () callback function will not be called.

 

  It is found from the above description, Stream-tag by monitoring mainly the GST_MESSAGE_TAG, extracting metadata according to a corresponding interface. In the use of the process you need to pay attention to the release of the data.

 

GstDiscoverer

  Obtaining media information is a common feature, so GStreamer by GstDiscoverer provides a practical interface. When used without concern of creating internal Pipeline, simply by creating instances gst_discoverer_new (), using gst_discoverer_discover_uri () specifies the URI, the corresponding monitor signal, to obtain the corresponding meta data within the callback function, the need for additional connection using libgstpbutils-1.0 library. Meanwhile GStreamer based GstDiscoverer provided gst-discoverer-1.0 tools, used as follows:

$ gst-discoverer-1.0 sintel_trailer-480p.mp4
Analyzing file:///home/xleng/video/sintel_trailer-480p.mp4
Done discovering file:///home/xleng/video/sintel_trailer-480p.mp4

Topology:
  container: Quicktime
    audio: MPEG-4 AAC
    video: H.264 (High Profile)

Properties:
  Duration: 0:00:52.209000000
  Seekable: yes
  Live: no
  Tags:
      audio codec: MPEG-4 AAC audio
      maximum bitrate: 128000
      datetime: 1970-01-01T00:00:00Z
      title: Sintel Trailer
      artist: Durian Open Movie Team
      copyright: (c) copyright Blender Foundation | durian.blender.org
      description: Trailer for the Sintel open movie project
      encoder: Lavf52.62.0
      container format: ISO MP4/M4A
      video codec: H.264 / AVC
      bitrate: 535929

 

to sum up

In this tutorial, we learned that:

  • How to get all the information on the label by GST_MESSAGE_TAG.
  • How gst_message_parse_tag () converts the message to GstTagList.
  • How to obtain data corresponding label by GstTagList interface.
  • gst-discoverer use command.

We will follow describes how to control the playback speed of GStreamer.

 

Quote

https://gstreamer.freedesktop.org/documentation/tutorials/basic/media-information-gathering.html?gi-language=c
https://gstreamer.freedesktop.org/documentation/application-development/advanced/metadata.html?gi-language=c
https://gstreamer.freedesktop.org/documentation/application-development/basics/bus.html?gi-language=c

 

Author: John.Leng
This article belongs to the author of all, welcome to reprint. Commercial reprint please contact the author authorized, non-commercial reprint please give the original connection in the apparent position of the article page.

Guess you like

Origin www.cnblogs.com/xleng/p/11277397.html