tizen 2.0 init
[framework/multimedia/gst-plugins-good0.10.git] / tests / check / elements / qtmux.c
index a70e345..a9364c9 100644 (file)
@@ -28,6 +28,8 @@
 #include <unistd.h>
 #endif
 
+#include <glib/gstdio.h>
+
 #include <gst/check/gstcheck.h>
 #include <gst/pbutils/encoding-profile.h>
 
@@ -41,12 +43,37 @@ static GstPad *mysrcpad, *mysinkpad;
                         "layer = (int) 3, " \
                         "channels = (int) 2, " \
                         "rate = (int) 48000"
+
+#define AUDIO_AAC_CAPS_STRING "audio/mpeg, " \
+                            "mpegversion=(int)4, " \
+                            "channels=(int)1, " \
+                            "rate=(int)44100, " \
+                            "stream-format=(string)raw, " \
+                            "level=(string)2, " \
+                            "base-profile=(string)lc, " \
+                            "profile=(string)lc, " \
+                            "codec_data=(buffer)1208"
+
 #define VIDEO_CAPS_STRING "video/mpeg, " \
                            "mpegversion = (int) 4, " \
+                           "systemstream = (boolean) false, " \
                            "width = (int) 384, " \
                            "height = (int) 288, " \
                            "framerate = (fraction) 25/1"
 
+#define VIDEO_CAPS_H264_STRING "video/x-h264, " \
+                               "width=(int)320, " \
+                               "height=(int)240, " \
+                               "framerate=(fraction)30/1, " \
+                               "pixel-aspect-ratio=(fraction)1/1, " \
+                               "codec_data=(buffer)01640014ffe1001867640014a" \
+                                   "cd94141fb0110000003001773594000f14299600" \
+                                   "1000568ebecb22c, " \
+                               "stream-format=(string)avc, " \
+                               "alignment=(string)au, " \
+                               "level=(string)2, " \
+                               "profile=(string)high"
+
 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
@@ -56,11 +83,22 @@ static GstStaticPadTemplate srcvideotemplate = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (VIDEO_CAPS_STRING));
 
+static GstStaticPadTemplate srcvideoh264template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CAPS_H264_STRING));
+
 static GstStaticPadTemplate srcaudiotemplate = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS (AUDIO_CAPS_STRING));
 
+static GstStaticPadTemplate srcaudioaactemplate =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (AUDIO_AAC_CAPS_STRING));
 
 /* setup and teardown needs some special handling for muxer */
 static GstPad *
@@ -517,7 +555,7 @@ create_qtmux_profile (const gchar * variant)
   return cprof;
 }
 
-GST_START_TEST (test_encodebin)
+GST_START_TEST (test_encodebin_qtmux)
 {
   GstEncodingContainerProfile *cprof;
   GstElement *enc;
@@ -553,6 +591,274 @@ GST_START_TEST (test_encodebin)
 
 GST_END_TEST;
 
+/* Fake mp3 encoder for test */
+typedef GstElement TestMp3Enc;
+typedef GstElementClass TestMp3EncClass;
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/mpeg, mpegversion=1, layer=[1,3]")
+    );
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS ("audio/x-raw-int")
+    );
+
+static GType test_mp3_enc_get_type (void);
+
+GST_BOILERPLATE (TestMp3Enc, test_mp3_enc, GstElement, GST_TYPE_ELEMENT);
+
+static void
+test_mp3_enc_base_init (gpointer klass)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+  gst_element_class_add_static_pad_template (element_class, &sink_template);
+  gst_element_class_add_static_pad_template (element_class, &src_template);
+
+  gst_element_class_set_details_simple (element_class, "MPEG1 Audio Encoder",
+      "Codec/Encoder/Audio", "Pretends to encode mp3", "Foo Bar <foo@bar.com>");
+}
+
+static void
+test_mp3_enc_class_init (TestMp3EncClass * klass)
+{
+  /* doesn't actually need to do anything for this test */
+}
+
+static void
+test_mp3_enc_init (TestMp3Enc * mp3enc, TestMp3EncClass * klass)
+{
+  GstPad *pad;
+
+  pad = gst_pad_new_from_static_template (&sink_template, "sink");
+  gst_element_add_pad (mp3enc, pad);
+
+  pad = gst_pad_new_from_static_template (&src_template, "src");
+  gst_element_add_pad (mp3enc, pad);
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "testmp3enc", GST_RANK_NONE,
+      test_mp3_enc_get_type ());
+}
+
+static GstEncodingContainerProfile *
+create_mp4mux_profile (void)
+{
+  GstEncodingContainerProfile *cprof;
+  GstCaps *caps;
+
+  caps = gst_caps_new_simple ("video/quicktime",
+      "variant", G_TYPE_STRING, "iso", NULL);
+
+  cprof = gst_encoding_container_profile_new ("Name", "blah", caps, NULL);
+  gst_caps_unref (caps);
+
+  caps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1,
+      "layer", G_TYPE_INT, 3, "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT,
+      44100, NULL);
+  gst_encoding_container_profile_add_profile (cprof,
+      GST_ENCODING_PROFILE (gst_encoding_audio_profile_new (caps, NULL, NULL,
+              1)));
+  gst_caps_unref (caps);
+
+  return cprof;
+}
+
+GST_START_TEST (test_encodebin_mp4mux)
+{
+  GstEncodingContainerProfile *cprof;
+  GstPluginFeature *feature;
+  GstElement *enc, *mux;
+  GstPad *pad;
+
+  /* need a fake mp3 encoder because mp4 only accepts encoded formats */
+  gst_plugin_register_static (GST_VERSION_MAJOR, GST_VERSION_MINOR,
+      "fakemp3enc", "fakemp3enc", plugin_init, VERSION, "LGPL",
+      "gst-plugins-good", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
+
+  feature = gst_default_registry_find_feature ("testmp3enc",
+      GST_TYPE_ELEMENT_FACTORY);
+  gst_plugin_feature_set_rank (feature, GST_RANK_PRIMARY + 100);
+
+  enc = gst_element_factory_make ("encodebin", NULL);
+  if (enc == NULL)
+    return;
+
+  /* Make sure encodebin finds mp4mux even though qtmux outputs a superset */
+  cprof = create_mp4mux_profile ();
+  g_object_set (enc, "profile", cprof, NULL);
+  gst_encoding_profile_unref (cprof);
+
+  /* should have created a pad after setting the profile */
+  pad = gst_element_get_static_pad (enc, "audio_0");
+  fail_unless (pad != NULL);
+  gst_object_unref (pad);
+
+  mux = gst_bin_get_by_interface (GST_BIN (enc), GST_TYPE_TAG_SETTER);
+  fail_unless (mux != NULL);
+  {
+    GstElementFactory *f = gst_element_get_factory (mux);
+
+    /* make sure we got mp4mux for variant=iso */
+    GST_INFO ("muxer: %s", G_OBJECT_TYPE_NAME (mux));
+    fail_unless_equals_string (GST_PLUGIN_FEATURE_NAME (f), "mp4mux");
+  }
+  gst_object_unref (mux);
+  gst_object_unref (enc);
+
+  gst_plugin_feature_set_rank (feature, GST_RANK_NONE);
+  gst_object_unref (feature);
+}
+
+GST_END_TEST;
+
+static gboolean
+extract_tags (const gchar * location, GstTagList ** taglist)
+{
+  gboolean ret = TRUE;
+  GstElement *src;
+  GstBus *bus;
+  GstElement *pipeline =
+      gst_parse_launch ("filesrc name=src ! qtdemux ! fakesink", NULL);
+
+  src = gst_bin_get_by_name (GST_BIN (pipeline), "src");
+  g_object_set (src, "location", location, NULL);
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+  fail_unless (gst_element_set_state (pipeline, GST_STATE_PLAYING)
+      != GST_STATE_CHANGE_FAILURE);
+
+  if (*taglist == NULL) {
+    *taglist = gst_tag_list_new ();
+  }
+
+  while (1) {
+    GstMessage *msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
+        GST_MESSAGE_TAG | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
+
+    if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS) {
+      gst_message_unref (msg);
+      break;
+    } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
+      ret = FALSE;
+      gst_message_unref (msg);
+      break;
+    } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_TAG) {
+      GstTagList *tags;
+
+      gst_message_parse_tag (msg, &tags);
+      gst_tag_list_insert (*taglist, tags, GST_TAG_MERGE_REPLACE);
+      gst_tag_list_free (tags);
+    }
+    gst_message_unref (msg);
+  }
+
+  gst_object_unref (bus);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (src);
+  gst_object_unref (pipeline);
+  return ret;
+}
+
+static void
+test_average_bitrate_custom (const gchar * elementname,
+    GstStaticPadTemplate * tmpl, const gchar * sinkpadname)
+{
+  gchar *location;
+  GstElement *qtmux;
+  GstElement *filesink;
+  GstBuffer *inbuffer;
+  GstCaps *caps;
+  int i;
+  gint bytes[] = { 16, 22, 12 };
+  gint64 durations[] = { GST_SECOND * 3, GST_SECOND * 5, GST_SECOND * 2 };
+  gint64 total_bytes = 0;
+  GstClockTime total_duration = 0;
+
+  location = g_strdup_printf ("%s/%s-%d", g_get_tmp_dir (), "qtmuxtest",
+      g_random_int ());
+  GST_INFO ("Using location %s for bitrate test", location);
+  qtmux = gst_check_setup_element (elementname);
+  filesink = gst_element_factory_make ("filesink", NULL);
+  g_object_set (filesink, "location", location, NULL);
+  gst_element_link (qtmux, filesink);
+  mysrcpad = setup_src_pad (qtmux, tmpl, NULL, sinkpadname);
+  fail_unless (mysrcpad != NULL);
+  gst_pad_set_active (mysrcpad, TRUE);
+
+  fail_unless (gst_element_set_state (filesink,
+          GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE,
+      "could not set filesink to playing");
+  fail_unless (gst_element_set_state (qtmux,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  for (i = 0; i < 3; i++) {
+    inbuffer = gst_buffer_new_and_alloc (bytes[i]);
+    caps = gst_caps_copy (gst_pad_get_pad_template_caps (mysrcpad));
+    gst_buffer_set_caps (inbuffer, caps);
+    gst_caps_unref (caps);
+    GST_BUFFER_TIMESTAMP (inbuffer) = total_duration;
+    GST_BUFFER_DURATION (inbuffer) = (GstClockTime) durations[i];
+    ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+
+    total_bytes += GST_BUFFER_SIZE (inbuffer);
+    total_duration += GST_BUFFER_DURATION (inbuffer);
+    fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  }
+
+  /* send eos to have moov written */
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()) == TRUE);
+
+  gst_element_set_state (qtmux, GST_STATE_NULL);
+  gst_element_set_state (filesink, GST_STATE_NULL);
+
+  gst_pad_set_active (mysrcpad, FALSE);
+  teardown_src_pad (mysrcpad);
+  gst_object_unref (filesink);
+  gst_check_teardown_element (qtmux);
+
+  /* check the bitrate tag */
+  {
+    GstTagList *taglist = NULL;
+    guint bitrate = 0;
+    guint expected;
+
+    fail_unless (extract_tags (location, &taglist));
+
+    fail_unless (gst_tag_list_get_uint (taglist, GST_TAG_BITRATE, &bitrate));
+
+    expected =
+        (guint) gst_util_uint64_scale_round ((guint64) total_bytes,
+        (guint64) 8 * GST_SECOND, (guint64) total_duration);
+    fail_unless (bitrate == expected);
+    gst_tag_list_free (taglist);
+  }
+
+  /* delete file */
+  g_unlink (location);
+  g_free (location);
+}
+
+GST_START_TEST (test_average_bitrate)
+{
+  test_average_bitrate_custom ("mp4mux", &srcaudioaactemplate, "audio_%d");
+  test_average_bitrate_custom ("mp4mux", &srcvideoh264template, "video_%d");
+
+  test_average_bitrate_custom ("qtmux", &srcaudioaactemplate, "audio_%d");
+  test_average_bitrate_custom ("qtmux", &srcvideoh264template, "video_%d");
+}
+
+GST_END_TEST;
+
+
 static Suite *
 qtmux_suite (void)
 {
@@ -581,8 +887,11 @@ qtmux_suite (void)
   tcase_add_test (tc_chain, test_video_pad_frag_asc_streamable);
   tcase_add_test (tc_chain, test_audio_pad_frag_asc_streamable);
 
+  tcase_add_test (tc_chain, test_average_bitrate);
+
   tcase_add_test (tc_chain, test_reuse);
-  tcase_add_test (tc_chain, test_encodebin);
+  tcase_add_test (tc_chain, test_encodebin_qtmux);
+  tcase_add_test (tc_chain, test_encodebin_mp4mux);
 
   return s;
 }