mirror of
https://github.com/mapmapteam/mapmap.git
synced 2026-06-16 12:33:19 +02:00
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:
+90
-11
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user