[longomatch] First attempt to write a gstreamer remuxer
- From: Andoni Morales Alastruey <amorales src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [longomatch] First attempt to write a gstreamer remuxer
- Date: Thu, 4 Oct 2012 23:30:54 +0000 (UTC)
commit fe37b459cd0a8072b829541728d0afa39de908b1
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date: Fri Oct 5 01:29:51 2012 +0200
First attempt to write a gstreamer remuxer
libcesarplayer/Makefile.am | 2 +
libcesarplayer/gst-remuxer.c | 602 +++++++++++++++++++++++++++++++++++++++++
libcesarplayer/gst-remuxer.h | 66 +++++
libcesarplayer/test-remuxer.c | 71 +++++
4 files changed, 741 insertions(+), 0 deletions(-)
---
diff --git a/libcesarplayer/Makefile.am b/libcesarplayer/Makefile.am
index ccc8b06..94f6a2d 100644
--- a/libcesarplayer/Makefile.am
+++ b/libcesarplayer/Makefile.am
@@ -37,6 +37,8 @@ libcesarplayer_la_SOURCES = \
gstscreenshot.h \
gst-camera-capturer.c\
gst-camera-capturer.h\
+ gst-remuxer.c\
+ gst-remuxer.h\
gst-video-editor.c\
gst-video-editor.h\
bacon-resize.c\
diff --git a/libcesarplayer/gst-remuxer.c b/libcesarplayer/gst-remuxer.c
new file mode 100644
index 0000000..7006365
--- /dev/null
+++ b/libcesarplayer/gst-remuxer.c
@@ -0,0 +1,602 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+* Gstreamer Remuxer
+* Copyright (C) Andoni Morales Alastruey 2012 <ylatuya gmail com>
+*
+* LongoMatch is free software.
+*
+* You may redistribute it and/or modify it under the terms of the
+* GNU General Public License, as published by the Free Software
+* Foundation; either version 2 of the License, or (at your option)
+* any later version.
+*
+* LongoMatch is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with foob. If not, write to:
+* The Free Software Foundation, Inc.,
+* 51 Franklin Street, Fifth Floor
+* Boston, MA 02110-1301, USA.
+*/
+
+#include <string.h>
+#include <stdio.h>
+
+#include <gst/gst.h>
+
+#include "gst-remuxer.h"
+
+GST_DEBUG_CATEGORY (_cesarplayer_gst_debug_cat);
+#define GST_CAT_DEFAULT _cesarplayer_gst_debug_cat
+
+/* Signals */
+enum
+{
+ SIGNAL_ERROR,
+ SIGNAL_PERCENT,
+ LAST_SIGNAL
+};
+
+struct GstRemuxerPrivate
+{
+
+ /*Encoding properties */
+ gchar *input_file;
+ gchar *output_file;
+ VideoMuxerType video_muxer_type;
+
+ /* Remuxer */
+ GstClockTime last_video_buf_ts;
+ GstClockTime last_audio_buf_ts;
+ gboolean audio_linked;
+ gboolean video_linked;
+
+ /*GStreamer elements */
+ GstElement *main_pipeline;
+
+ /*GStreamer bus */
+ GstBus *bus;
+ gulong sig_bus_async;
+};
+
+static GObject *parent_class = NULL;
+
+static int remuxer_signals[LAST_SIGNAL] = { 0 };
+
+static void remuxer_error_msg (GstRemuxer * remuxer, GstMessage * msg);
+static void remuxer_bus_message_cb (GstBus * bus, GstMessage * message,
+ gpointer data);
+
+G_DEFINE_TYPE (GstRemuxer, gst_remuxer, G_TYPE_OBJECT);
+
+/***********************************
+*
+* Class, Object and Properties
+*
+************************************/
+
+static void
+gst_remuxer_init (GstRemuxer * object)
+{
+ GstRemuxerPrivate *priv;
+ object->priv = priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (object, GST_TYPE_REMUXER,
+ GstRemuxerPrivate);
+
+ priv->input_file = NULL;
+ priv->output_file = NULL;
+ priv->last_video_buf_ts = GST_CLOCK_TIME_NONE;
+ priv->last_audio_buf_ts = GST_CLOCK_TIME_NONE;
+ priv->video_muxer_type = VIDEO_MUXER_WEBM;
+ priv->audio_linked = FALSE;
+ priv->video_linked = FALSE;
+}
+
+void
+gst_remuxer_finalize (GObject * object)
+{
+ GstRemuxer *remuxer = (GstRemuxer *) object;
+
+ GST_DEBUG_OBJECT (remuxer, "Finalizing.");
+ if (remuxer->priv->bus) {
+ /* make bus drop all messages to make sure none of our callbacks is ever
+ * called again (main loop might be run again to display error dialog) */
+ gst_bus_set_flushing (remuxer->priv->bus, TRUE);
+
+ if (remuxer->priv->sig_bus_async)
+ g_signal_handler_disconnect (remuxer->priv->bus, remuxer->priv->sig_bus_async);
+
+ gst_object_unref (remuxer->priv->bus);
+ remuxer->priv->bus = NULL;
+ }
+
+ if (remuxer->priv->input_file) {
+ g_free (remuxer->priv->input_file);
+ remuxer->priv->input_file = NULL;
+ }
+
+ if (remuxer->priv->output_file) {
+ g_free (remuxer->priv->output_file);
+ remuxer->priv->output_file = NULL;
+ }
+
+ if (remuxer->priv->main_pipeline != NULL
+ && GST_IS_ELEMENT (remuxer->priv->main_pipeline)) {
+ gst_element_set_state (remuxer->priv->main_pipeline,
+ GST_STATE_NULL);
+ gst_object_unref (remuxer->priv->main_pipeline);
+ remuxer->priv->main_pipeline = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_remuxer_class_init (GstRemuxerClass * klass)
+{
+ GObjectClass *object_class;
+
+ object_class = (GObjectClass *) klass;
+ parent_class = g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (object_class, sizeof (GstRemuxerPrivate));
+
+ object_class->finalize = gst_remuxer_finalize;
+
+ /* Signals */
+ remuxer_signals[SIGNAL_ERROR] =
+ g_signal_new ("error",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstRemuxerClass, error),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ remuxer_signals[SIGNAL_PERCENT] =
+ g_signal_new ("percent-completed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GstRemuxerClass, percent_completed),
+ NULL, NULL, g_cclosure_marshal_VOID__FLOAT, G_TYPE_NONE, 1, G_TYPE_FLOAT);
+}
+
+/***********************************
+*
+* GStreamer
+*
+************************************/
+
+void
+gst_remuxer_init_backend (int *argc, char ***argv)
+{
+ gst_init (argc, argv);
+}
+
+GQuark
+gst_remuxer_error_quark (void)
+{
+ static GQuark q; /* 0 */
+
+ if (G_UNLIKELY (q == 0)) {
+ q = g_quark_from_static_string ("remuxer-error-quark");
+ }
+ return q;
+}
+
+
+/*static gboolean*/
+/*gst_remuxer_encoding_retimestamper (GstRemuxer *remuxer,*/
+ /*GstBuffer *prev_buf, gboolean is_video)*/
+/*{*/
+ /*GstClockTime buf_ts, new_buf_ts, duration;*/
+ /*GstBuffer *enc_buf;*/
+
+ /*g_mutex_lock(remuxer->priv->recording_lock);*/
+
+ /*if (!remuxer->priv->is_recording) {*/
+ /*[> Drop buffers if we are not recording <]*/
+ /*GST_LOG_OBJECT (remuxer, "Dropping buffer on %s pad", is_video ? "video": "audio");*/
+ /*goto done;*/
+ /*}*/
+
+ /*[> If we are just remuxing, drop everything until we see a keyframe <]*/
+ /*if (remuxer->priv->video_needs_keyframe_sync && !remuxer->priv->video_synced) {*/
+ /*if (is_video && !GST_BUFFER_FLAG_IS_SET(prev_buf, GST_BUFFER_FLAG_DELTA_UNIT)) {*/
+ /*remuxer->priv->video_synced = TRUE;*/
+ /*} else {*/
+ /*GST_LOG_OBJECT (remuxer, "Waiting for a keyframe, "*/
+ /*"dropping buffer on %s pad", is_video ? "video": "audio");*/
+ /*goto done;*/
+ /*}*/
+ /*}*/
+
+ /*enc_buf = gst_buffer_create_sub (prev_buf, 0, GST_BUFFER_SIZE(prev_buf));*/
+ /*buf_ts = GST_BUFFER_TIMESTAMP (prev_buf);*/
+ /*duration = GST_BUFFER_DURATION (prev_buf);*/
+ /*if (duration == GST_CLOCK_TIME_NONE)*/
+ /*duration = 0;*/
+
+ /* Check if it's the first buffer after starting or restarting the capture
+ * and update the timestamps accordingly */
+ /*if (G_UNLIKELY(remuxer->priv->current_recording_start_ts == GST_CLOCK_TIME_NONE)) {*/
+ /*remuxer->priv->current_recording_start_ts = buf_ts;*/
+ /*remuxer->priv->last_accum_recorded_ts = remuxer->priv->accum_recorded_ts;*/
+ /*GST_INFO_OBJECT (remuxer, "Starting recording at %" GST_TIME_FORMAT,*/
+ /*GST_TIME_ARGS(remuxer->priv->last_accum_recorded_ts));*/
+ /*}*/
+
+ /*[> Clip buffers that are not in the segment <]*/
+ /*if (buf_ts < remuxer->priv->current_recording_start_ts) {*/
+ /*GST_WARNING_OBJECT (remuxer, "Discarding buffer out of segment");*/
+ /*goto done;*/
+ /*}*/
+
+ /*if (buf_ts != GST_CLOCK_TIME_NONE) {*/
+ /* Get the buffer timestamp with respect of the encoding time and not
+ * the playing time for a continous stream in the encoders input */
+ /*new_buf_ts = buf_ts - remuxer->priv->current_recording_start_ts + remuxer->priv->last_accum_recorded_ts;*/
+
+ /*[> Store the last timestamp seen on this pad <]*/
+ /*if (is_video)*/
+ /*remuxer->priv->last_video_buf_ts = new_buf_ts;*/
+ /*else*/
+ /*remuxer->priv->last_audio_buf_ts = new_buf_ts;*/
+
+ /*[> Update the highest encoded timestamp <]*/
+ /*if (new_buf_ts + duration > remuxer->priv->accum_recorded_ts)*/
+ /*remuxer->priv->accum_recorded_ts = new_buf_ts + duration;*/
+ /*} else {*/
+ /* h264parse only sets the timestamp on the first buffer if a frame is
+ * split in several ones. Other parsers might do the same. We only set
+ * the last timestamp seen on the pad */
+ /*if (is_video)*/
+ /*new_buf_ts = remuxer->priv->last_video_buf_ts;*/
+ /*else*/
+ /*new_buf_ts = remuxer->priv->last_audio_buf_ts;*/
+ /*}*/
+
+ /*GST_BUFFER_TIMESTAMP (enc_buf) = new_buf_ts;*/
+
+ /*GST_LOG_OBJECT(remuxer, "Pushing %s frame to the encoder in ts:% " GST_TIME_FORMAT*/
+ /*" out ts: %" GST_TIME_FORMAT, is_video ? "video": "audio",*/
+ /*GST_TIME_ARGS(buf_ts), GST_TIME_ARGS(new_buf_ts));*/
+
+ /*if (is_video)*/
+ /*gst_app_src_push_buffer(GST_APP_SRC(remuxer->priv->video_appsrc), enc_buf);*/
+ /*else*/
+ /*gst_app_src_push_buffer(GST_APP_SRC(remuxer->priv->audio_appsrc), enc_buf);*/
+
+/*done:*/
+ /*{*/
+ /*g_mutex_unlock(remuxer->priv->recording_lock);*/
+ /*return TRUE;*/
+ /*}*/
+/*}*/
+
+/*
+static gboolean
+gst_remuxer_audio_encoding_probe (GstPad *pad, GstBuffer *buf,
+ GstRemuxer *remuxer)
+{
+ return gst_remuxer_encoding_retimestamper(remuxer, buf, FALSE);
+}
+
+static gboolean
+gst_remuxer_video_encoding_probe (GstPad *pad, GstBuffer *buf,
+ GstRemuxer *remuxer)
+{
+ return gst_remuxer_encoding_retimestamper(remuxer, buf, TRUE);
+}
+*/
+
+static GstElement *
+gst_remuxer_create_video_muxer (GstRemuxer * remuxer,
+ VideoMuxerType type)
+{
+ GstElement *muxer;
+
+ g_return_val_if_fail (remuxer != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_REMUXER (remuxer), FALSE);
+
+ switch (type) {
+ case VIDEO_MUXER_OGG:
+ muxer = gst_element_factory_make ("oggmux", "muxer");
+ break;
+ case VIDEO_MUXER_AVI:
+ muxer = gst_element_factory_make ("avimux", "muxer");
+ break;
+ case VIDEO_MUXER_MATROSKA:
+ muxer = gst_element_factory_make ("matroskamux", "muxer");
+ break;
+ case VIDEO_MUXER_MP4:
+ muxer = gst_element_factory_make ("qtmux", "muxer");
+ break;
+ case VIDEO_MUXER_WEBM:
+ default:
+ muxer = gst_element_factory_make ("webmmux", "muxer");
+ break;
+ }
+
+ return muxer;
+}
+
+static gboolean
+gst_remuxer_fix_video_ts (GstPad *pad, GstBuffer *buf, GstRemuxer *remuxer)
+{
+ if (GST_BUFFER_TIMESTAMP (buf) == GST_CLOCK_TIME_NONE) {
+ GST_BUFFER_TIMESTAMP (buf) = remuxer->priv->last_video_buf_ts;
+ } else {
+ remuxer->priv->last_video_buf_ts = GST_BUFFER_TIMESTAMP (buf);
+ }
+}
+
+static gboolean
+gst_remuxer_pad_added_cb (GstElement *demuxer, GstPad *pad,
+ GstRemuxer *remuxer)
+{
+ GstElement *muxer, *queue;
+ GstElement *parser = NULL;
+ GstPad *muxer_pad, *queue_sink_pad, *queue_src_pad;
+ GstCaps *caps, *parser_caps = NULL;
+ const GstStructure *s;
+ gchar *muxer_pad_name = NULL;
+ const gchar *mime;
+
+ caps = gst_pad_get_caps_reffed (pad);
+ s = gst_caps_get_structure (caps, 0);
+ mime = gst_structure_get_name (s);
+ GST_INFO_OBJECT (remuxer, "Found mime type: %s", mime);
+
+ if (g_strrstr (mime, "video") && !remuxer->priv->video_linked) {
+ muxer_pad_name = "video_%d";
+ if (g_strrstr (mime, "video/x-h264")) {
+ GstPad *parser_pad;
+
+ parser = gst_element_factory_make("h264parse", "video-parser");
+ parser_caps = gst_caps_from_string("video/x-h264, stream-format=avc, alignment=au");
+
+ parser_pad = gst_element_get_static_pad (parser, "src");
+ gst_pad_add_buffer_probe (parser_pad, (GCallback)gst_remuxer_fix_video_ts, remuxer);
+ }
+ remuxer->priv->video_linked = TRUE;
+ } else if (g_strrstr (mime, "audio") && !remuxer->priv->audio_linked) {
+ muxer_pad_name = "audio_%d";
+ if (g_strrstr (mime, "audio/mpeg")) {
+ gint version;
+ gst_structure_get_int (s, "mpegversion", &version);
+ if (version == 4) {
+ /* FIXME: aacparse doesn't seem to support adts to raw conversion */
+ parser = gst_parse_bin_from_description ("faad ! faac", TRUE, NULL);
+ } else if (version == 3) {
+ parser = gst_element_factory_make("mp3parse", "audio-parser");
+ } else {
+ parser = gst_element_factory_make("mpegaudioparse", "audio-parser");
+ }
+ } else if (g_strrstr (mime, "audio/x-eac3")) {
+ parser = gst_parse_bin_from_description ("ffdec_eac3 ! faac", TRUE, NULL);
+ } else if (g_strrstr (mime, "audio/x-ac3")) {
+ parser = gst_parse_bin_from_description ("ffdec_ac3 ! faac", TRUE, NULL);
+ }
+ remuxer->priv->audio_linked = TRUE;
+ }
+
+ if (muxer_pad_name == NULL) {
+ gst_caps_unref (caps);
+ return TRUE;
+ }
+
+ muxer = gst_bin_get_by_name (GST_BIN(remuxer->priv->main_pipeline), "muxer");
+ if (parser != NULL) {
+ gst_bin_add (GST_BIN(remuxer->priv->main_pipeline), parser);
+ gst_element_set_state (parser, GST_STATE_PLAYING);
+ if (parser_caps) {
+ gst_element_link_filtered (parser, muxer, parser_caps);
+ gst_caps_unref (parser_caps);
+ } else {
+ gst_element_link (parser, muxer);
+ }
+ muxer_pad = gst_element_get_static_pad (parser, "sink");
+ } else {
+ muxer_pad = gst_element_get_compatible_pad (muxer, pad, caps);
+ }
+
+ queue = gst_element_factory_make ("queue2", NULL);
+ gst_bin_add (GST_BIN(remuxer->priv->main_pipeline), queue);
+ gst_element_set_state (queue, GST_STATE_PLAYING);
+ queue_sink_pad = gst_element_get_static_pad (queue, "sink");
+ queue_src_pad = gst_element_get_static_pad (queue, "src");
+
+ gst_pad_link (pad, queue_sink_pad);
+ gst_pad_link (queue_src_pad, muxer_pad);
+
+ gst_object_unref (muxer);
+ gst_object_unref (queue_sink_pad);
+ gst_object_unref (queue_src_pad);
+
+ gst_caps_unref (caps);
+ return TRUE;
+}
+
+static gboolean
+gst_remuxer_have_type_cb (GstElement *typefind, guint prob,
+ GstCaps *caps, GstRemuxer *remuxer)
+{
+ GstElement *demuxer = NULL;
+ const gchar *mime;
+
+ mime = gst_structure_get_name (gst_caps_get_structure (caps, 0));
+ GST_INFO_OBJECT (remuxer, "Found mime type: %s", mime);
+
+ if (g_strrstr (mime, "video/mpegts")) {
+ demuxer = gst_element_factory_make("tsdemux", NULL);
+ }
+
+ if (demuxer) {
+ gst_bin_add (GST_BIN(remuxer->priv->main_pipeline), demuxer);
+ gst_element_link (typefind, demuxer);
+ g_signal_connect (demuxer, "pad-added",
+ G_CALLBACK (gst_remuxer_pad_added_cb), remuxer);
+ } else {
+ gchar *msg;
+
+ msg = g_strdup_printf ("File with mime type %s is not supported", mime);
+ g_signal_emit (remuxer, remuxer_signals[SIGNAL_ERROR], 0, msg);
+ g_free (msg);
+ gst_remuxer_cancel (remuxer);
+ }
+
+ return TRUE;
+}
+
+static void
+gst_remuxer_initialize (GstRemuxer *remuxer)
+{
+ GstElement *filesrc, *typefind, *muxer, *filesink;
+
+ GST_INFO_OBJECT (remuxer, "Initializing pipeline");
+
+ /* Create elements */
+ remuxer->priv->main_pipeline = gst_pipeline_new ("pipeline");
+
+ filesrc = gst_element_factory_make("filesrc", "source");
+ typefind = gst_element_factory_make("typefind", "typefind");
+ muxer = gst_remuxer_create_video_muxer (remuxer, remuxer->priv->video_muxer_type);
+ filesink = gst_element_factory_make("filesink", "sink");
+
+ /* Set properties */
+ g_object_set (filesrc, "location", remuxer->priv->input_file, NULL);
+ g_object_set (filesink, "location", remuxer->priv->output_file, NULL);
+
+ /* Add elements to the bin */
+ gst_bin_add_many(GST_BIN(remuxer->priv->main_pipeline), filesrc, typefind,
+ muxer, filesink, NULL);
+ gst_element_link(filesrc, typefind);
+ gst_element_link(muxer, filesink);
+
+ g_signal_connect (typefind, "have-type",
+ G_CALLBACK (gst_remuxer_have_type_cb), remuxer);
+}
+
+
+static void
+remuxer_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
+{
+ GstRemuxer *remuxer = (GstRemuxer *) data;
+ GstMessageType msg_type;
+
+ g_return_if_fail (remuxer != NULL);
+ g_return_if_fail (GST_IS_REMUXER (remuxer));
+
+ msg_type = GST_MESSAGE_TYPE (message);
+
+ switch (msg_type) {
+ case GST_MESSAGE_ERROR:
+ {
+ if (remuxer->priv->main_pipeline) {
+ gst_remuxer_cancel (remuxer);
+ }
+ remuxer_error_msg (remuxer, message);
+ break;
+ }
+
+ case GST_MESSAGE_WARNING:
+ {
+ GST_WARNING ("Warning message: %" GST_PTR_FORMAT, message);
+ break;
+ }
+
+ case GST_MESSAGE_EOS:
+ {
+ GST_INFO_OBJECT (remuxer, "EOS message");
+ g_signal_emit (remuxer, remuxer_signals[SIGNAL_PERCENT], 0, (gfloat) 1);
+ break;
+ }
+
+ default:
+ GST_LOG ("Unhandled message: %" GST_PTR_FORMAT, message);
+ break;
+ }
+}
+
+static void
+remuxer_error_msg (GstRemuxer * remuxer, GstMessage * msg)
+{
+ GError *err = NULL;
+ gchar *dbg = NULL;
+
+ gst_message_parse_error (msg, &err, &dbg);
+ if (err) {
+ GST_ERROR ("message = %s", GST_STR_NULL (err->message));
+ GST_ERROR ("domain = %d (%s)", err->domain,
+ GST_STR_NULL (g_quark_to_string (err->domain)));
+ GST_ERROR ("code = %d", err->code);
+ GST_ERROR ("debug = %s", GST_STR_NULL (dbg));
+ GST_ERROR ("source = %" GST_PTR_FORMAT, msg->src);
+
+
+ g_message ("Error: %s\n%s\n", GST_STR_NULL (err->message),
+ GST_STR_NULL (dbg));
+ g_signal_emit (remuxer, remuxer_signals[SIGNAL_ERROR], 0, err->message);
+ g_error_free (err);
+ }
+ g_free (dbg);
+}
+
+/*******************************************
+ *
+ * Public methods
+ *
+ * ****************************************/
+
+void
+gst_remuxer_start (GstRemuxer * remuxer)
+{
+ g_return_if_fail (remuxer != NULL);
+ g_return_if_fail (GST_IS_REMUXER (remuxer));
+
+ gst_element_set_state (remuxer->priv->main_pipeline, GST_STATE_PLAYING);
+}
+
+void
+gst_remuxer_cancel (GstRemuxer * remuxer)
+{
+ g_return_if_fail (remuxer != NULL);
+ g_return_if_fail (GST_IS_REMUXER (remuxer));
+
+ gst_element_set_state (remuxer->priv->main_pipeline, GST_STATE_NULL);
+ gst_element_get_state (remuxer->priv->main_pipeline, NULL, NULL, -1);
+}
+
+GstRemuxer *
+gst_remuxer_new (gchar * input_file, gchar *output_file, GError ** err)
+{
+ GstRemuxer *remuxer = NULL;
+
+#ifndef GST_DISABLE_GST_INFO
+ if (_cesarplayer_gst_debug_cat == NULL) {
+ GST_DEBUG_CATEGORY_INIT (_cesarplayer_gst_debug_cat, "longomatch", 0,
+ "LongoMatch GStreamer Backend");
+ }
+#endif
+
+ remuxer = g_object_new (GST_TYPE_REMUXER, NULL);
+
+ remuxer->priv->input_file = input_file;
+ remuxer->priv->output_file = output_file;
+ remuxer->priv->video_muxer_type = VIDEO_MUXER_MP4;
+
+ gst_remuxer_initialize (remuxer);
+
+ /*Connect bus signals */
+ GST_INFO_OBJECT (remuxer, "Connecting bus signals");
+ remuxer->priv->bus = gst_element_get_bus (remuxer->priv->main_pipeline);
+ gst_bus_add_signal_watch (remuxer->priv->bus);
+ remuxer->priv->sig_bus_async =
+ g_signal_connect (remuxer->priv->bus, "message",
+ G_CALLBACK (remuxer_bus_message_cb), remuxer);
+
+ return remuxer;
+}
diff --git a/libcesarplayer/gst-remuxer.h b/libcesarplayer/gst-remuxer.h
new file mode 100644
index 0000000..516d196
--- /dev/null
+++ b/libcesarplayer/gst-remuxer.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * Gstreamer DV capturer
+ * Copyright (C) Andoni Morales Alastruey 2008 <ylatuya gmail com>
+ *
+ * Gstreamer DV capturer is free software.
+ *
+ * You may redistribute it and/or modify it under the terms of the
+ * GNU General Public License, as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * foob is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with foob. If not, write to:
+ * The Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_REMUXER_H_
+#define _GST_REMUXER_H_
+
+#include <gst/gst.h>
+#include "common.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_REMUXER (gst_remuxer_get_type ())
+#define GST_REMUXER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_REMUXER, GstRemuxer))
+#define GST_REMUXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_REMUXER, GstRemuxerClass))
+#define GST_IS_REMUXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_REMUXER))
+#define GST_IS_REMUXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_REMUXER))
+#define GST_REMUXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_REMUXER, GstRemuxerClass))
+#define GCC_ERROR gst_remuxer_error_quark ()
+typedef struct _GstRemuxerClass GstRemuxerClass;
+typedef struct _GstRemuxer GstRemuxer;
+typedef struct GstRemuxerPrivate GstRemuxerPrivate;
+
+
+struct _GstRemuxerClass
+{
+ GObjectClass parent_class;
+
+ void (*percent_completed) (GstRemuxer * remuxer, gfloat *percent);
+ void (*error) (GstRemuxer * remuxer, const char *message);
+};
+
+struct _GstRemuxer
+{
+ GObject parent;
+ GstRemuxerPrivate *priv;
+};
+
+GType gst_remuxer_get_type (void) G_GNUC_CONST;
+
+void gst_remuxer_init_backend (int *argc, char ***argv);
+GstRemuxer *gst_remuxer_new (gchar *in_filename, gchar *out_filename, GError ** err);
+void gst_remuxer_start (GstRemuxer * remuxer);
+void gst_remuxer_cancel (GstRemuxer * remuxer);
+
+G_END_DECLS
+#endif /* _GST_REMUXER_H_ */
diff --git a/libcesarplayer/test-remuxer.c b/libcesarplayer/test-remuxer.c
new file mode 100644
index 0000000..27eb4f2
--- /dev/null
+++ b/libcesarplayer/test-remuxer.c
@@ -0,0 +1,71 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * main.c
+ * Copyright (C) Andoni Morales Alastruey 2008 <ylatuya gmail com>
+ *
+ * main.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * main.c is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Compile with:
+ * gcc -o test-remuxer test-remuxer.c gst-remuxer.c `pkg-config --cflags --libs gstreamer-0.10` -DOSTYPE_LINUX -O0 -g
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include "gst-remuxer.h"
+
+static gboolean
+percent_done_cb (GstRemuxer *remuxer, gfloat percent, GMainLoop *loop)
+{
+ if (percent == 1) {
+ g_print("SUCESS!\n");
+ g_main_loop_quit (loop);
+ } else {
+ g_print("----> %f%%", percent);
+ }
+}
+
+static gboolean
+error_cb (GstRemuxer *remuxer, gchar *error, GMainLoop *loop)
+{
+ g_print("ERROR: %s\n", error);
+ g_main_loop_quit (loop);
+}
+
+int
+main (int argc, char *argv[])
+{
+ GstRemuxer *remuxer;
+ GMainLoop *loop;
+
+ gst_remuxer_init_backend (&argc, &argv);
+
+ if (argc != 3) {
+ g_print("Usage: test-remuxer input_file output_file\n");
+ return 1;
+ }
+ remuxer = gst_remuxer_new (argv[1], argv[2], NULL);
+ gst_remuxer_start (remuxer);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ g_signal_connect (remuxer, "percent-completed",
+ G_CALLBACK (percent_done_cb), loop);
+ g_signal_connect (remuxer, "error",
+ G_CALLBACK (error_cb), loop);
+
+ g_main_loop_run (loop);
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]