X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/884a9bb30ff4a4715e96207269d149c304ecfc1d..9ec56f0aae40fe0c4afb071df436eacf79ac10af:/lib/service/servicemp3.cpp diff --git a/lib/service/servicemp3.cpp b/lib/service/servicemp3.cpp index 7d5901e2..f74bc5ee 100644 --- a/lib/service/servicemp3.cpp +++ b/lib/service/servicemp3.cpp @@ -2,26 +2,23 @@ /* note: this requires gstreamer 0.10.x and a big list of plugins. */ /* it's currently hardcoded to use a big-endian alsasink as sink. */ +#include #include +#include +#include +#include #include -#include -#include +#include +#include +#include #include #include -#include -#include -#include + +#include + #include #include #include -/* for subtitles */ -#include - -#ifndef GST_SEEK_FLAG_SKIP -#warning Compiling for legacy gstreamer, things will break -#define GST_SEEK_FLAG_SKIP 0 -#define GST_TAG_HOMEPAGE "" -#endif // eServiceFactoryMP3 @@ -48,7 +45,6 @@ eServiceFactoryMP3::eServiceFactoryMP3() extensions.push_back("mp4"); extensions.push_back("mov"); extensions.push_back("m4a"); - extensions.push_back("m2ts"); sc->addServiceFactory(eServiceFactoryMP3::id, this, extensions); } @@ -193,6 +189,8 @@ int eStaticServiceMP3Info::getLength(const eServiceReference &ref) } // eServiceMP3 +int eServiceMP3::ac3_delay, + eServiceMP3::pcm_delay; eServiceMP3::eServiceMP3(eServiceReference ref) :m_ref(ref), m_pump(eApp, 1) @@ -200,7 +198,7 @@ eServiceMP3::eServiceMP3(eServiceReference ref) m_seekTimeout = eTimer::create(eApp); m_subtitle_sync_timer = eTimer::create(eApp); m_stream_tags = 0; - m_currentAudioStream = 0; + m_currentAudioStream = -1; m_currentSubtitleStream = 0; m_subtitle_widget = 0; m_currentTrickRatio = 0; @@ -308,7 +306,7 @@ eServiceMP3::eServiceMP3(eServiceReference ref) eDebug("eServiceMP3::sorry, can't play: missing gst-plugin-appsink"); else { - g_signal_connect (subsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this); + m_subs_to_pull_handler_id = g_signal_connect (subsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this); g_object_set (G_OBJECT (m_gst_playbin), "text-sink", subsink, NULL); } @@ -341,16 +339,28 @@ eServiceMP3::eServiceMP3(eServiceReference ref) m_gst_playbin = 0; } - gst_element_set_state (m_gst_playbin, GST_STATE_PLAYING); setBufferSize(m_buffer_size); } eServiceMP3::~eServiceMP3() { + // disconnect subtitle callback + GstElement *sink; + g_object_get (G_OBJECT (m_gst_playbin), "text-sink", &sink, NULL); + if (sink) + { + g_signal_handler_disconnect (sink, m_subs_to_pull_handler_id); + gst_object_unref(sink); + } + delete m_subtitle_widget; + + // disconnect sync handler callback + gst_bus_set_sync_handler(gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin)), NULL, NULL); + if (m_state == stRunning) stop(); - + if (m_stream_tags) gst_tag_list_free(m_stream_tags); @@ -361,7 +371,7 @@ eServiceMP3::~eServiceMP3() } } -DEFINE_REF(eServiceMP3); +DEFINE_REF(eServiceMP3); RESULT eServiceMP3::connectEvent(const Slot2 &event, ePtr &connection) { @@ -372,25 +382,30 @@ RESULT eServiceMP3::connectEvent(const Slot2 &event, RESULT eServiceMP3::start() { ASSERT(m_state == stIdle); - + m_state = stRunning; if (m_gst_playbin) { eDebug("eServiceMP3::starting pipeline"); gst_element_set_state (m_gst_playbin, GST_STATE_PLAYING); } + m_event(this, evStart); + return 0; } RESULT eServiceMP3::stop() { ASSERT(m_state != stIdle); + if (m_state == stStopped) return -1; + eDebug("eServiceMP3::stop %s", m_ref.path.c_str()); gst_element_set_state(m_gst_playbin, GST_STATE_NULL); m_state = stStopped; + return 0; } @@ -446,24 +461,19 @@ RESULT eServiceMP3::pause() { if (!m_gst_playbin || m_state != stRunning) return -1; - GstStateChangeReturn res = gst_element_set_state(m_gst_playbin, GST_STATE_PAUSED); - if (res == GST_STATE_CHANGE_ASYNC) - { - pts_t ppos; - getPlayPosition(ppos); - seekTo(ppos); - } + + gst_element_set_state(m_gst_playbin, GST_STATE_PAUSED); + return 0; } RESULT eServiceMP3::unpause() { - m_subtitle_pages.clear(); if (!m_gst_playbin || m_state != stRunning) return -1; - GstStateChangeReturn res; - res = gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING); + gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING); + return 0; } @@ -478,9 +488,10 @@ RESULT eServiceMP3::getLength(pts_t &pts) { if (!m_gst_playbin) return -1; + if (m_state != stRunning) return -1; - + GstFormat fmt = GST_FORMAT_TIME; gint64 len; @@ -492,13 +503,8 @@ RESULT eServiceMP3::getLength(pts_t &pts) return 0; } -RESULT eServiceMP3::seekTo(pts_t to) +RESULT eServiceMP3::seekToImpl(pts_t to) { - if (!m_gst_playbin) - return -1; - - eSingleLocker l(m_subs_to_pull_lock); // this is needed to dont handle incomming subtitles during seek! - /* convert pts to nanoseconds */ gint64 time_nanoseconds = to * 11111LL; if (!gst_element_seek (m_gst_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, @@ -509,12 +515,26 @@ RESULT eServiceMP3::seekTo(pts_t to) return -1; } - m_subtitle_pages.clear(); - m_subs_to_pull = 0; - return 0; } +RESULT eServiceMP3::seekTo(pts_t to) +{ + RESULT ret = -1; + + if (m_gst_playbin) { + eSingleLocker l(m_subs_to_pull_lock); // this is needed to dont handle incomming subtitles during seek! + if (!(ret = seekToImpl(to))) + { + m_subtitle_pages.clear(); + m_subs_to_pull = 0; + } + } + + return ret; +} + + RESULT eServiceMP3::trickSeek(gdouble ratio) { if (!m_gst_playbin) @@ -523,11 +543,11 @@ RESULT eServiceMP3::trickSeek(gdouble ratio) return seekRelative(0, 0); GstEvent *s_event; - GstSeekFlags flags; + int flags; flags = GST_SEEK_FLAG_NONE; - flags |= GstSeekFlags (GST_SEEK_FLAG_FLUSH); + flags |= GST_SEEK_FLAG_FLUSH; // flags |= GstSeekFlags (GST_SEEK_FLAG_ACCURATE); - flags |= GstSeekFlags (GST_SEEK_FLAG_KEY_UNIT); + flags |= GST_SEEK_FLAG_KEY_UNIT; // flags |= GstSeekFlags (GST_SEEK_FLAG_SEGMENT); // flags |= GstSeekFlags (GST_SEEK_FLAG_SKIP); @@ -538,13 +558,13 @@ RESULT eServiceMP3::trickSeek(gdouble ratio) if ( ratio >= 0 ) { - s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_SET, len); + s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, (GstSeekFlags)flags, GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_SET, len); eDebug("eServiceMP3::trickSeek with rate %lf to %" GST_TIME_FORMAT " ", ratio, GST_TIME_ARGS (pos)); } else { - s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, GST_SEEK_FLAG_SKIP|GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1); + s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_SKIP|GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1); } if (!gst_element_send_event ( GST_ELEMENT (m_gst_playbin), s_event)) @@ -643,7 +663,6 @@ RESULT eServiceMP3::getName(std::string &name) return 0; } - int eServiceMP3::getInfo(int w) { const gchar *tag = 0; @@ -900,10 +919,7 @@ PyObject *eServiceMP3::getInfoObject(int w) default: break; } - gdouble value; - if ( !tag || !m_stream_tags ) - value = 0.0; - PyObject *pyValue; + if ( isBuffer ) { const GValue *gv_buffer = gst_tag_list_get_value_index(m_stream_tags, tag, 0); @@ -911,16 +927,17 @@ PyObject *eServiceMP3::getInfoObject(int w) { GstBuffer *buffer; buffer = gst_value_get_buffer (gv_buffer); - pyValue = PyBuffer_FromMemory(GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); + return PyBuffer_FromMemory(GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); } } else { + gdouble value = 0.0; gst_tag_list_get_double(m_stream_tags, tag, &value); - pyValue = PyFloat_FromDouble(value); + return PyFloat_FromDouble(value); } - return pyValue; + return 0; } RESULT eServiceMP3::audioChannel(ePtr &ptr) @@ -941,6 +958,12 @@ RESULT eServiceMP3::subtitle(ePtr &ptr) return 0; } +RESULT eServiceMP3::audioDelay(ePtr &ptr) +{ + ptr = this; + return 0; +} + int eServiceMP3::getNumberOfTracks() { return m_audioStreams.size(); @@ -948,16 +971,24 @@ int eServiceMP3::getNumberOfTracks() int eServiceMP3::getCurrentTrack() { + if (m_currentAudioStream == -1) + g_object_get (G_OBJECT (m_gst_playbin), "current-audio", &m_currentAudioStream, NULL); return m_currentAudioStream; } RESULT eServiceMP3::selectTrack(unsigned int i) { - int ret = selectAudioStream(i); - /* flush */ pts_t ppos; getPlayPosition(ppos); - seekTo(ppos); + ppos -= 90000; + if (ppos < 0) + ppos = 0; + + int ret = selectAudioStream(i); + if (!ret) { + /* flush */ + seekTo(ppos); + } return ret; } @@ -1071,6 +1102,8 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg) g_object_set (G_OBJECT (sink), "emit-signals", TRUE, NULL); gst_object_unref(sink); } + setAC3Delay(ac3_delay); + setPCMDelay(pcm_delay); } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: { @@ -1182,8 +1215,7 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg) if (!caps) continue; GstStructure* str = gst_caps_get_structure(caps, 0); - gchar *g_type; - g_type = gst_structure_get_name(str); + const gchar *g_type = gst_structure_get_name(str); eDebug("AUDIO STRUCT=%s", g_type); audio.type = gstCheckAudioPad(str); g_codec = g_strdup(g_type); @@ -1374,8 +1406,8 @@ void eServiceMP3::pullSubtitle() { eSingleLocker l(m_subs_to_pull_lock); --m_subs_to_pull; + g_signal_emit_by_name (sink, "pull-buffer", &buffer); } - g_signal_emit_by_name (sink, "pull-buffer", &buffer); if (buffer) { gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer); @@ -1471,9 +1503,9 @@ RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple) if (m_currentSubtitleStream != pid) { + eSingleLocker l(m_subs_to_pull_lock); g_object_set (G_OBJECT (m_gst_playbin), "current-text", pid, NULL); m_currentSubtitleStream = pid; - eSingleLocker l(m_subs_to_pull_lock); m_subs_to_pull = 0; m_subtitle_pages.clear(); } @@ -1486,7 +1518,6 @@ RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple) eDebug ("eServiceMP3::switched to subtitle stream %i", text_pid); - return 0; error_out: @@ -1559,6 +1590,96 @@ int eServiceMP3::setBufferSize(int size) return 0; } +int eServiceMP3::getAC3Delay() +{ + return ac3_delay; +} + +int eServiceMP3::getPCMDelay() +{ + return pcm_delay; +} + +void eServiceMP3::setAC3Delay(int delay) +{ + ac3_delay = delay; + if (!m_gst_playbin || m_state != stRunning) + return; + else + { + GstElement *sink; + int config_delay_int = delay; + g_object_get (G_OBJECT (m_gst_playbin), "video-sink", &sink, NULL); + + if (sink) + { + std::string config_delay; + if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0) + config_delay_int += atoi(config_delay.c_str()); + gst_object_unref(sink); + } + else + { + eDebug("dont apply ac3 delay when no video is running!"); + config_delay_int = 0; + } + + g_object_get (G_OBJECT (m_gst_playbin), "audio-sink", &sink, NULL); + + if (sink) + { + gchar *name = gst_element_get_name(sink); + if (strstr(name, "dvbaudiosink")) + eTSMPEGDecoder::setHwAC3Delay(config_delay_int); + g_free(name); + gst_object_unref(sink); + } + } +} + +void eServiceMP3::setPCMDelay(int delay) +{ + pcm_delay = delay; + if (!m_gst_playbin || m_state != stRunning) + return; + else + { + GstElement *sink; + int config_delay_int = delay; + g_object_get (G_OBJECT (m_gst_playbin), "video-sink", &sink, NULL); + + if (sink) + { + std::string config_delay; + if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0) + config_delay_int += atoi(config_delay.c_str()); + gst_object_unref(sink); + } + else + { + eDebug("dont apply pcm delay when no video is running!"); + config_delay_int = 0; + } + + g_object_get (G_OBJECT (m_gst_playbin), "audio-sink", &sink, NULL); + + if (sink) + { + gchar *name = gst_element_get_name(sink); + if (strstr(name, "dvbaudiosink")) + eTSMPEGDecoder::setHwPCMDelay(config_delay_int); + else + { + // this is realy untested..and not used yet + gint64 offset = config_delay_int; + offset *= 1000000; // milli to nano + g_object_set (G_OBJECT (m_gst_playbin), "ts-offset", offset, NULL); + } + g_free(name); + gst_object_unref(sink); + } + } +} #else #warning gstreamer not available, not building media player