352 lines
12 KiB
C
352 lines
12 KiB
C
/*------------------------------------------------------------------------------
|
|
|
|
Copyright (c) 2004 Media Development Loan Fund
|
|
|
|
This file is part of the LiveSupport project.
|
|
http://livesupport.campware.org/
|
|
To report bugs, send an e-mail to bugs@campware.org
|
|
|
|
LiveSupport 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 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
LiveSupport 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 LiveSupport; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
Author : $Author: maroy $
|
|
Version : $Revision: 1.7 $
|
|
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/gstreamerElements/src/seek-pack.c,v $
|
|
|
|
------------------------------------------------------------------------------*/
|
|
|
|
/* ============================================================ include files */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "configure.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_STRING_H
|
|
#include <string.h>
|
|
#else
|
|
#error need string.h
|
|
#endif
|
|
|
|
|
|
#include <gst/gst.h>
|
|
|
|
#include "LiveSupport/GstreamerElements/autoplug.h"
|
|
#include "util.h"
|
|
#include "seek.h"
|
|
#include "seek-pack.h"
|
|
|
|
|
|
/* =================================================== local data structures */
|
|
|
|
|
|
/* ================================================ local constants & macros */
|
|
|
|
#define NSEC_PER_SEC 1000000000LL
|
|
#define SEC_PER_MIN 60
|
|
#define SEC_PER_HOUR 3600
|
|
#define NSEC_PER_SEC_FLOAT 1000000000.0
|
|
#define SEC_PER_MIN_FLOAT 60.0
|
|
#define SEC_PER_HOUR_FLOAT 3600.0
|
|
|
|
|
|
/* =============================================== local function prototypes */
|
|
|
|
/**
|
|
* Signal handler for the eos event of the switcher element.
|
|
*
|
|
* @param element the element emitting the eos signal
|
|
* @param userData pointer to the container bin of the switcher.
|
|
*/
|
|
static void
|
|
switcher_eos_signal_handler(GstElement * element,
|
|
gpointer userData);
|
|
|
|
/**
|
|
* Perform the seeks on the SeekPack, set by the initialization function.
|
|
*
|
|
* @param seekPack the SeekPack to perform the seek on.
|
|
* @see #livesupport_seek_pack_init
|
|
*/
|
|
static void
|
|
livesupport_seek_pack_seek(LivesupportSeekPack * seekPack);
|
|
|
|
|
|
/* ============================================================= module code */
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* eos signal handler for the switcher element
|
|
*----------------------------------------------------------------------------*/
|
|
static void
|
|
switcher_eos_signal_handler(GstElement * element,
|
|
gpointer userData)
|
|
{
|
|
GstElement * container = GST_ELEMENT(userData);
|
|
|
|
g_return_if_fail(container != NULL);
|
|
g_return_if_fail(GST_IS_ELEMENT(container));
|
|
|
|
/* set the container into eos state */
|
|
GST_DEBUG("SeekPack.switcher setting SeekPack.bin to eos");
|
|
gst_element_set_eos(container);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Create a new SeekPack.
|
|
*----------------------------------------------------------------------------*/
|
|
LivesupportSeekPack *
|
|
livesupport_seek_pack_new(const gchar * uniqueName)
|
|
{
|
|
unsigned int len = strlen(uniqueName) + 64;
|
|
gchar * str = g_malloc(len);
|
|
LivesupportSeekPack * seekPack = g_malloc(sizeof(LivesupportSeekPack));
|
|
|
|
seekPack->name = g_strdup(uniqueName);
|
|
|
|
g_snprintf(str, len, "%s_seekPackSilence", uniqueName);
|
|
seekPack->silence = gst_element_factory_make("silence", str);
|
|
g_snprintf(str, len, "%s_seekPackAudioConvert", uniqueName);
|
|
seekPack->audioconvert = gst_element_factory_make("audioconvert", str);
|
|
|
|
seekPack->source = NULL;
|
|
|
|
/* generate decoder later, by autoplugging */
|
|
seekPack->decoder = 0;
|
|
g_snprintf(str, len, "%s_seekPackSwitcher", uniqueName);
|
|
seekPack->switcher = gst_element_factory_make("switcher", str);
|
|
g_snprintf(str, len, "%s_seekPackBin", uniqueName);
|
|
seekPack->bin = gst_bin_new(str);
|
|
g_free(str);
|
|
|
|
g_signal_connect(seekPack->switcher,
|
|
"eos",
|
|
G_CALLBACK(switcher_eos_signal_handler),
|
|
seekPack->bin);
|
|
|
|
seekPack->silenceDuration = 0LL;
|
|
seekPack->startTime = 0LL;
|
|
seekPack->endTime = 0LL;
|
|
seekPack->duration = 0LL;
|
|
seekPack->positionAfterSeek = 0LL;
|
|
seekPack->realEndTime = 0LL;
|
|
|
|
seekPack->sendingSilence = TRUE;
|
|
|
|
gst_element_add_ghost_pad(seekPack->bin,
|
|
gst_element_get_pad(seekPack->switcher, "src"),
|
|
"src");
|
|
|
|
return seekPack;
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Initialize a SeekPack.
|
|
*----------------------------------------------------------------------------*/
|
|
void
|
|
livesupport_seek_pack_init(LivesupportSeekPack * seekPack,
|
|
GstElement * source,
|
|
gint64 silenceDuration,
|
|
gint64 startTime,
|
|
gint64 endTime)
|
|
{
|
|
GValue gvalue = { 0 };
|
|
gchar str[256];
|
|
unsigned int len = strlen(seekPack->name) + 64;
|
|
gchar * name = g_malloc(len);
|
|
|
|
seekPack->source = source;
|
|
|
|
seekPack->silenceDuration = silenceDuration;
|
|
seekPack->startTime = startTime;
|
|
seekPack->endTime = endTime;
|
|
seekPack->duration = endTime - startTime;
|
|
seekPack->positionAfterSeek = 0LL;
|
|
seekPack->realEndTime = 0LL;
|
|
|
|
g_value_init(&gvalue, G_TYPE_STRING);
|
|
if (seekPack->endTime >= 0) {
|
|
g_snprintf(str, 256, "0[%lfs];1[%lfs]",
|
|
seekPack->silenceDuration / NSEC_PER_SEC_FLOAT,
|
|
seekPack->duration / NSEC_PER_SEC_FLOAT);
|
|
} else {
|
|
g_snprintf(str, 256, "0[%lfs];1[]",
|
|
seekPack->silenceDuration / NSEC_PER_SEC_FLOAT);
|
|
}
|
|
g_value_set_string(&gvalue, str);
|
|
gst_element_set_property(seekPack->switcher, "source-config", &gvalue);
|
|
|
|
g_snprintf(name, len, "%s_seekPackDecoder", seekPack->name);
|
|
seekPack->decoder = ls_gst_autoplug_plug_source(seekPack->source,
|
|
name);
|
|
g_free(name);
|
|
|
|
/* link up the silence element with the switcher first */
|
|
gst_element_link_many(seekPack->silence,
|
|
seekPack->audioconvert,
|
|
seekPack->switcher,
|
|
NULL);
|
|
|
|
if (seekPack->decoder) {
|
|
/* seek on the decoder, and link it up with the switcher */
|
|
gst_element_link(seekPack->source, seekPack->decoder);
|
|
livesupport_seek_pack_seek(seekPack);
|
|
gst_element_link(seekPack->decoder, seekPack->switcher);
|
|
} else {
|
|
/* just fake the content with silence,
|
|
* if it could not be auto-plugged */
|
|
seekPack->decoder = gst_element_factory_make("silence", "decoder");
|
|
gst_element_link(seekPack->decoder, seekPack->switcher);
|
|
}
|
|
|
|
/* put all inside the bin, and link up a ghost pad to switch's src pad */
|
|
gst_bin_add_many(GST_BIN(seekPack->bin),
|
|
seekPack->silence,
|
|
seekPack->audioconvert,
|
|
seekPack->source,
|
|
seekPack->decoder,
|
|
NULL);
|
|
|
|
/* put the switcher last into the bin, and also link it as last
|
|
* otherwise we'll get a:
|
|
* "assertion failed: (group->group_links == NULL)"
|
|
* error later on when trying to free up the pipeline
|
|
* see http://bugzilla.gnome.org/show_bug.cgi?id=309122
|
|
*/
|
|
gst_bin_add(GST_BIN(seekPack->bin), seekPack->switcher);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Destroy a SeekPack.
|
|
*----------------------------------------------------------------------------*/
|
|
void
|
|
livesupport_seek_pack_destroy(LivesupportSeekPack * seekPack)
|
|
{
|
|
gst_element_set_state(seekPack->bin, GST_STATE_NULL);
|
|
g_object_unref(seekPack->bin);
|
|
g_free(seekPack->name);
|
|
g_free(seekPack);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Link a SeekPack to another element.
|
|
*----------------------------------------------------------------------------*/
|
|
gboolean
|
|
livesupport_seek_pack_link(LivesupportSeekPack * seekPack,
|
|
GstElement * element)
|
|
{
|
|
return gst_element_link(seekPack->bin, element);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Add a SeekPack to a bin.
|
|
*----------------------------------------------------------------------------*/
|
|
void
|
|
livesupport_seek_pack_add_to_bin(LivesupportSeekPack * seekPack,
|
|
GstBin * bin)
|
|
{
|
|
/* put an extra ref on our elements, as the bin will decrease the
|
|
* ref when they are removed from there */
|
|
g_object_ref(seekPack->bin);
|
|
gst_bin_add(bin, seekPack->bin);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Remove a SeekPack from a bin.
|
|
*----------------------------------------------------------------------------*/
|
|
void
|
|
livesupport_seek_pack_remove_from_bin(LivesupportSeekPack * seekPack,
|
|
GstBin * bin)
|
|
{
|
|
gst_bin_remove(bin, seekPack->bin);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Set the state of a SeekPack.
|
|
*----------------------------------------------------------------------------*/
|
|
void
|
|
livesupport_seek_pack_set_state(LivesupportSeekPack * seekPack,
|
|
GstElementState state)
|
|
{
|
|
/* FIXME: resetting the source from PLAYING state would make it lose
|
|
* it's seek position */
|
|
if (seekPack->audioconvert) {
|
|
gst_element_set_state(seekPack->audioconvert, state);
|
|
}
|
|
if (seekPack->decoder) {
|
|
gst_element_set_state(seekPack->decoder, state);
|
|
}
|
|
if (seekPack->switcher) {
|
|
gst_element_set_state(seekPack->switcher, state);
|
|
}
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Do the seeking on a SeekPack.
|
|
*----------------------------------------------------------------------------*/
|
|
static void
|
|
livesupport_seek_pack_seek(LivesupportSeekPack * seekPack)
|
|
{
|
|
GstElement * pipeline;
|
|
GstElement * fakesink;
|
|
gboolean ret;
|
|
gint64 value;
|
|
GstSeekType seekType;
|
|
|
|
seekType = (GstSeekType) (GST_FORMAT_TIME |
|
|
GST_SEEK_METHOD_SET |
|
|
GST_SEEK_FLAG_FLUSH);
|
|
pipeline = gst_pipeline_new("seek_pipeline");
|
|
fakesink = gst_element_factory_make("fakesink", "seek_fakesink");
|
|
|
|
gst_element_link(seekPack->decoder, fakesink);
|
|
/* ref the objects we want to keep after pipeline, as it will unref them */
|
|
g_object_ref(seekPack->source);
|
|
g_object_ref(seekPack->decoder);
|
|
gst_bin_add_many(GST_BIN(pipeline),
|
|
seekPack->source,
|
|
seekPack->decoder,
|
|
fakesink,
|
|
NULL);
|
|
|
|
GST_DEBUG("setting seek pipeline to PLAYING state");
|
|
gst_element_set_state(seekPack->decoder, GST_STATE_PAUSED);
|
|
gst_element_set_state(fakesink, GST_STATE_PAUSED);
|
|
gst_element_set_state(pipeline, GST_STATE_PLAYING);
|
|
|
|
GST_DEBUG("starting to iterate...");
|
|
for (value = 0; value == 0 && gst_bin_iterate(GST_BIN(pipeline)); ) {
|
|
GstFormat format = GST_FORMAT_DEFAULT;
|
|
gst_element_query(fakesink, GST_QUERY_POSITION, &format, &value);
|
|
GST_DEBUG("position value: %" G_GINT64_FORMAT, value);
|
|
}
|
|
GST_DEBUG("seeking on element");
|
|
ret = livesupport_seek(seekPack->decoder, seekType, seekPack->startTime);
|
|
GST_DEBUG("seek result: %d", ret);
|
|
|
|
gst_bin_remove_many(GST_BIN(pipeline),
|
|
seekPack->source,
|
|
seekPack->decoder,
|
|
NULL);
|
|
gst_element_unlink(seekPack->decoder, fakesink);
|
|
gst_object_unref(GST_OBJECT(pipeline));
|
|
}
|
|
|