Support shmsrc (live source)

If the imported file is a socket path, we mark the media as "live". We
continuously poll for the socket path (in case e.g. it disappears / reappears).
As soon as the source socket patch exists, we connect a shmsrc ! gdpdepay
pipeline  (instead of a normal uridecodebin element for file-based media) and we
set the pipeline state to PLAYING (playAction button is not needed at the moment
for live sources, but we can change behaviour to only start the pipeline if
play is selected, like with normal file-based media)

In case of a GST_MESSAGE_ERROR, the polling function keeps looking for the
socket path until it exists again. The existing shmsrc pipeline is re-used
once the live source is transmitting again.

Tested with live source gst-launch-1.0:

gst-launch-1.0 uridecodebin uri=file:////opt/Videos/test.avi !  queue !
videoconvert ! video/x-raw, format="RGBA" ! gdppay ! shmsink
socket-path=/tmp/sock  shm-size=100000000

The live source was interrupted and restarted again, and the shmsrc in mapmap is
able to pick up the reappearing media stream.

Signed-off-by: Vasilis Liaskovitis <vliaskov@gmail.com>
This commit is contained in:
Vasilis Liaskovitis
2014-06-25 22:15:51 +02:00
parent 4246c5a3b4
commit f3e94f743c
7 changed files with 116 additions and 22 deletions
+90 -11
View File
@@ -57,6 +57,21 @@ const uchar* MediaImpl::getBits() const
return _data;
}
QString MediaImpl::getUri() const
{
return _uri;
}
bool MediaImpl::getAttached()
{
return _attached;
}
void MediaImpl::setAttached(bool attach)
{
_attached = attach;
}
void MediaImpl::build()
{
qDebug() << "Building video impl";
@@ -179,7 +194,7 @@ GstFlowReturn MediaImpl::gstNewSampleCallback(GstElement*, MediaImpl *p)
return GST_FLOW_OK;
}
MediaImpl::MediaImpl(const QString uri) :
MediaImpl::MediaImpl(const QString uri, bool live) :
_currentMovie(""),
_bus(NULL),
_pipeline(NULL),
@@ -200,7 +215,9 @@ _data(NULL),
_seekEnabled(false),
//_audioNewBufferCounter(0),
_movieReady(false),
_uri(uri)
_uri(uri),
_live(live),
_attached(false)
{
if (uri != "")
loadMovie(uri);
@@ -299,6 +316,21 @@ void MediaImpl::resetMovie()
}
}
gboolean
gstPollShmsrc (void *user_data)
{
MediaImpl *p = (MediaImpl*) user_data;
if (g_file_test(p->getUri().toUtf8().constData() , G_FILE_TEST_EXISTS) && !p->getAttached()) {
if (!p->setPlayState(true)) {
qDebug() << "tried to attach, but starting pipeline failed!" << endl;
return false;
}
//qDebug() << "attached, started pipeline!" << endl;
p->setAttached(true);
}
return true;
}
bool MediaImpl::loadMovie(QString filename)
{
_uri = filename;
@@ -317,7 +349,19 @@ bool MediaImpl::loadMovie(QString filename)
GstElement *videoScale = NULL;
// Create the elements.
_source = gst_element_factory_make ("uridecodebin", "source");
if (!_live)
_source = gst_element_factory_make ("uridecodebin", "source");
else {
_source = gst_element_factory_make ("shmsrc", "source");
_deserializer = gst_element_factory_make ("gdpdepay", "deserializer");
_pollSource = g_timeout_source_new (500);
g_source_set_callback (_pollSource,
gstPollShmsrc,
this,
NULL);
g_source_attach (_pollSource, g_main_context_default());
g_source_unref (_pollSource);
}
// _audioQueue = gst_element_factory_make ("queue", "aqueue");
// _audioConvert = gst_element_factory_make ("audioconvert", "aconvert");
@@ -343,7 +387,7 @@ bool MediaImpl::loadMovie(QString filename)
// Create the empty pipeline.
_pipeline = gst_pipeline_new ( "video-source-pipeline" );
if (!_pipeline || !_source ||
if (!_pipeline || !_source || (_live && !_deserializer) ||
// !_audioQueue || !_audioConvert || !_audioResample || !_audioSink ||
!_videoQueue || !_videoColorSpace || ! videoScale || ! capsFilter || ! _videoSink)
{
@@ -358,6 +402,15 @@ bool MediaImpl::loadMovie(QString filename)
// _audioQueue, _audioConvert, _audioResample, _audioSink,
_videoQueue, _videoColorSpace, videoScale, capsFilter, _videoSink, NULL);
if (_live) {
gst_bin_add (GST_BIN(_pipeline), _deserializer);
if (!gst_element_link_many (_source, _deserializer, _videoQueue, NULL)) {
g_printerr ("Video elements could not be linked.\n");
}
}
else if (!gst_element_link (_source, _videoQueue))
g_printerr ("Video elements could not be linked.\n");
// if (!gst_element_link_many(_audioQueue, _audioConvert, _audioResample, _audioSink, NULL)) {
// g_printerr ("Audio elements could not be linked.\n");
// unloadMovie();
@@ -371,8 +424,9 @@ bool MediaImpl::loadMovie(QString filename)
}
// Process URI.
QByteArray ba = filename.toLocal8Bit();
gchar* uri = (gchar*) filename.toUtf8().constData();
if (!gst_uri_is_valid(uri))
if (!_live && !gst_uri_is_valid(uri))
{
// Try to convert filename to URI.
GError* error = NULL;
@@ -386,12 +440,25 @@ bool MediaImpl::loadMovie(QString filename)
}
}
if (_live)
uri = (gchar*) ba.data();
// Set URI to be played.
qDebug() << "URI for uridecodebin: " << uri;
// FIXME: sometimes it's just the path to the directory that is given, not the file itself.
g_object_set (_source, "uri", uri, NULL);
// Connect to the pad-added signal
g_signal_connect (_source, "pad-added", G_CALLBACK (MediaImpl::gstPadAddedCallback), &_padHandlerData);
if (!_live) {
g_object_set (_source, "uri", uri, NULL);
g_signal_connect (_source, "pad-added", G_CALLBACK (MediaImpl::gstPadAddedCallback), &_padHandlerData);
}
else {
//qDebug() << "LIVE mode" << uri;
g_object_set (_source, "socket-path", uri, NULL);
g_object_set (_source, "is-live", TRUE, NULL);
_padHandlerData.videoIsConnected = true;
}
// Configure audio appsink.
// TODO: change from mono to stereo
@@ -414,6 +481,7 @@ bool MediaImpl::loadMovie(QString filename)
g_object_set (_videoSink, "emit-signals", TRUE,
"max-buffers", 1, // only one buffer (the last) is maintained in the queue
"drop", TRUE, // ... other buffers are dropped
"sync", TRUE,
NULL);
g_signal_connect (_videoSink, "new-sample", G_CALLBACK (MediaImpl::gstNewSampleCallback), this);
gst_caps_unref (videoCaps);
@@ -422,7 +490,7 @@ bool MediaImpl::loadMovie(QString filename)
_bus = gst_element_get_bus (_pipeline);
// Start playing.
if (!setPlayState(true))
if (!_live && !setPlayState(true))
return false;
qDebug() << "Pipeline started.";
@@ -523,7 +591,7 @@ bool MediaImpl::setPlayState(bool play)
bool MediaImpl::_preRun()
{
// Check for end-of-stream or terminate.
if (_eos() || _terminate)
if ((_eos() || _terminate) && !_live)
{
_setFinished(true);
resetMovie();
@@ -543,8 +611,12 @@ bool MediaImpl::_preRun()
// resetMovie();
if (!_movieReady ||
!_padHandlerData.isConnected())
!_padHandlerData.isConnected()) {
qDebug() << "movieReady" << _movieReady << " padhandler " <<
_padHandlerData.isConnected() << endl;
return false;
}
return true;
}
@@ -573,7 +645,14 @@ void MediaImpl::_postRun()
g_clear_error(&err);
g_free(debug_info);
_terminate = true;
if (!_live)
_terminate = true;
else {
_attached = false;
gst_element_set_state (_pipeline, GST_STATE_PAUSED);
gst_element_set_state (_pipeline, GST_STATE_NULL);
gst_element_set_state (_pipeline, GST_STATE_READY);
}
// _finish();
break;