Revert "Revert "disable m2ts support for release 2.6""
[vuplus_dvbapp] / lib / service / servicemp3.cpp
index 34d0936..1fb1e44 100644 (file)
@@ -2,20 +2,25 @@
 
        /* 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 <lib/base/ebase.h>
 #include <lib/base/eerror.h>
+#include <lib/base/init_num.h>
+#include <lib/base/init.h>
+#include <lib/base/nconfig.h>
 #include <lib/base/object.h>
-#include <lib/base/ebase.h>
-#include <string>
+#include <lib/dvb/decoder.h>
+#include <lib/components/file_eraser.h>
+#include <lib/gui/esubtitle.h>
 #include <lib/service/servicemp3.h>
 #include <lib/service/service.h>
-#include <lib/components/file_eraser.h>
-#include <lib/base/init_num.h>
-#include <lib/base/init.h>
+
+#include <string>
+
 #include <gst/gst.h>
 #include <gst/pbutils/missing-plugins.h>
 #include <sys/stat.h>
-/* for subtitles */
-#include <lib/gui/esubtitle.h>
+
+#define HTTP_TIMEOUT 10
 
 // eServiceFactoryMP3
 
@@ -186,13 +191,35 @@ int eStaticServiceMP3Info::getLength(const eServiceReference &ref)
        return -1;
 }
 
+int eStaticServiceMP3Info::getInfo(const eServiceReference &ref, int w)
+{
+       switch (w)
+       {
+       case iServiceInformation::sTimeCreate:
+       {
+               struct stat s;
+               if(stat(ref.path.c_str(), &s) == 0)
+               {
+                 return s.st_mtime;
+               }
+               return iServiceInformation::resNA;
+       }
+       default: break;
+       }
+       return iServiceInformation::resNA;
+}
+
 // eServiceMP3
+int eServiceMP3::ac3_delay,
+    eServiceMP3::pcm_delay;
 
 eServiceMP3::eServiceMP3(eServiceReference ref)
        :m_ref(ref), m_pump(eApp, 1)
 {
        m_seekTimeout = eTimer::create(eApp);
        m_subtitle_sync_timer = eTimer::create(eApp);
+       m_streamingsrc_timeout = 0;
        m_stream_tags = 0;
        m_currentAudioStream = -1;
        m_currentSubtitleStream = 0;
@@ -213,63 +240,73 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
        if (!ext)
                ext = filename;
 
-       sourceStream sourceinfo;
-       sourceinfo.is_video = FALSE;
-       sourceinfo.audiotype = atUnknown;
+       m_sourceinfo.is_video = FALSE;
+       m_sourceinfo.audiotype = atUnknown;
        if ( (strcasecmp(ext, ".mpeg") && strcasecmp(ext, ".mpg") && strcasecmp(ext, ".vob") && strcasecmp(ext, ".bin") && strcasecmp(ext, ".dat") ) == 0 )
        {
-               sourceinfo.containertype = ctMPEGPS;
-               sourceinfo.is_video = TRUE;
+               m_sourceinfo.containertype = ctMPEGPS;
+               m_sourceinfo.is_video = TRUE;
        }
        else if ( strcasecmp(ext, ".ts") == 0 )
        {
-               sourceinfo.containertype = ctMPEGTS;
-               sourceinfo.is_video = TRUE;
+               m_sourceinfo.containertype = ctMPEGTS;
+               m_sourceinfo.is_video = TRUE;
        }
        else if ( strcasecmp(ext, ".mkv") == 0 )
        {
-               sourceinfo.containertype = ctMKV;
-               sourceinfo.is_video = TRUE;
+               m_sourceinfo.containertype = ctMKV;
+               m_sourceinfo.is_video = TRUE;
        }
        else if ( strcasecmp(ext, ".avi") == 0 || strcasecmp(ext, ".divx") == 0)
        {
-               sourceinfo.containertype = ctAVI;
-               sourceinfo.is_video = TRUE;
+               m_sourceinfo.containertype = ctAVI;
+               m_sourceinfo.is_video = TRUE;
        }
        else if ( strcasecmp(ext, ".mp4") == 0 || strcasecmp(ext, ".mov") == 0 || strcasecmp(ext, ".m4v") == 0)
        {
-               sourceinfo.containertype = ctMP4;
-               sourceinfo.is_video = TRUE;
+               m_sourceinfo.containertype = ctMP4;
+               m_sourceinfo.is_video = TRUE;
        }
        else if ( strcasecmp(ext, ".m4a") == 0 )
        {
-               sourceinfo.containertype = ctMP4;
-               sourceinfo.audiotype = atAAC;
+               m_sourceinfo.containertype = ctMP4;
+               m_sourceinfo.audiotype = atAAC;
        }
        else if ( strcasecmp(ext, ".mp3") == 0 )
-               sourceinfo.audiotype = atMP3;
+               m_sourceinfo.audiotype = atMP3;
        else if ( (strncmp(filename, "/autofs/", 8) || strncmp(filename+strlen(filename)-13, "/track-", 7) || strcasecmp(ext, ".wav")) == 0 )
-               sourceinfo.containertype = ctCDA;
+               m_sourceinfo.containertype = ctCDA;
        if ( strcasecmp(ext, ".dat") == 0 )
        {
-               sourceinfo.containertype = ctVCD;
-               sourceinfo.is_video = TRUE;
+               m_sourceinfo.containertype = ctVCD;
+               m_sourceinfo.is_video = TRUE;
        }
-       if ( (strncmp(filename, "http://", 7)) == 0 || (strncmp(filename, "udp://", 6)) == 0 || (strncmp(filename, "rtp://", 6)) == 0  || (strncmp(filename, "https://", 8)) == 0 || (strncmp(filename, "mms://", 6)) == 0 || (strncmp(filename, "rtsp://", 7)) == 0 )
-               sourceinfo.is_streaming = TRUE;
+       if ( (strncmp(filename, "http://", 7)) == 0 || (strncmp(filename, "udp://", 6)) == 0 || (strncmp(filename, "rtp://", 6)) == 0  || (strncmp(filename, "https://", 8)) == 0 || (strncmp(filename, "mms://", 6)) == 0 || (strncmp(filename, "rtsp://", 7)) == 0 || (strncmp(filename, "rtspt://", 7)) == 0 )
+               m_sourceinfo.is_streaming = TRUE;
 
        gchar *uri;
 
-       if ( sourceinfo.is_streaming )
+       if ( m_sourceinfo.is_streaming )
        {
                uri = g_strdup_printf ("%s", filename);
+               m_streamingsrc_timeout = eTimer::create(eApp);;
+               CONNECT(m_streamingsrc_timeout->timeout, eServiceMP3::sourceTimeout);
+
+               std::string config_str;
+               if( ePythonConfigQuery::getConfigValue("config.mediaplayer.useAlternateUserAgent", config_str) == 0 )
+               {
+                       if ( config_str == "True" )
+                               ePythonConfigQuery::getConfigValue("config.mediaplayer.alternateUserAgent", m_useragent);
+               }
+               if ( m_useragent.length() == 0 )
+                       m_useragent = "Dream Multimedia Dreambox Enigma2 Mediaplayer";
        }
-       else if ( sourceinfo.containertype == ctCDA )
+       else if ( m_sourceinfo.containertype == ctCDA )
        {
                int i_track = atoi(filename+18);
                uri = g_strdup_printf ("cdda://%i", i_track);
        }
-       else if ( sourceinfo.containertype == ctVCD )
+       else if ( m_sourceinfo.containertype == ctVCD )
        {
                int fd = open(filename,O_RDONLY);
                char tmp[128*1024];
@@ -278,11 +315,11 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
                if ( ret == -1 ) // this is a "REAL" VCD
                        uri = g_strdup_printf ("vcd://");
                else
-                       uri = g_strdup_printf ("file://%s", filename);
+                       uri = g_filename_to_uri(filename, NULL, NULL);
        }
        else
 
-               uri = g_strdup_printf ("file://%s", filename);
+               uri = g_filename_to_uri(filename, NULL, NULL);
 
        eDebug("eServiceMP3::playbin2 uri=%s", uri);
 
@@ -303,6 +340,7 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
        else
        {
                m_subs_to_pull_handler_id = g_signal_connect (subsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this);
+               g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-pango-markup"), NULL);
                g_object_set (G_OBJECT (m_gst_playbin), "text-sink", subsink, NULL);
        }
 
@@ -316,14 +354,17 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
                struct stat buffer;
                if (stat(srt_filename, &buffer) == 0)
                {
-                       std::string suburi = "file://" + (std::string)srt_filename;
-                       eDebug("eServiceMP3::subtitle uri: %s",suburi.c_str());
-                       g_object_set (G_OBJECT (m_gst_playbin), "suburi", suburi.c_str(), NULL);
+                       eDebug("eServiceMP3::subtitle uri: %s", g_filename_to_uri(srt_filename, NULL, NULL));
+                       g_object_set (G_OBJECT (m_gst_playbin), "suburi", g_filename_to_uri(srt_filename, NULL, NULL), NULL);
                        subtitleStream subs;
                        subs.type = stSRT;
                        subs.language_code = std::string("und");
                        m_subtitleStreams.push_back(subs);
                }
+               if ( m_sourceinfo.is_streaming )
+               {
+                       g_signal_connect (G_OBJECT (m_gst_playbin), "notify::source", G_CALLBACK (gstHTTPSourceSetAgent), this);
+               }
        } else
        {
                m_event((iPlayableService*)this, evUser+12);
@@ -391,6 +432,12 @@ RESULT eServiceMP3::start()
        return 0;
 }
 
+void eServiceMP3::sourceTimeout()
+{
+       eDebug("eServiceMP3::http source timeout! issuing eof...");
+       m_event((iPlayableService*)this, evEOF);
+}
+
 RESULT eServiceMP3::stop()
 {
        ASSERT(m_state != stIdle);
@@ -635,7 +682,31 @@ RESULT eServiceMP3::setTrickmode(int trick)
 
 RESULT eServiceMP3::isCurrentlySeekable()
 {
-       return 1;
+       int ret = 3; // seeking and fast/slow winding possible
+       GstElement *sink;
+
+       if (!m_gst_playbin)
+               return 0;
+       if (m_state != stRunning)
+               return 0;
+
+       g_object_get (G_OBJECT (m_gst_playbin), "video-sink", &sink, NULL);
+
+       // disable fast winding yet when a dvbvideosink or dvbaudiosink is used
+       // for this we must do some changes on different places.. (gstreamer.. our sinks.. enigma2)
+       if (sink) {
+               ret &= ~2; // only seeking possible
+               gst_object_unref(sink);
+       }
+       else {
+               g_object_get (G_OBJECT (m_gst_playbin), "audio-sink", &sink, NULL);
+               if (sink) {
+                       ret &= ~2; // only seeking possible
+                       gst_object_unref(sink);
+               }
+       }
+
+       return ret;
 }
 
 RESULT eServiceMP3::info(ePtr<iServiceInformation>&i)
@@ -659,7 +730,6 @@ RESULT eServiceMP3::getName(std::string &name)
        return 0;
 }
 
-
 int eServiceMP3::getInfo(int w)
 {
        const gchar *tag = 0;
@@ -955,6 +1025,12 @@ RESULT eServiceMP3::subtitle(ePtr<iSubtitleOutput> &ptr)
        return 0;
 }
 
+RESULT eServiceMP3::audioDelay(ePtr<iAudioDelay> &ptr)
+{
+       ptr = this;
+       return 0;
+}
+
 int eServiceMP3::getNumberOfTracks()
 {
        return m_audioStreams.size();
@@ -1093,9 +1169,13 @@ 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:
                                {
+                                       if ( m_sourceinfo.is_streaming && m_streamingsrc_timeout )
+                                               m_streamingsrc_timeout->stop();
                                }       break;
                                case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
                                {
@@ -1247,6 +1327,7 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
 //                             g_free (g_type);
                        }
                        m_event((iPlayableService*)this, evUpdatedEventInfo);
+                       break;
                }
                case GST_MESSAGE_ELEMENT:
                {
@@ -1295,6 +1376,37 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                        gst_message_parse_buffering(msg, &(m_bufferInfo.bufferPercent));
                        gst_message_parse_buffering_stats(msg, &mode, &(m_bufferInfo.avgInRate), &(m_bufferInfo.avgOutRate), &(m_bufferInfo.bufferingLeft));
                        m_event((iPlayableService*)this, evBuffering);
+                       break;
+               }
+               case GST_MESSAGE_STREAM_STATUS:
+               {
+                       GstStreamStatusType type;
+                       GstElement *owner;
+                       gst_message_parse_stream_status (msg, &type, &owner);
+                       if ( type == GST_STREAM_STATUS_TYPE_CREATE && m_sourceinfo.is_streaming )
+                       {
+                               if ( GST_IS_PAD(source) )
+                                       owner = gst_pad_get_parent_element(GST_PAD(source));
+                               else if ( GST_IS_ELEMENT(source) )
+                                       owner = GST_ELEMENT(source);
+                               else
+                                       owner = 0;
+                               if ( owner )
+                               {
+                                       GstElementFactory *factory = gst_element_get_factory(GST_ELEMENT(owner));
+                                       const gchar *name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
+                                       if (!strcmp(name, "souphttpsrc"))
+                                       {
+                                               m_streamingsrc_timeout->start(HTTP_TIMEOUT*1000, true);
+                                               g_object_set (G_OBJECT (owner), "timeout", HTTP_TIMEOUT, NULL);
+                                               eDebug("eServiceMP3::GST_STREAM_STATUS_TYPE_CREATE -> setting timeout on %s to %is", name, HTTP_TIMEOUT);
+                                       }
+                                       
+                               }
+                               if ( GST_IS_PAD(source) )
+                                       gst_object_unref(owner);
+                       }
+                       break;
                }
                default:
                        break;
@@ -1310,6 +1422,15 @@ GstBusSyncReply eServiceMP3::gstBusSyncHandler(GstBus *bus, GstMessage *message,
        return GST_BUS_PASS;
 }
 
+void eServiceMP3::gstHTTPSourceSetAgent(GObject *object, GParamSpec *unused, gpointer user_data)
+{
+       eServiceMP3 *_this = (eServiceMP3*)user_data;
+       GstElement *source;
+       g_object_get(_this->m_gst_playbin, "source", &source, NULL);
+       g_object_set (G_OBJECT (source), "user-agent", _this->m_useragent.c_str(), NULL);
+       gst_object_unref(source);
+}
+
 audiotype_t eServiceMP3::gstCheckAudioPad(GstStructure* structure)
 {
        if (!structure)
@@ -1579,6 +1700,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