Blame tests/check/pipelines/tagschecking.c

Packit 1f69a5
/* GStreamer
Packit 1f69a5
 * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
Packit 1f69a5
 * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
Packit 1f69a5
 *
Packit 1f69a5
 * This library is free software; you can redistribute it and/or
Packit 1f69a5
 * modify it under the terms of the GNU Library General Public
Packit 1f69a5
 * License as published by the Free Software Foundation; either
Packit 1f69a5
 * version 2 of the License, or (at your option) any later version.
Packit 1f69a5
 *
Packit 1f69a5
 * This library is distributed in the hope that it will be useful,
Packit 1f69a5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1f69a5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 1f69a5
 * Library General Public License for more details.
Packit 1f69a5
 *
Packit 1f69a5
 * You should have received a copy of the GNU Library General Public
Packit 1f69a5
 * License along with this library; if not, write to the
Packit 1f69a5
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 1f69a5
 * Boston, MA 02110-1301, USA.
Packit 1f69a5
 */
Packit 1f69a5
Packit 1f69a5
#include <gst/check/gstcheck.h>
Packit 1f69a5
#include <glib/gstdio.h>
Packit 1f69a5
Packit 1f69a5
static GstTagList *received_tags = NULL;
Packit 1f69a5
Packit 1f69a5
static gboolean
Packit 1f69a5
bus_handler (GstBus * bus, GstMessage * message, gpointer data)
Packit 1f69a5
{
Packit 1f69a5
  GMainLoop *loop = (GMainLoop *) data;
Packit 1f69a5
Packit 1f69a5
  switch (message->type) {
Packit 1f69a5
    case GST_MESSAGE_EOS:
Packit 1f69a5
      g_main_loop_quit (loop);
Packit 1f69a5
      break;
Packit 1f69a5
    case GST_MESSAGE_WARNING:
Packit 1f69a5
    case GST_MESSAGE_ERROR:{
Packit 1f69a5
      GError *gerror;
Packit 1f69a5
Packit 1f69a5
      gchar *debug;
Packit 1f69a5
Packit 1f69a5
      gst_message_parse_error (message, &gerror, &debug);
Packit 1f69a5
      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
Packit 1f69a5
      g_error_free (gerror);
Packit 1f69a5
      g_free (debug);
Packit 1f69a5
      g_main_loop_quit (loop);
Packit 1f69a5
      break;
Packit 1f69a5
    }
Packit 1f69a5
    case GST_MESSAGE_TAG:{
Packit 1f69a5
      if (received_tags == NULL) {
Packit 1f69a5
        gst_message_parse_tag (message, &received_tags);
Packit 1f69a5
      } else {
Packit 1f69a5
        GstTagList *tl = NULL, *ntl = NULL;
Packit 1f69a5
Packit 1f69a5
        gst_message_parse_tag (message, &tl;;
Packit 1f69a5
        if (tl) {
Packit 1f69a5
          ntl = gst_tag_list_merge (received_tags, tl, GST_TAG_MERGE_PREPEND);
Packit 1f69a5
          if (ntl) {
Packit 1f69a5
            GST_LOG ("taglists merged: %" GST_PTR_FORMAT, ntl);
Packit 1f69a5
            gst_tag_list_unref (received_tags);
Packit 1f69a5
            received_tags = ntl;
Packit 1f69a5
          }
Packit 1f69a5
          gst_tag_list_unref (tl);
Packit 1f69a5
        }
Packit 1f69a5
      }
Packit 1f69a5
      break;
Packit 1f69a5
    }
Packit 1f69a5
    default:
Packit 1f69a5
      break;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  return TRUE;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
/*
Packit 1f69a5
 * Creates a pipeline in the form:
Packit 1f69a5
 * fakesrc num-buffers=1 ! caps ! muxer ! filesink location=file
Packit 1f69a5
 *
Packit 1f69a5
 * And sets the tags in tag_str into the muxer via tagsetter.
Packit 1f69a5
 */
Packit 1f69a5
static void
Packit 1f69a5
test_mux_tags (const gchar * tag_str, const gchar * caps,
Packit 1f69a5
    const gchar * muxer, const gchar * file)
Packit 1f69a5
{
Packit 1f69a5
  GstElement *pipeline;
Packit 1f69a5
  GstBus *bus;
Packit 1f69a5
  GMainLoop *loop;
Packit 1f69a5
  GstTagList *sent_tags;
Packit 1f69a5
  GstElement *mux;
Packit 1f69a5
  GstTagSetter *setter;
Packit 1f69a5
  gchar *launch_str;
Packit 1f69a5
  guint bus_watch = 0;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG ("testing xmp muxing on : %s", muxer);
Packit 1f69a5
Packit 1f69a5
  launch_str =
Packit 1f69a5
      g_strdup_printf ("fakesrc num-buffers=1 format=time datarate=100 ! "
Packit 1f69a5
      "%s ! %s name=mux ! filesink location=%s name=sink", caps, muxer, file);
Packit 1f69a5
  pipeline = gst_parse_launch (launch_str, NULL);
Packit 1f69a5
  g_free (launch_str);
Packit 1f69a5
  fail_unless (pipeline != NULL);
Packit 1f69a5
Packit 1f69a5
  mux = gst_bin_get_by_name (GST_BIN (pipeline), "mux");
Packit 1f69a5
  fail_unless (mux != NULL);
Packit 1f69a5
Packit 1f69a5
  loop = g_main_loop_new (NULL, TRUE);
Packit 1f69a5
  fail_unless (loop != NULL);
Packit 1f69a5
Packit 1f69a5
  bus = gst_element_get_bus (pipeline);
Packit 1f69a5
  fail_unless (bus != NULL);
Packit 1f69a5
  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
Packit 1f69a5
  gst_object_unref (bus);
Packit 1f69a5
Packit 1f69a5
  gst_element_set_state (pipeline, GST_STATE_READY);
Packit 1f69a5
Packit 1f69a5
  setter = GST_TAG_SETTER (mux);
Packit 1f69a5
  fail_unless (setter != NULL);
Packit 1f69a5
  sent_tags = gst_tag_list_new_from_string (tag_str);
Packit 1f69a5
  fail_unless (sent_tags != NULL);
Packit 1f69a5
  gst_tag_setter_merge_tags (setter, sent_tags, GST_TAG_MERGE_REPLACE);
Packit 1f69a5
  gst_tag_list_unref (sent_tags);
Packit 1f69a5
Packit 1f69a5
  gst_element_set_state (pipeline, GST_STATE_PLAYING);
Packit 1f69a5
  g_main_loop_run (loop);
Packit 1f69a5
Packit 1f69a5
  gst_element_set_state (pipeline, GST_STATE_NULL);
Packit 1f69a5
Packit 1f69a5
  g_main_loop_unref (loop);
Packit 1f69a5
  g_object_unref (mux);
Packit 1f69a5
  g_object_unref (pipeline);
Packit 1f69a5
  g_source_remove (bus_watch);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
/*
Packit 1f69a5
 * Makes a pipeline in the form:
Packit 1f69a5
 * filesrc location=file ! demuxer ! fakesink
Packit 1f69a5
 *
Packit 1f69a5
 * And gets the tags that are posted on the bus to compare
Packit 1f69a5
 * with the tags in 'tag_str'
Packit 1f69a5
 */
Packit 1f69a5
static void
Packit 1f69a5
test_demux_tags (const gchar * tag_str, const gchar * demuxer,
Packit 1f69a5
    const gchar * file)
Packit 1f69a5
{
Packit 1f69a5
  GstElement *pipeline;
Packit 1f69a5
  GstBus *bus;
Packit 1f69a5
  GMainLoop *loop;
Packit 1f69a5
  GstTagList *sent_tags;
Packit 1f69a5
  gint i, j, k, n_recv, n_sent;
Packit 1f69a5
  const gchar *name_sent, *name_recv;
Packit 1f69a5
  const GValue *value_sent, *value_recv;
Packit 1f69a5
  gboolean found;
Packit 1f69a5
  gint comparison;
Packit 1f69a5
  GstElement *demux;
Packit 1f69a5
  gchar *launch_str;
Packit 1f69a5
  guint bus_watch = 0;
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG ("testing tags : %s", tag_str);
Packit 1f69a5
Packit 1f69a5
  if (received_tags) {
Packit 1f69a5
    gst_tag_list_unref (received_tags);
Packit 1f69a5
    received_tags = NULL;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  launch_str = g_strdup_printf ("filesrc location=%s ! %s name=demux ! "
Packit 1f69a5
      "fakesink", file, demuxer);
Packit 1f69a5
  pipeline = gst_parse_launch (launch_str, NULL);
Packit 1f69a5
  g_free (launch_str);
Packit 1f69a5
  fail_unless (pipeline != NULL);
Packit 1f69a5
Packit 1f69a5
  demux = gst_bin_get_by_name (GST_BIN (pipeline), "demux");
Packit 1f69a5
  fail_unless (demux != NULL);
Packit 1f69a5
Packit 1f69a5
  loop = g_main_loop_new (NULL, TRUE);
Packit 1f69a5
  fail_unless (loop != NULL);
Packit 1f69a5
Packit 1f69a5
  bus = gst_element_get_bus (pipeline);
Packit 1f69a5
  fail_unless (bus != NULL);
Packit 1f69a5
  bus_watch = gst_bus_add_watch (bus, bus_handler, loop);
Packit 1f69a5
  gst_object_unref (bus);
Packit 1f69a5
Packit 1f69a5
  sent_tags = gst_tag_list_new_from_string (tag_str);
Packit 1f69a5
  fail_unless (sent_tags != NULL);
Packit 1f69a5
Packit 1f69a5
  gst_element_set_state (pipeline, GST_STATE_PLAYING);
Packit 1f69a5
  g_main_loop_run (loop);
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG ("mainloop done : %p", received_tags);
Packit 1f69a5
Packit 1f69a5
  /* verify tags */
Packit 1f69a5
  fail_unless (received_tags != NULL);
Packit 1f69a5
  n_recv = gst_tag_list_n_tags (received_tags);
Packit 1f69a5
  n_sent = gst_tag_list_n_tags (sent_tags);
Packit 1f69a5
  fail_unless (n_recv >= n_sent);
Packit 1f69a5
  /* FIXME: compare taglits values */
Packit 1f69a5
  for (i = 0; i < n_sent; i++) {
Packit 1f69a5
    name_sent = gst_tag_list_nth_tag_name (sent_tags, i);
Packit 1f69a5
Packit 1f69a5
    found = FALSE;
Packit 1f69a5
    for (j = 0; j < n_recv; j++) {
Packit 1f69a5
      name_recv = gst_tag_list_nth_tag_name (received_tags, j);
Packit 1f69a5
Packit 1f69a5
      if (!strcmp (name_sent, name_recv)) {
Packit 1f69a5
        guint sent_len, recv_len;
Packit 1f69a5
Packit 1f69a5
        sent_len = gst_tag_list_get_tag_size (sent_tags, name_sent);
Packit 1f69a5
        recv_len = gst_tag_list_get_tag_size (received_tags, name_recv);
Packit 1f69a5
Packit 1f69a5
        fail_unless (sent_len == recv_len,
Packit 1f69a5
            "tag item %s has been received with different size", name_sent);
Packit 1f69a5
Packit 1f69a5
        for (k = 0; k < sent_len; k++) {
Packit 1f69a5
          value_sent = gst_tag_list_get_value_index (sent_tags, name_sent, k);
Packit 1f69a5
          value_recv =
Packit 1f69a5
              gst_tag_list_get_value_index (received_tags, name_recv, k);
Packit 1f69a5
Packit 1f69a5
          comparison = gst_value_compare (value_sent, value_recv);
Packit 1f69a5
          if (comparison != GST_VALUE_EQUAL) {
Packit 1f69a5
            gchar *vs = g_strdup_value_contents (value_sent);
Packit 1f69a5
            gchar *vr = g_strdup_value_contents (value_recv);
Packit 1f69a5
            GST_DEBUG ("sent = %s:'%s', recv = %s:'%s'",
Packit 1f69a5
                G_VALUE_TYPE_NAME (value_sent), vs,
Packit 1f69a5
                G_VALUE_TYPE_NAME (value_recv), vr);
Packit 1f69a5
            g_free (vs);
Packit 1f69a5
            g_free (vr);
Packit 1f69a5
          }
Packit 1f69a5
          fail_unless (comparison == GST_VALUE_EQUAL,
Packit 1f69a5
              "tag item %s has been received with different type or value",
Packit 1f69a5
              name_sent);
Packit 1f69a5
          found = TRUE;
Packit 1f69a5
          break;
Packit 1f69a5
        }
Packit 1f69a5
      }
Packit 1f69a5
    }
Packit 1f69a5
    fail_unless (found, "tag item %s is lost", name_sent);
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  gst_tag_list_unref (received_tags);
Packit 1f69a5
  received_tags = NULL;
Packit 1f69a5
  gst_tag_list_unref (sent_tags);
Packit 1f69a5
Packit 1f69a5
  gst_element_set_state (pipeline, GST_STATE_NULL);
Packit 1f69a5
Packit 1f69a5
  g_main_loop_unref (loop);
Packit 1f69a5
  g_object_unref (demux);
Packit 1f69a5
  g_object_unref (pipeline);
Packit 1f69a5
  g_source_remove (bus_watch);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
/*
Packit 1f69a5
 * Tests if the muxer/demuxer pair can serialize the tags in 'tag_str'
Packit 1f69a5
 * to a file and recover them correctly.
Packit 1f69a5
 *
Packit 1f69a5
 * 'caps' are used to assure the muxer accepts the fake buffer fakesrc
Packit 1f69a5
 * will send to it.
Packit 1f69a5
 */
Packit 1f69a5
static void
Packit 1f69a5
test_tags (const gchar * tag_str, const gchar * caps, const gchar * muxer,
Packit 1f69a5
    const gchar * demuxer)
Packit 1f69a5
{
Packit 1f69a5
  gchar *tmpfile;
Packit 1f69a5
  gchar *tmpdir;
Packit 1f69a5
Packit 1f69a5
  tmpdir = g_dir_make_tmp ("gst-check-good-XXXXXX", NULL);
Packit 1f69a5
  fail_unless (tmpdir != NULL);
Packit 1f69a5
  tmpfile = g_build_filename (tmpdir, "tagschecking-xmp", NULL);
Packit 1f69a5
Packit 1f69a5
  GST_DEBUG ("testing tags : %s", tag_str);
Packit 1f69a5
  test_mux_tags (tag_str, caps, muxer, tmpfile);
Packit 1f69a5
  test_demux_tags (tag_str, demuxer, tmpfile);
Packit 1f69a5
  g_unlink (tmpfile);
Packit 1f69a5
  g_rmdir (tmpdir);
Packit 1f69a5
  g_free (tmpfile);
Packit 1f69a5
  g_free (tmpdir);
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
#define H264_CAPS "video/x-h264, width=(int)320, height=(int)240," \
Packit 1f69a5
                  " framerate=(fraction)30/1, codec_data=(buffer)" \
Packit 1f69a5
                  "01401592ffe10017674d401592540a0fd8088000000300" \
Packit 1f69a5
                  "8000001e478b175001000468ee3c80, "\
Packit 1f69a5
                  "stream-format=(string)avc, alignment=(string)au"
Packit 1f69a5
Packit 1f69a5
#define COMMON_TAGS \
Packit 1f69a5
    "taglist,title=test_title,"    \
Packit 1f69a5
    "artist=test_artist,"          \
Packit 1f69a5
    "keywords=\"key1,key2\","      \
Packit 1f69a5
    "description=test_desc"
Packit 1f69a5
Packit 1f69a5
GST_START_TEST (test_common_tags)
Packit 1f69a5
{
Packit 1f69a5
  if (!gst_registry_check_feature_version (gst_registry_get (), "qtdemux", 0,
Packit 1f69a5
          10, 23)) {
Packit 1f69a5
    GST_INFO ("Skipping test, qtdemux either not available or too old");
Packit 1f69a5
    return;
Packit 1f69a5
  }
Packit 1f69a5
  test_tags (COMMON_TAGS, H264_CAPS, "qtmux", "qtdemux");
Packit 1f69a5
  test_tags (COMMON_TAGS, H264_CAPS, "mp4mux", "qtdemux");
Packit 1f69a5
  test_tags (COMMON_TAGS, H264_CAPS, "3gppmux", "qtdemux");
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
GST_END_TEST;
Packit 1f69a5
Packit 1f69a5
#define GEO_LOCATION_TAGS \
Packit 1f69a5
    "taglist,geo-location-country=Brazil,"    \
Packit 1f69a5
      "geo-location-city=\"Campina Grande\"," \
Packit 1f69a5
      "geo-location-sublocation=Bodocongo,"   \
Packit 1f69a5
      "geo-location-latitude=-12.125,"        \
Packit 1f69a5
      "geo-location-longitude=56.75,"         \
Packit 1f69a5
      "geo-location-elevation=327.5"
Packit 1f69a5
Packit 1f69a5
GST_START_TEST (test_geo_location_tags)
Packit 1f69a5
{
Packit 1f69a5
  if (!gst_registry_check_feature_version (gst_registry_get (), "qtdemux", 0,
Packit 1f69a5
          10, 23)) {
Packit 1f69a5
    GST_INFO ("Skipping test, qtdemux either not available or too old");
Packit 1f69a5
    return;
Packit 1f69a5
  }
Packit 1f69a5
  test_tags (GEO_LOCATION_TAGS, H264_CAPS, "qtmux", "qtdemux");
Packit 1f69a5
  test_tags (GEO_LOCATION_TAGS, H264_CAPS, "mp4mux", "qtdemux");
Packit 1f69a5
  test_tags (GEO_LOCATION_TAGS, H264_CAPS, "3gppmux", "qtdemux");
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
GST_END_TEST;
Packit 1f69a5
Packit 1f69a5
Packit 1f69a5
#define USER_TAGS \
Packit 1f69a5
    "taglist,user-rating=(uint)85"
Packit 1f69a5
Packit 1f69a5
GST_START_TEST (test_user_tags)
Packit 1f69a5
{
Packit 1f69a5
  if (!gst_registry_check_feature_version (gst_registry_get (), "qtdemux", 0,
Packit 1f69a5
          10, 23)) {
Packit 1f69a5
    GST_INFO ("Skipping test, qtdemux either not available or too old");
Packit 1f69a5
    return;
Packit 1f69a5
  }
Packit 1f69a5
Packit 1f69a5
  test_tags (USER_TAGS, H264_CAPS, "qtmux", "qtdemux");
Packit 1f69a5
  test_tags (USER_TAGS, H264_CAPS, "mp4mux", "qtdemux");
Packit 1f69a5
  test_tags (USER_TAGS, H264_CAPS, "3gppmux", "qtdemux");
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
GST_END_TEST;
Packit 1f69a5
Packit 1f69a5
static Suite *
Packit 1f69a5
metadata_suite (void)
Packit 1f69a5
{
Packit 1f69a5
  Suite *s = suite_create ("tagschecking");
Packit 1f69a5
Packit 1f69a5
  TCase *tc_chain = tcase_create ("general");
Packit 1f69a5
Packit 1f69a5
  /* time out after 60s, not the default 3 */
Packit 1f69a5
  tcase_set_timeout (tc_chain, 60);
Packit 1f69a5
Packit 1f69a5
  suite_add_tcase (s, tc_chain);
Packit 1f69a5
  tcase_add_test (tc_chain, test_common_tags);
Packit 1f69a5
  tcase_add_test (tc_chain, test_geo_location_tags);
Packit 1f69a5
  tcase_add_test (tc_chain, test_user_tags);
Packit 1f69a5
Packit 1f69a5
  return s;
Packit 1f69a5
}
Packit 1f69a5
Packit 1f69a5
GST_CHECK_MAIN (metadata);