more vob experiments
[vuplus_dvbapp] / lib / service / servicemp3.cpp
1 #ifdef HAVE_GSTREAMER
2
3         /* note: this requires gstreamer 0.10.x and a big list of plugins. */
4         /* it's currently hardcoded to use a big-endian alsasink as sink. */
5 #include <lib/base/ebase.h>
6 #include <lib/base/eerror.h>
7 #include <lib/base/init_num.h>
8 #include <lib/base/init.h>
9 #include <lib/base/nconfig.h>
10 #include <lib/base/object.h>
11 #include <lib/dvb/decoder.h>
12 #include <lib/components/file_eraser.h>
13 #include <lib/gui/esubtitle.h>
14 #include <lib/service/servicemp3.h>
15 #include <lib/service/service.h>
16 #include <lib/gdi/gpixmap.h>
17
18 #include <string>
19
20 #include <gst/gst.h>
21 #include <gst/pbutils/missing-plugins.h>
22 #include <sys/stat.h>
23
24 static GstStaticPadTemplate subsinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("text/plain; text/x-pango-markup; video/x-dvd-subpicture"));
25
26 // eServiceFactoryMP3
27
28 eServiceFactoryMP3::eServiceFactoryMP3()
29 {
30         ePtr<eServiceCenter> sc;
31         
32         eServiceCenter::getPrivInstance(sc);
33         if (sc)
34         {
35                 std::list<std::string> extensions;
36                 extensions.push_back("mp2");
37                 extensions.push_back("mp3");
38                 extensions.push_back("ogg");
39                 extensions.push_back("mpg");
40                 extensions.push_back("vob");
41                 extensions.push_back("wav");
42                 extensions.push_back("wave");
43                 extensions.push_back("m4v");
44                 extensions.push_back("mkv");
45                 extensions.push_back("avi");
46                 extensions.push_back("divx");
47                 extensions.push_back("dat");
48                 extensions.push_back("flac");
49                 extensions.push_back("mp4");
50                 extensions.push_back("mov");
51                 extensions.push_back("m4a");
52                 extensions.push_back("m2ts");
53                 sc->addServiceFactory(eServiceFactoryMP3::id, this, extensions);
54         }
55
56         m_service_info = new eStaticServiceMP3Info();
57 }
58
59 eServiceFactoryMP3::~eServiceFactoryMP3()
60 {
61         ePtr<eServiceCenter> sc;
62         
63         eServiceCenter::getPrivInstance(sc);
64         if (sc)
65                 sc->removeServiceFactory(eServiceFactoryMP3::id);
66 }
67
68 DEFINE_REF(eServiceFactoryMP3)
69
70         // iServiceHandler
71 RESULT eServiceFactoryMP3::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
72 {
73                 // check resources...
74         ptr = new eServiceMP3(ref);
75         return 0;
76 }
77
78 RESULT eServiceFactoryMP3::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
79 {
80         ptr=0;
81         return -1;
82 }
83
84 RESULT eServiceFactoryMP3::list(const eServiceReference &, ePtr<iListableService> &ptr)
85 {
86         ptr=0;
87         return -1;
88 }
89
90 RESULT eServiceFactoryMP3::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
91 {
92         ptr = m_service_info;
93         return 0;
94 }
95
96 class eMP3ServiceOfflineOperations: public iServiceOfflineOperations
97 {
98         DECLARE_REF(eMP3ServiceOfflineOperations);
99         eServiceReference m_ref;
100 public:
101         eMP3ServiceOfflineOperations(const eServiceReference &ref);
102         
103         RESULT deleteFromDisk(int simulate);
104         RESULT getListOfFilenames(std::list<std::string> &);
105         RESULT reindex();
106 };
107
108 DEFINE_REF(eMP3ServiceOfflineOperations);
109
110 eMP3ServiceOfflineOperations::eMP3ServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReference&)ref)
111 {
112 }
113
114 RESULT eMP3ServiceOfflineOperations::deleteFromDisk(int simulate)
115 {
116         if (simulate)
117                 return 0;
118         else
119         {
120                 std::list<std::string> res;
121                 if (getListOfFilenames(res))
122                         return -1;
123                 
124                 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
125                 if (!eraser)
126                         eDebug("FATAL !! can't get background file eraser");
127                 
128                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
129                 {
130                         eDebug("Removing %s...", i->c_str());
131                         if (eraser)
132                                 eraser->erase(i->c_str());
133                         else
134                                 ::unlink(i->c_str());
135                 }
136                 
137                 return 0;
138         }
139 }
140
141 RESULT eMP3ServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
142 {
143         res.clear();
144         res.push_back(m_ref.path);
145         return 0;
146 }
147
148 RESULT eMP3ServiceOfflineOperations::reindex()
149 {
150         return -1;
151 }
152
153
154 RESULT eServiceFactoryMP3::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
155 {
156         ptr = new eMP3ServiceOfflineOperations(ref);
157         return 0;
158 }
159
160 // eStaticServiceMP3Info
161
162
163 // eStaticServiceMP3Info is seperated from eServiceMP3 to give information
164 // about unopened files.
165
166 // probably eServiceMP3 should use this class as well, and eStaticServiceMP3Info
167 // should have a database backend where ID3-files etc. are cached.
168 // this would allow listing the mp3 database based on certain filters.
169
170 DEFINE_REF(eStaticServiceMP3Info)
171
172 eStaticServiceMP3Info::eStaticServiceMP3Info()
173 {
174 }
175
176 RESULT eStaticServiceMP3Info::getName(const eServiceReference &ref, std::string &name)
177 {
178         if ( ref.name.length() )
179                 name = ref.name;
180         else
181         {
182                 size_t last = ref.path.rfind('/');
183                 if (last != std::string::npos)
184                         name = ref.path.substr(last+1);
185                 else
186                         name = ref.path;
187         }
188         return 0;
189 }
190
191 int eStaticServiceMP3Info::getLength(const eServiceReference &ref)
192 {
193         return -1;
194 }
195
196 int eStaticServiceMP3Info::getInfo(const eServiceReference &ref, int w)
197 {
198         switch (w)
199         {
200         case iServiceInformation::sTimeCreate:
201         {
202                 struct stat s;
203                 if(stat(ref.path.c_str(), &s) == 0)
204                 {
205                   return s.st_mtime;
206                 }
207                 return iServiceInformation::resNA;
208         }
209         default: break;
210         }
211         return iServiceInformation::resNA;
212 }
213  
214
215 // eServiceMP3
216 int eServiceMP3::ac3_delay,
217     eServiceMP3::pcm_delay;
218
219 eServiceMP3::eServiceMP3(eServiceReference ref)
220         :m_ref(ref), m_pump(eApp, 1)
221 {
222         m_seekTimeout = eTimer::create(eApp);
223         m_subtitle_sync_timer = eTimer::create(eApp);
224         m_subtitle_hide_timer = eTimer::create(eApp);
225         m_stream_tags = 0;
226         m_currentAudioStream = -1;
227         m_currentSubtitleStream = 0;
228         m_subtitle_widget = 0;
229         m_currentTrickRatio = 0;
230         m_subs_to_pull = 0;
231         m_buffer_size = 1*1024*1024;
232         CONNECT(m_seekTimeout->timeout, eServiceMP3::seekTimeoutCB);
233         CONNECT(m_subtitle_sync_timer->timeout, eServiceMP3::pushSubtitles);
234         CONNECT(m_subtitle_hide_timer->timeout, eServiceMP3::hideSubtitles);
235         CONNECT(m_pump.recv_msg, eServiceMP3::gstPoll);
236         m_aspect = m_width = m_height = m_framerate = m_progressive = -1;
237
238         m_state = stIdle;
239         eDebug("eServiceMP3::construct!");
240
241         const char *filename = m_ref.path.c_str();
242         const char *ext = strrchr(filename, '.');
243         if (!ext)
244                 ext = filename;
245
246         sourceStream sourceinfo;
247         sourceinfo.is_video = FALSE;
248         sourceinfo.audiotype = atUnknown;
249         if ( (strcasecmp(ext, ".mpeg") && strcasecmp(ext, ".mpg") && strcasecmp(ext, ".vob") && strcasecmp(ext, ".bin") && strcasecmp(ext, ".dat") ) == 0 )
250         {
251                 sourceinfo.containertype = ctMPEGPS;
252                 sourceinfo.is_video = TRUE;
253         }
254         else if ( strcasecmp(ext, ".ts") == 0 )
255         {
256                 sourceinfo.containertype = ctMPEGTS;
257                 sourceinfo.is_video = TRUE;
258         }
259         else if ( strcasecmp(ext, ".mkv") == 0 )
260         {
261                 sourceinfo.containertype = ctMKV;
262                 sourceinfo.is_video = TRUE;
263         }
264         else if ( strcasecmp(ext, ".avi") == 0 || strcasecmp(ext, ".divx") == 0)
265         {
266                 sourceinfo.containertype = ctAVI;
267                 sourceinfo.is_video = TRUE;
268         }
269         else if ( strcasecmp(ext, ".mp4") == 0 || strcasecmp(ext, ".mov") == 0 || strcasecmp(ext, ".m4v") == 0)
270         {
271                 sourceinfo.containertype = ctMP4;
272                 sourceinfo.is_video = TRUE;
273         }
274         else if ( strcasecmp(ext, ".m4a") == 0 )
275         {
276                 sourceinfo.containertype = ctMP4;
277                 sourceinfo.audiotype = atAAC;
278         }
279         else if ( strcasecmp(ext, ".mp3") == 0 )
280                 sourceinfo.audiotype = atMP3;
281         else if ( (strncmp(filename, "/autofs/", 8) || strncmp(filename+strlen(filename)-13, "/track-", 7) || strcasecmp(ext, ".wav")) == 0 )
282                 sourceinfo.containertype = ctCDA;
283         if ( strcasecmp(ext, ".dat") == 0 )
284         {
285                 sourceinfo.containertype = ctVCD;
286                 sourceinfo.is_video = TRUE;
287         }
288         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 )
289                 sourceinfo.is_streaming = TRUE;
290
291         gchar *uri;
292
293         if ( sourceinfo.is_streaming )
294         {
295                 uri = g_strdup_printf ("%s", filename);
296         }
297         else if ( sourceinfo.containertype == ctCDA )
298         {
299                 int i_track = atoi(filename+18);
300                 uri = g_strdup_printf ("cdda://%i", i_track);
301         }
302         else if ( sourceinfo.containertype == ctVCD )
303         {
304                 int fd = open(filename,O_RDONLY);
305                 char tmp[128*1024];
306                 int ret = read(fd, tmp, 128*1024);
307                 close(fd);
308                 if ( ret == -1 ) // this is a "REAL" VCD
309                         uri = g_strdup_printf ("vcd://");
310                 else
311                         uri = g_filename_to_uri(filename, NULL, NULL);
312         }
313         else
314
315                 uri = g_filename_to_uri(filename, NULL, NULL);
316
317         eDebug("eServiceMP3::playbin2 uri=%s", uri);
318
319         m_gst_playbin = gst_element_factory_make("playbin2", "playbin");
320         if (!m_gst_playbin)
321                 m_error_message = "failed to create GStreamer pipeline!\n";
322
323         g_object_set (G_OBJECT (m_gst_playbin), "uri", uri, NULL);
324
325         int flags = 0x47; // ( GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_TEXT );
326         g_object_set (G_OBJECT (m_gst_playbin), "flags", flags, NULL);
327
328         g_free(uri);
329
330         m_gst_subtitlebin = gst_bin_new("subtitle_bin");
331         
332         if ( m_gst_playbin )
333         {
334                 GstElement *appsink = gst_element_factory_make("appsink", "subtitle_sink");
335
336                 if (!appsink)
337                         eDebug("eServiceMP3::sorry, can't play: missing gst-plugin-appsink");
338
339                 GstElement *dvdsubdec = gst_element_factory_make("dvdsubdec", "vobsubtitle_decoder");
340                 if ( !dvdsubdec )
341                         eDebug("eServiceMP3::sorry, can't play: missing gst-plugin-dvdsub");
342
343                 gst_bin_add_many(GST_BIN(m_gst_subtitlebin), dvdsubdec, appsink, NULL);
344                 
345 //              GstPad *ghostpad = gst_ghost_pad_new("sink", gst_element_get_static_pad (appsink, "sink"));
346
347                 GstPadTemplate *templ;
348                 templ = gst_static_pad_template_get (&subsinktemplate);
349   
350                 GstPad *ghostpad = gst_ghost_pad_new_no_target_from_template("sink", templ);
351                 gst_element_add_pad (m_gst_subtitlebin, ghostpad);
352
353                 g_signal_connect (ghostpad, "notify::caps", G_CALLBACK (gstCBsubtitleCAPS), this);
354
355                 GstCaps* caps = gst_caps_from_string("text/plain; text/x-pango-markup; video/x-raw-rgb");
356                 g_object_set (G_OBJECT (appsink), "caps", caps, NULL);
357                 gst_caps_unref(caps);
358                 
359 //              GstCaps* caps2 = gst_caps_from_string("text/plain; text/x-pango-markup; video/x-dvd-subpicture");
360 //              int ret = gst_pad_set_caps (ghostpad, caps2);
361 //              gst_caps_unref(caps2);
362                 
363                 g_object_set (G_OBJECT (dvdsubdec), "singlebuffer", TRUE, NULL);
364                 g_object_set (G_OBJECT (appsink), "async", FALSE, NULL);
365
366                 gst_pad_set_getcaps_function (ghostpad, gstGhostpadGetCAPS);
367
368                 eDebug("eServiceMP3::construct dvdsubdec=%p, appsink=%p, ghostpad=%p", dvdsubdec, appsink, ghostpad);
369                 
370                 g_object_set (G_OBJECT (m_gst_playbin), "text-sink", m_gst_subtitlebin, NULL);
371                 m_subs_to_pull_handler_id = g_signal_connect (appsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this);
372                 
373                 gst_bus_set_sync_handler(gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin)), gstBusSyncHandler, this);
374                 char srt_filename[strlen(filename)+1];
375                 strncpy(srt_filename,filename,strlen(filename)-3);
376                 srt_filename[strlen(filename)-3]='\0';
377                 strcat(srt_filename, "srt");
378                 struct stat buffer;
379                 if (stat(srt_filename, &buffer) == 0)
380                 {
381                         eDebug("eServiceMP3::subtitle uri: %s", g_filename_to_uri(srt_filename, NULL, NULL));
382                         g_object_set (G_OBJECT (m_gst_playbin), "suburi", g_filename_to_uri(srt_filename, NULL, NULL), NULL);
383                         subtitleStream subs;
384                         subs.type = stSRT;
385                         subs.language_code = std::string("und");
386                         m_subtitleStreams.push_back(subs);
387                 }
388         } else
389         {
390                 m_event((iPlayableService*)this, evUser+12);
391
392                 if (m_gst_playbin)
393                         gst_object_unref(GST_OBJECT(m_gst_playbin));
394
395                 eDebug("eServiceMP3::sorry, can't play: %s",m_error_message.c_str());
396                 m_gst_playbin = 0;
397         }
398
399         setBufferSize(m_buffer_size);
400 }
401
402 eServiceMP3::~eServiceMP3()
403 {
404         // disconnect subtitle callback
405         GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_subtitlebin), "subtitle_sink");
406 //      GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
407
408         if (appsink)
409         {
410                 g_signal_handler_disconnect (appsink, m_subs_to_pull_handler_id);
411                 gst_object_unref(appsink);
412         }
413
414         delete m_subtitle_widget;
415
416         // disconnect sync handler callback
417         gst_bus_set_sync_handler(gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin)), NULL, NULL);
418
419         if (m_state == stRunning)
420                 stop();
421
422         if (m_stream_tags)
423                 gst_tag_list_free(m_stream_tags);
424         
425         if (m_gst_playbin)
426         {
427                 gst_object_unref (GST_OBJECT (m_gst_playbin));
428                 eDebug("eServiceMP3::destruct!");
429         }
430 }
431
432 DEFINE_REF(eServiceMP3);
433
434 RESULT eServiceMP3::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
435 {
436         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
437         return 0;
438 }
439
440 RESULT eServiceMP3::start()
441 {
442         ASSERT(m_state == stIdle);
443
444         m_state = stRunning;
445         if (m_gst_playbin)
446         {
447                 eDebug("eServiceMP3::starting pipeline");
448                 gst_element_set_state (m_gst_playbin, GST_STATE_PLAYING);
449         }
450
451         m_event(this, evStart);
452
453         return 0;
454 }
455
456 RESULT eServiceMP3::stop()
457 {
458         ASSERT(m_state != stIdle);
459
460         if (m_state == stStopped)
461                 return -1;
462         
463         GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(m_gst_playbin),GST_DEBUG_GRAPH_SHOW_ALL,"e2-playbin");
464
465         eDebug("eServiceMP3::stop %s", m_ref.path.c_str());
466         gst_element_set_state(m_gst_playbin, GST_STATE_NULL);
467         m_state = stStopped;
468
469         return 0;
470 }
471
472 RESULT eServiceMP3::setTarget(int target)
473 {
474         return -1;
475 }
476
477 RESULT eServiceMP3::pause(ePtr<iPauseableService> &ptr)
478 {
479         ptr=this;
480         return 0;
481 }
482
483 RESULT eServiceMP3::setSlowMotion(int ratio)
484 {
485         if (!ratio)
486                 return 0;
487         eDebug("eServiceMP3::setSlowMotion ratio=%f",1/(float)ratio);
488         return trickSeek(1/(float)ratio);
489 }
490
491 RESULT eServiceMP3::setFastForward(int ratio)
492 {
493         eDebug("eServiceMP3::setFastForward ratio=%i",ratio);
494         return trickSeek(ratio);
495 }
496
497 void eServiceMP3::seekTimeoutCB()
498 {
499         pts_t ppos, len;
500         getPlayPosition(ppos);
501         getLength(len);
502         ppos += 90000*m_currentTrickRatio;
503         
504         if (ppos < 0)
505         {
506                 ppos = 0;
507                 m_seekTimeout->stop();
508         }
509         if (ppos > len)
510         {
511                 ppos = 0;
512                 stop();
513                 m_seekTimeout->stop();
514                 return;
515         }
516         seekTo(ppos);
517 }
518
519                 // iPausableService
520 RESULT eServiceMP3::pause()
521 {
522         if (!m_gst_playbin || m_state != stRunning)
523                 return -1;
524
525         gst_element_set_state(m_gst_playbin, GST_STATE_PAUSED);
526
527         return 0;
528 }
529
530 RESULT eServiceMP3::unpause()
531 {
532         if (!m_gst_playbin || m_state != stRunning)
533                 return -1;
534
535         gst_element_set_state(m_gst_playbin, GST_STATE_PLAYING);
536
537         return 0;
538 }
539
540         /* iSeekableService */
541 RESULT eServiceMP3::seek(ePtr<iSeekableService> &ptr)
542 {
543         ptr = this;
544         return 0;
545 }
546
547 RESULT eServiceMP3::getLength(pts_t &pts)
548 {
549         if (!m_gst_playbin)
550                 return -1;
551
552         if (m_state != stRunning)
553                 return -1;
554
555         GstFormat fmt = GST_FORMAT_TIME;
556         gint64 len;
557         
558         if (!gst_element_query_duration(m_gst_playbin, &fmt, &len))
559                 return -1;
560                 /* len is in nanoseconds. we have 90 000 pts per second. */
561         
562         pts = len / 11111;
563         return 0;
564 }
565
566 RESULT eServiceMP3::seekToImpl(pts_t to)
567 {
568                 /* convert pts to nanoseconds */
569         gint64 time_nanoseconds = to * 11111LL;
570         if (!gst_element_seek (m_gst_playbin, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
571                 GST_SEEK_TYPE_SET, time_nanoseconds,
572                 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
573         {
574                 eDebug("eServiceMP3::seekTo failed");
575                 return -1;
576         }
577
578         return 0;
579 }
580
581 RESULT eServiceMP3::seekTo(pts_t to)
582 {
583         RESULT ret = -1;
584
585         if (m_gst_playbin) {
586                 eSingleLocker l(m_subs_to_pull_lock); // this is needed to dont handle incomming subtitles during seek!
587                 if (!(ret = seekToImpl(to)))
588                 {
589                         m_subtitle_pages.clear();
590                         m_subs_to_pull = 0;
591                 }
592         }
593
594         return ret;
595 }
596
597
598 RESULT eServiceMP3::trickSeek(gdouble ratio)
599 {
600         if (!m_gst_playbin)
601                 return -1;
602         if (!ratio)
603                 return seekRelative(0, 0);
604
605         GstEvent *s_event;
606         int flags;
607         flags = GST_SEEK_FLAG_NONE;
608         flags |= GST_SEEK_FLAG_FLUSH;
609 //      flags |= GstSeekFlags (GST_SEEK_FLAG_ACCURATE);
610         flags |= GST_SEEK_FLAG_KEY_UNIT;
611 //      flags |= GstSeekFlags (GST_SEEK_FLAG_SEGMENT);
612 //      flags |= GstSeekFlags (GST_SEEK_FLAG_SKIP);
613
614         GstFormat fmt = GST_FORMAT_TIME;
615         gint64 pos, len;
616         gst_element_query_duration(m_gst_playbin, &fmt, &len);
617         gst_element_query_position(m_gst_playbin, &fmt, &pos);
618
619         if ( ratio >= 0 )
620         {
621                 s_event = gst_event_new_seek (ratio, GST_FORMAT_TIME, (GstSeekFlags)flags, GST_SEEK_TYPE_SET, pos, GST_SEEK_TYPE_SET, len);
622
623                 eDebug("eServiceMP3::trickSeek with rate %lf to %" GST_TIME_FORMAT " ", ratio, GST_TIME_ARGS (pos));
624         }
625         else
626         {
627                 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);
628         }
629
630         if (!gst_element_send_event ( GST_ELEMENT (m_gst_playbin), s_event))
631         {
632                 eDebug("eServiceMP3::trickSeek failed");
633                 return -1;
634         }
635
636         return 0;
637 }
638
639
640 RESULT eServiceMP3::seekRelative(int direction, pts_t to)
641 {
642         if (!m_gst_playbin)
643                 return -1;
644
645         pts_t ppos;
646         getPlayPosition(ppos);
647         ppos += to * direction;
648         if (ppos < 0)
649                 ppos = 0;
650         seekTo(ppos);
651         
652         return 0;
653 }
654
655 RESULT eServiceMP3::getPlayPosition(pts_t &pts)
656 {
657         GstFormat fmt = GST_FORMAT_TIME;
658         gint64 pos;
659         GstElement *sink;
660         pts = 0;
661
662         if (!m_gst_playbin)
663                 return -1;
664         if (m_state != stRunning)
665                 return -1;
666
667         g_object_get (G_OBJECT (m_gst_playbin), "audio-sink", &sink, NULL);
668
669         if (!sink)
670                 g_object_get (G_OBJECT (m_gst_playbin), "video-sink", &sink, NULL);
671
672         if (!sink)
673                 return -1;
674
675         gchar *name = gst_element_get_name(sink);
676         gboolean use_get_decoder_time = strstr(name, "dvbaudiosink") || strstr(name, "dvbvideosink");
677         g_free(name);
678
679         if (use_get_decoder_time)
680                 g_signal_emit_by_name(sink, "get-decoder-time", &pos);
681
682         gst_object_unref(sink);
683
684         if (!use_get_decoder_time && !gst_element_query_position(m_gst_playbin, &fmt, &pos)) {
685                 eDebug("gst_element_query_position failed in getPlayPosition");
686                 return -1;
687         }
688
689         /* pos is in nanoseconds. we have 90 000 pts per second. */
690         pts = pos / 11111;
691 //      eDebug("gst_element_query_position %lld pts (%lld ms)", pts, pos/1000000);
692         return 0;
693 }
694
695 RESULT eServiceMP3::setTrickmode(int trick)
696 {
697                 /* trickmode is not yet supported by our dvbmediasinks. */
698         return -1;
699 }
700
701 RESULT eServiceMP3::isCurrentlySeekable()
702 {
703         int ret = 3; // seeking and fast/slow winding possible
704         GstElement *sink;
705
706         if (!m_gst_playbin)
707                 return 0;
708         if (m_state != stRunning)
709                 return 0;
710
711         g_object_get (G_OBJECT (m_gst_playbin), "video-sink", &sink, NULL);
712
713         // disable fast winding yet when a dvbvideosink or dvbaudiosink is used
714         // for this we must do some changes on different places.. (gstreamer.. our sinks.. enigma2)
715         if (sink) {
716                 ret &= ~2; // only seeking possible
717                 gst_object_unref(sink);
718         }
719         else {
720                 g_object_get (G_OBJECT (m_gst_playbin), "audio-sink", &sink, NULL);
721                 if (sink) {
722                         ret &= ~2; // only seeking possible
723                         gst_object_unref(sink);
724                 }
725         }
726
727         return ret;
728 }
729
730 RESULT eServiceMP3::info(ePtr<iServiceInformation>&i)
731 {
732         i = this;
733         return 0;
734 }
735
736 RESULT eServiceMP3::getName(std::string &name)
737 {
738         std::string title = m_ref.getName();
739         if (title.empty())
740         {
741                 name = m_ref.path;
742                 size_t n = name.rfind('/');
743                 if (n != std::string::npos)
744                         name = name.substr(n + 1);
745         }
746         else
747                 name = title;
748         return 0;
749 }
750
751 int eServiceMP3::getInfo(int w)
752 {
753         const gchar *tag = 0;
754
755         switch (w)
756         {
757         case sServiceref: return m_ref;
758         case sVideoHeight: return m_height;
759         case sVideoWidth: return m_width;
760         case sFrameRate: return m_framerate;
761         case sProgressive: return m_progressive;
762         case sAspect: return m_aspect;
763         case sTagTitle:
764         case sTagArtist:
765         case sTagAlbum:
766         case sTagTitleSortname:
767         case sTagArtistSortname:
768         case sTagAlbumSortname:
769         case sTagDate:
770         case sTagComposer:
771         case sTagGenre:
772         case sTagComment:
773         case sTagExtendedComment:
774         case sTagLocation:
775         case sTagHomepage:
776         case sTagDescription:
777         case sTagVersion:
778         case sTagISRC:
779         case sTagOrganization:
780         case sTagCopyright:
781         case sTagCopyrightURI:
782         case sTagContact:
783         case sTagLicense:
784         case sTagLicenseURI:
785         case sTagCodec:
786         case sTagAudioCodec:
787         case sTagVideoCodec:
788         case sTagEncoder:
789         case sTagLanguageCode:
790         case sTagKeywords:
791         case sTagChannelMode:
792         case sUser+12:
793                 return resIsString;
794         case sTagTrackGain:
795         case sTagTrackPeak:
796         case sTagAlbumGain:
797         case sTagAlbumPeak:
798         case sTagReferenceLevel:
799         case sTagBeatsPerMinute:
800         case sTagImage:
801         case sTagPreviewImage:
802         case sTagAttachment:
803                 return resIsPyObject;
804         case sTagTrackNumber:
805                 tag = GST_TAG_TRACK_NUMBER;
806                 break;
807         case sTagTrackCount:
808                 tag = GST_TAG_TRACK_COUNT;
809                 break;
810         case sTagAlbumVolumeNumber:
811                 tag = GST_TAG_ALBUM_VOLUME_NUMBER;
812                 break;
813         case sTagAlbumVolumeCount:
814                 tag = GST_TAG_ALBUM_VOLUME_COUNT;
815                 break;
816         case sTagBitrate:
817                 tag = GST_TAG_BITRATE;
818                 break;
819         case sTagNominalBitrate:
820                 tag = GST_TAG_NOMINAL_BITRATE;
821                 break;
822         case sTagMinimumBitrate:
823                 tag = GST_TAG_MINIMUM_BITRATE;
824                 break;
825         case sTagMaximumBitrate:
826                 tag = GST_TAG_MAXIMUM_BITRATE;
827                 break;
828         case sTagSerial:
829                 tag = GST_TAG_SERIAL;
830                 break;
831         case sTagEncoderVersion:
832                 tag = GST_TAG_ENCODER_VERSION;
833                 break;
834         case sTagCRC:
835                 tag = "has-crc";
836                 break;
837         default:
838                 return resNA;
839         }
840
841         if (!m_stream_tags || !tag)
842                 return 0;
843         
844         guint value;
845         if (gst_tag_list_get_uint(m_stream_tags, tag, &value))
846                 return (int) value;
847
848         return 0;
849 }
850
851 std::string eServiceMP3::getInfoString(int w)
852 {
853         if ( !m_stream_tags && w < sUser && w > 26 )
854                 return "";
855         const gchar *tag = 0;
856         switch (w)
857         {
858         case sTagTitle:
859                 tag = GST_TAG_TITLE;
860                 break;
861         case sTagArtist:
862                 tag = GST_TAG_ARTIST;
863                 break;
864         case sTagAlbum:
865                 tag = GST_TAG_ALBUM;
866                 break;
867         case sTagTitleSortname:
868                 tag = GST_TAG_TITLE_SORTNAME;
869                 break;
870         case sTagArtistSortname:
871                 tag = GST_TAG_ARTIST_SORTNAME;
872                 break;
873         case sTagAlbumSortname:
874                 tag = GST_TAG_ALBUM_SORTNAME;
875                 break;
876         case sTagDate:
877                 GDate *date;
878                 if (gst_tag_list_get_date(m_stream_tags, GST_TAG_DATE, &date))
879                 {
880                         gchar res[5];
881                         g_date_strftime (res, sizeof(res), "%Y-%M-%D", date); 
882                         return (std::string)res;
883                 }
884                 break;
885         case sTagComposer:
886                 tag = GST_TAG_COMPOSER;
887                 break;
888         case sTagGenre:
889                 tag = GST_TAG_GENRE;
890                 break;
891         case sTagComment:
892                 tag = GST_TAG_COMMENT;
893                 break;
894         case sTagExtendedComment:
895                 tag = GST_TAG_EXTENDED_COMMENT;
896                 break;
897         case sTagLocation:
898                 tag = GST_TAG_LOCATION;
899                 break;
900         case sTagHomepage:
901                 tag = GST_TAG_HOMEPAGE;
902                 break;
903         case sTagDescription:
904                 tag = GST_TAG_DESCRIPTION;
905                 break;
906         case sTagVersion:
907                 tag = GST_TAG_VERSION;
908                 break;
909         case sTagISRC:
910                 tag = GST_TAG_ISRC;
911                 break;
912         case sTagOrganization:
913                 tag = GST_TAG_ORGANIZATION;
914                 break;
915         case sTagCopyright:
916                 tag = GST_TAG_COPYRIGHT;
917                 break;
918         case sTagCopyrightURI:
919                 tag = GST_TAG_COPYRIGHT_URI;
920                 break;
921         case sTagContact:
922                 tag = GST_TAG_CONTACT;
923                 break;
924         case sTagLicense:
925                 tag = GST_TAG_LICENSE;
926                 break;
927         case sTagLicenseURI:
928                 tag = GST_TAG_LICENSE_URI;
929                 break;
930         case sTagCodec:
931                 tag = GST_TAG_CODEC;
932                 break;
933         case sTagAudioCodec:
934                 tag = GST_TAG_AUDIO_CODEC;
935                 break;
936         case sTagVideoCodec:
937                 tag = GST_TAG_VIDEO_CODEC;
938                 break;
939         case sTagEncoder:
940                 tag = GST_TAG_ENCODER;
941                 break;
942         case sTagLanguageCode:
943                 tag = GST_TAG_LANGUAGE_CODE;
944                 break;
945         case sTagKeywords:
946                 tag = GST_TAG_KEYWORDS;
947                 break;
948         case sTagChannelMode:
949                 tag = "channel-mode";
950                 break;
951         case sUser+12:
952                 return m_error_message;
953         default:
954                 return "";
955         }
956         if ( !tag )
957                 return "";
958         gchar *value;
959         if (gst_tag_list_get_string(m_stream_tags, tag, &value))
960         {
961                 std::string res = value;
962                 g_free(value);
963                 return res;
964         }
965         return "";
966 }
967
968 PyObject *eServiceMP3::getInfoObject(int w)
969 {
970         const gchar *tag = 0;
971         bool isBuffer = false;
972         switch (w)
973         {
974                 case sTagTrackGain:
975                         tag = GST_TAG_TRACK_GAIN;
976                         break;
977                 case sTagTrackPeak:
978                         tag = GST_TAG_TRACK_PEAK;
979                         break;
980                 case sTagAlbumGain:
981                         tag = GST_TAG_ALBUM_GAIN;
982                         break;
983                 case sTagAlbumPeak:
984                         tag = GST_TAG_ALBUM_PEAK;
985                         break;
986                 case sTagReferenceLevel:
987                         tag = GST_TAG_REFERENCE_LEVEL;
988                         break;
989                 case sTagBeatsPerMinute:
990                         tag = GST_TAG_BEATS_PER_MINUTE;
991                         break;
992                 case sTagImage:
993                         tag = GST_TAG_IMAGE;
994                         isBuffer = true;
995                         break;
996                 case sTagPreviewImage:
997                         tag = GST_TAG_PREVIEW_IMAGE;
998                         isBuffer = true;
999                         break;
1000                 case sTagAttachment:
1001                         tag = GST_TAG_ATTACHMENT;
1002                         isBuffer = true;
1003                         break;
1004                 default:
1005                         break;
1006         }
1007
1008         if ( isBuffer )
1009         {
1010                 const GValue *gv_buffer = gst_tag_list_get_value_index(m_stream_tags, tag, 0);
1011                 if ( gv_buffer )
1012                 {
1013                         GstBuffer *buffer;
1014                         buffer = gst_value_get_buffer (gv_buffer);
1015                         return PyBuffer_FromMemory(GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
1016                 }
1017         }
1018         else
1019         {
1020                 gdouble value = 0.0;
1021                 gst_tag_list_get_double(m_stream_tags, tag, &value);
1022                 return PyFloat_FromDouble(value);
1023         }
1024
1025         return 0;
1026 }
1027
1028 RESULT eServiceMP3::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1029 {
1030         ptr = this;
1031         return 0;
1032 }
1033
1034 RESULT eServiceMP3::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1035 {
1036         ptr = this;
1037         return 0;
1038 }
1039
1040 RESULT eServiceMP3::subtitle(ePtr<iSubtitleOutput> &ptr)
1041 {
1042         ptr = this;
1043         return 0;
1044 }
1045
1046 RESULT eServiceMP3::audioDelay(ePtr<iAudioDelay> &ptr)
1047 {
1048         ptr = this;
1049         return 0;
1050 }
1051
1052 int eServiceMP3::getNumberOfTracks()
1053 {
1054         return m_audioStreams.size();
1055 }
1056
1057 int eServiceMP3::getCurrentTrack()
1058 {
1059         if (m_currentAudioStream == -1)
1060                 g_object_get (G_OBJECT (m_gst_playbin), "current-audio", &m_currentAudioStream, NULL);
1061         return m_currentAudioStream;
1062 }
1063
1064 RESULT eServiceMP3::selectTrack(unsigned int i)
1065 {
1066         pts_t ppos;
1067         getPlayPosition(ppos);
1068         ppos -= 90000;
1069         if (ppos < 0)
1070                 ppos = 0;
1071
1072         int ret = selectAudioStream(i);
1073         if (!ret) {
1074                 /* flush */
1075                 seekTo(ppos);
1076         }
1077
1078         return ret;
1079 }
1080
1081 int eServiceMP3::selectAudioStream(int i)
1082 {
1083         int current_audio;
1084         g_object_set (G_OBJECT (m_gst_playbin), "current-audio", i, NULL);
1085         g_object_get (G_OBJECT (m_gst_playbin), "current-audio", &current_audio, NULL);
1086         if ( current_audio == i )
1087         {
1088                 eDebug ("eServiceMP3::switched to audio stream %i", current_audio);
1089                 m_currentAudioStream = i;
1090                 return 0;
1091         }
1092         return -1;
1093 }
1094
1095 int eServiceMP3::getCurrentChannel()
1096 {
1097         return STEREO;
1098 }
1099
1100 RESULT eServiceMP3::selectChannel(int i)
1101 {
1102         eDebug("eServiceMP3::selectChannel(%i)",i);
1103         return 0;
1104 }
1105
1106 RESULT eServiceMP3::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1107 {
1108         if (i >= m_audioStreams.size())
1109                 return -2;
1110                 info.m_description = m_audioStreams[i].codec;
1111 /*      if (m_audioStreams[i].type == atMPEG)
1112                 info.m_description = "MPEG";
1113         else if (m_audioStreams[i].type == atMP3)
1114                 info.m_description = "MP3";
1115         else if (m_audioStreams[i].type == atAC3)
1116                 info.m_description = "AC3";
1117         else if (m_audioStreams[i].type == atAAC)
1118                 info.m_description = "AAC";
1119         else if (m_audioStreams[i].type == atDTS)
1120                 info.m_description = "DTS";
1121         else if (m_audioStreams[i].type == atPCM)
1122                 info.m_description = "PCM";
1123         else if (m_audioStreams[i].type == atOGG)
1124                 info.m_description = "OGG";
1125         else if (m_audioStreams[i].type == atFLAC)
1126                 info.m_description = "FLAC";
1127         else
1128                 info.m_description = "???";*/
1129         if (info.m_language.empty())
1130                 info.m_language = m_audioStreams[i].language_code;
1131         return 0;
1132 }
1133
1134 subtype_t getSubtitleType(GstPad* pad, gchar *g_codec=NULL)
1135 {
1136         subtype_t type = stUnknown;
1137         GstCaps* caps = gst_pad_get_negotiated_caps(pad);
1138
1139         if ( caps )
1140         {
1141                 GstStructure* str = gst_caps_get_structure(caps, 0);
1142                 const gchar *g_type = gst_structure_get_name(str);
1143                 eDebug("getSubtitleType::subtitle probe caps type=%s", g_type);
1144
1145                 if ( !strcmp(g_type, "video/x-dvd-subpicture") )
1146                         type = stVOB;
1147                 else if ( !strcmp(g_type, "text/x-pango-markup") )
1148                         type = stSSA;
1149                 else if ( !strcmp(g_type, "text/plain") )
1150                         type = stPlainText;
1151                 else
1152                         eDebug("getSubtitleType::unsupported subtitle caps %s (%s)", g_type, g_codec);
1153         }
1154         else if ( g_codec )
1155         {
1156                 eDebug("getSubtitleType::subtitle probe codec tag=%s", g_codec);
1157                 if ( !strcmp(g_codec, "VOB") )
1158                         type = stVOB;
1159                 else if ( !strcmp(g_codec, "SubStation Alpha") || !strcmp(g_codec, "SSA") )
1160                         type = stSSA;
1161                 else if ( !strcmp(g_codec, "ASS") )
1162                         type = stASS;
1163                 else if ( !strcmp(g_codec, "UTF-8 plain text") )
1164                         type = stPlainText;
1165                 else
1166                         eDebug("getSubtitleType::unsupported subtitle codec %s", g_codec);
1167         }
1168         else
1169                 eDebug("getSubtitleType::unidentifiable subtitle stream!");
1170
1171         return type;
1172 }
1173
1174 void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
1175 {
1176         if (!msg)
1177                 return;
1178         gchar *sourceName;
1179         GstObject *source;
1180
1181         source = GST_MESSAGE_SRC(msg);
1182         sourceName = gst_object_get_name(source);
1183 #if 1
1184         if (gst_message_get_structure(msg))
1185         {
1186                 gchar *string = gst_structure_to_string(gst_message_get_structure(msg));
1187                 eDebug("eServiceMP3::gst_message from %s: %s", sourceName, string);
1188                 g_free(string);
1189         }
1190         else
1191                 eDebug("eServiceMP3::gst_message from %s: %s (without structure)", sourceName, GST_MESSAGE_TYPE_NAME(msg));
1192 #endif
1193         switch (GST_MESSAGE_TYPE (msg))
1194         {
1195                 case GST_MESSAGE_EOS:
1196                         m_event((iPlayableService*)this, evEOF);
1197                         break;
1198                 case GST_MESSAGE_STATE_CHANGED:
1199                 {
1200                         if(GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin))
1201                                 break;
1202
1203                         GstState old_state, new_state;
1204                         gst_message_parse_state_changed(msg, &old_state, &new_state, NULL);
1205                 
1206                         if(old_state == new_state)
1207                                 break;
1208         
1209                         eDebug("eServiceMP3::state transition %s -> %s", gst_element_state_get_name(old_state), gst_element_state_get_name(new_state));
1210         
1211                         GstStateChange transition = (GstStateChange)GST_STATE_TRANSITION(old_state, new_state);
1212         
1213                         switch(transition)
1214                         {
1215                                 case GST_STATE_CHANGE_NULL_TO_READY:
1216                                 {
1217                                 }       break;
1218                                 case GST_STATE_CHANGE_READY_TO_PAUSED:
1219                                 {
1220                                         GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_subtitlebin), "subtitle_sink");
1221 //                                      GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
1222                                         if (appsink)
1223                                         {
1224                                                 g_object_set (G_OBJECT (appsink), "max-buffers", 2, NULL);
1225                                                 g_object_set (G_OBJECT (appsink), "sync", FALSE, NULL);
1226                                                 g_object_set (G_OBJECT (appsink), "emit-signals", TRUE, NULL);
1227                                                 eDebug("eServiceMP3::appsink properties set!");
1228                                                 gst_object_unref(appsink);
1229                                         }
1230                                         setAC3Delay(ac3_delay);
1231                                         setPCMDelay(pcm_delay);
1232                                 }       break;
1233                                 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1234                                 {
1235                                 }       break;
1236                                 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1237                                 {
1238                                 }       break;
1239                                 case GST_STATE_CHANGE_PAUSED_TO_READY:
1240                                 {
1241                                 }       break;
1242                                 case GST_STATE_CHANGE_READY_TO_NULL:
1243                                 {
1244                                 }       break;
1245                         }
1246                         break;
1247                 }
1248                 case GST_MESSAGE_ERROR:
1249                 {
1250                         gchar *debug;
1251                         GError *err;
1252                         gst_message_parse_error (msg, &err, &debug);
1253                         g_free (debug);
1254                         eWarning("Gstreamer error: %s (%i) from %s", err->message, err->code, sourceName );
1255                         if ( err->domain == GST_STREAM_ERROR )
1256                         {
1257                                 if ( err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND )
1258                                 {
1259                                         if ( g_strrstr(sourceName, "videosink") )
1260                                                 m_event((iPlayableService*)this, evUser+11);
1261                                         else if ( g_strrstr(sourceName, "audiosink") )
1262                                                 m_event((iPlayableService*)this, evUser+10);
1263                                 }
1264                         }
1265                         g_error_free(err);
1266                         break;
1267                 }
1268                 case GST_MESSAGE_INFO:
1269                 {
1270                         gchar *debug;
1271                         GError *inf;
1272         
1273                         gst_message_parse_info (msg, &inf, &debug);
1274                         g_free (debug);
1275                         if ( inf->domain == GST_STREAM_ERROR && inf->code == GST_STREAM_ERROR_DECODE )
1276                         {
1277                                 if ( g_strrstr(sourceName, "videosink") )
1278                                         m_event((iPlayableService*)this, evUser+14);
1279                         }
1280                         g_error_free(inf);
1281                         break;
1282                 }
1283                 case GST_MESSAGE_TAG:
1284                 {
1285                         GstTagList *tags, *result;
1286                         gst_message_parse_tag(msg, &tags);
1287         
1288                         result = gst_tag_list_merge(m_stream_tags, tags, GST_TAG_MERGE_REPLACE);
1289                         if (result)
1290                         {
1291                                 if (m_stream_tags)
1292                                         gst_tag_list_free(m_stream_tags);
1293                                 m_stream_tags = result;
1294                         }
1295         
1296                         const GValue *gv_image = gst_tag_list_get_value_index(tags, GST_TAG_IMAGE, 0);
1297                         if ( gv_image )
1298                         {
1299                                 GstBuffer *buf_image;
1300                                 buf_image = gst_value_get_buffer (gv_image);
1301                                 int fd = open("/tmp/.id3coverart", O_CREAT|O_WRONLY|O_TRUNC, 0644);
1302                                 int ret = write(fd, GST_BUFFER_DATA(buf_image), GST_BUFFER_SIZE(buf_image));
1303                                 close(fd);
1304                                 eDebug("eServiceMP3::/tmp/.id3coverart %d bytes written ", ret);
1305                                 m_event((iPlayableService*)this, evUser+13);
1306                         }
1307                         gst_tag_list_free(tags);
1308                         m_event((iPlayableService*)this, evUpdatedInfo);
1309                         break;
1310                 }
1311                 case GST_MESSAGE_ASYNC_DONE:
1312                 {
1313                         if(GST_MESSAGE_SRC(msg) != GST_OBJECT(m_gst_playbin))
1314                                 break;
1315
1316                         GstTagList *tags;
1317                         gint i, active_idx, n_video = 0, n_audio = 0, n_text = 0;
1318
1319                         g_object_get (m_gst_playbin, "n-video", &n_video, NULL);
1320                         g_object_get (m_gst_playbin, "n-audio", &n_audio, NULL);
1321                         g_object_get (m_gst_playbin, "n-text", &n_text, NULL);
1322
1323                         eDebug("eServiceMP3::async-done - %d video, %d audio, %d subtitle", n_video, n_audio, n_text);
1324
1325                         if ( n_video + n_audio <= 0 )
1326                                 stop();
1327
1328                         active_idx = 0;
1329
1330                         m_audioStreams.clear();
1331                         m_subtitleStreams.clear();
1332
1333                         for (i = 0; i < n_audio; i++)
1334                         {
1335                                 audioStream audio;
1336                                 gchar *g_codec, *g_lang;
1337                                 GstPad* pad = 0;
1338                                 g_signal_emit_by_name (m_gst_playbin, "get-audio-pad", i, &pad);
1339                                 GstCaps* caps = gst_pad_get_negotiated_caps(pad);
1340                                 if (!caps)
1341                                         continue;
1342                                 GstStructure* str = gst_caps_get_structure(caps, 0);
1343                                 const gchar *g_type = gst_structure_get_name(str);
1344                                 audio.type = gstCheckAudioPad(str);
1345                                 g_codec = g_strdup(g_type);
1346                                 g_lang = g_strdup_printf ("und");
1347                                 g_signal_emit_by_name (m_gst_playbin, "get-audio-tags", i, &tags);
1348                                 if ( tags && gst_is_tag_list(tags) )
1349                                 {
1350                                         gst_tag_list_get_string(tags, GST_TAG_AUDIO_CODEC, &g_codec);
1351                                         gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang);
1352                                         gst_tag_list_free(tags);
1353                                 }
1354                                 audio.language_code = std::string(g_lang);
1355                                 audio.codec = std::string(g_codec);
1356                                 eDebug("eServiceMP3::audio stream=%i codec=%s language=%s", i, g_codec, g_lang);
1357                                 m_audioStreams.push_back(audio);
1358                                 g_free (g_lang);
1359                                 g_free (g_codec);
1360                                 gst_caps_unref(caps);
1361                         }
1362
1363                         for (i = 0; i < n_text; i++)
1364                         {
1365                                 gchar *g_codec = NULL, *g_lang = NULL;
1366                                 g_signal_emit_by_name (m_gst_playbin, "get-text-tags", i, &tags);
1367                                 subtitleStream subs;
1368                                 int ret;
1369
1370                                 g_lang = g_strdup_printf ("und");
1371                                 if ( tags && gst_is_tag_list(tags) )
1372                                 {
1373                                         gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang);
1374                                         gst_tag_list_get_string(tags, GST_TAG_SUBTITLE_CODEC, &g_codec);
1375                                         gst_tag_list_free(tags);
1376                                 }
1377
1378                                 subs.language_code = std::string(g_lang);
1379                                 eDebug("eServiceMP3::subtitle stream=%i language=%s codec=%s", i, g_lang, g_codec);
1380                                 
1381                                 GstPad* pad = 0;
1382                                 g_signal_emit_by_name (m_gst_playbin, "get-text-pad", i, &pad);
1383                                 if ( subs.type != stSRT )
1384                                         subs.type = getSubtitleType(pad, g_codec);
1385
1386                                 m_subtitleStreams.push_back(subs);
1387                                 g_free (g_lang);
1388                         }
1389                         m_event((iPlayableService*)this, evUpdatedEventInfo);
1390                 }
1391                 case GST_MESSAGE_ELEMENT:
1392                 {
1393                         if ( gst_is_missing_plugin_message(msg) )
1394                         {
1395                                 gchar *description = gst_missing_plugin_message_get_description(msg);
1396                                 if ( description )
1397                                 {
1398                                         m_error_message = "GStreamer plugin " + (std::string)description + " not available!\n";
1399                                         g_free(description);
1400                                         m_event((iPlayableService*)this, evUser+12);
1401                                 }
1402                         }
1403                         else if (const GstStructure *msgstruct = gst_message_get_structure(msg))
1404                         {
1405                                 const gchar *eventname = gst_structure_get_name(msgstruct);
1406                                 if ( eventname )
1407                                 {
1408                                         if (!strcmp(eventname, "eventSizeChanged") || !strcmp(eventname, "eventSizeAvail"))
1409                                         {
1410                                                 gst_structure_get_int (msgstruct, "aspect_ratio", &m_aspect);
1411                                                 gst_structure_get_int (msgstruct, "width", &m_width);
1412                                                 gst_structure_get_int (msgstruct, "height", &m_height);
1413                                                 if (strstr(eventname, "Changed"))
1414                                                         m_event((iPlayableService*)this, evVideoSizeChanged);
1415                                         }
1416                                         else if (!strcmp(eventname, "eventFrameRateChanged") || !strcmp(eventname, "eventFrameRateAvail"))
1417                                         {
1418                                                 gst_structure_get_int (msgstruct, "frame_rate", &m_framerate);
1419                                                 if (strstr(eventname, "Changed"))
1420                                                         m_event((iPlayableService*)this, evVideoFramerateChanged);
1421                                         }
1422                                         else if (!strcmp(eventname, "eventProgressiveChanged") || !strcmp(eventname, "eventProgressiveAvail"))
1423                                         {
1424                                                 gst_structure_get_int (msgstruct, "progressive", &m_progressive);
1425                                                 if (strstr(eventname, "Changed"))
1426                                                         m_event((iPlayableService*)this, evVideoProgressiveChanged);
1427                                         }
1428                                 }
1429                         }
1430                         break;
1431                 }
1432                 case GST_MESSAGE_BUFFERING:
1433                 {
1434                         GstBufferingMode mode;
1435                         gst_message_parse_buffering(msg, &(m_bufferInfo.bufferPercent));
1436                         gst_message_parse_buffering_stats(msg, &mode, &(m_bufferInfo.avgInRate), &(m_bufferInfo.avgOutRate), &(m_bufferInfo.bufferingLeft));
1437                         m_event((iPlayableService*)this, evBuffering);
1438                 }
1439                 default:
1440                         break;
1441         }
1442         g_free (sourceName);
1443 }
1444
1445 GstBusSyncReply eServiceMP3::gstBusSyncHandler(GstBus *bus, GstMessage *message, gpointer user_data)
1446 {
1447         eServiceMP3 *_this = (eServiceMP3*)user_data;
1448         _this->m_pump.send(1);
1449                 /* wake */
1450         return GST_BUS_PASS;
1451 }
1452
1453 audiotype_t eServiceMP3::gstCheckAudioPad(GstStructure* structure)
1454 {
1455         if (!structure)
1456                 return atUnknown;
1457
1458         if ( gst_structure_has_name (structure, "audio/mpeg"))
1459         {
1460                 gint mpegversion, layer = -1;
1461                 if (!gst_structure_get_int (structure, "mpegversion", &mpegversion))
1462                         return atUnknown;
1463
1464                 switch (mpegversion) {
1465                         case 1:
1466                                 {
1467                                         gst_structure_get_int (structure, "layer", &layer);
1468                                         if ( layer == 3 )
1469                                                 return atMP3;
1470                                         else
1471                                                 return atMPEG;
1472                                         break;
1473                                 }
1474                         case 2:
1475                                 return atAAC;
1476                         case 4:
1477                                 return atAAC;
1478                         default:
1479                                 return atUnknown;
1480                 }
1481         }
1482
1483         else if ( gst_structure_has_name (structure, "audio/x-ac3") || gst_structure_has_name (structure, "audio/ac3") )
1484                 return atAC3;
1485         else if ( gst_structure_has_name (structure, "audio/x-dts") || gst_structure_has_name (structure, "audio/dts") )
1486                 return atDTS;
1487         else if ( gst_structure_has_name (structure, "audio/x-raw-int") )
1488                 return atPCM;
1489
1490         return atUnknown;
1491 }
1492
1493 void eServiceMP3::gstPoll(const int &msg)
1494 {
1495                 /* ok, we have a serious problem here. gstBusSyncHandler sends 
1496                    us the wakup signal, but likely before it was posted.
1497                    the usleep, an EVIL HACK (DON'T DO THAT!!!) works around this.
1498                    
1499                    I need to understand the API a bit more to make this work 
1500                    proplerly. */
1501         if (msg == 1)
1502         {
1503                 GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin));
1504                 GstMessage *message;
1505                 usleep(1);
1506                 while ((message = gst_bus_pop (bus)))
1507                 {
1508                         gstBusCall(bus, message);
1509                         gst_message_unref (message);
1510                 }
1511         }
1512         else
1513                 pullSubtitle();
1514 }
1515
1516 eAutoInitPtr<eServiceFactoryMP3> init_eServiceFactoryMP3(eAutoInitNumbers::service+1, "eServiceFactoryMP3");
1517
1518 void eServiceMP3::gstCBsubtitleAvail(GstElement *appsink, gpointer user_data)
1519 {
1520         eServiceMP3 *_this = (eServiceMP3*)user_data;   
1521         eSingleLocker l(_this->m_subs_to_pull_lock);
1522         ++_this->m_subs_to_pull;
1523         _this->m_pump.send(2);
1524 }
1525
1526 GstCaps* eServiceMP3::gstGhostpadGetCAPS (GstPad * pad)
1527 {
1528         eDebug("eServiceMP3::gstGhostpadGetCAPS");
1529         return gst_static_pad_template_get_caps(&subsinktemplate);
1530 //      return gst_pad_get_pad_template_caps(pad);
1531 //      return get_pad_template_caps(pad);
1532 //      GstCaps* caps = gst_caps_from_string("text/plain; text/x-pango-markup; video/x-dvd-subpicture");
1533 //      return caps;
1534 }
1535
1536 void eServiceMP3::gstCBsubtitleCAPS(GObject *obj, GParamSpec *pspec, gpointer user_data)
1537 {
1538         eDebug("gstCBsubtitleCAPS:: signal::caps callback obj=%p", obj);
1539
1540         eServiceMP3 *_this = (eServiceMP3*)user_data;
1541         eDebug("gstCBsubtitleCAPS:: m_currentSubtitleStream=%i, m_subtitleStreams.size()=%i", _this->m_currentSubtitleStream, _this->m_subtitleStreams.size());
1542
1543         if ( _this->m_currentSubtitleStream >= (int)_this->m_subtitleStreams.size() )
1544         {
1545                 eDebug("return invalid stream count");
1546                 return;
1547         }
1548
1549         subtitleStream subs = _this->m_subtitleStreams[_this->m_currentSubtitleStream];
1550         
1551         if ( subs.type == stUnknown )
1552         {
1553                 GstTagList *tags;
1554                 eDebug("gstCBsubtitleCAPS::m_subtitleStreams[%i].type == stUnknown...", _this->m_currentSubtitleStream);
1555                 
1556                 gchar *g_lang;
1557                 g_signal_emit_by_name (_this->m_gst_playbin, "get-text-tags", _this->m_currentSubtitleStream, &tags);
1558
1559                 g_lang = g_strdup_printf ("und");
1560                 if ( tags && gst_is_tag_list(tags) )
1561                         gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang);
1562                 subs.language_code = std::string(g_lang);
1563
1564                 subs.type = getSubtitleType(GST_PAD(obj));
1565                 
1566                 _this->m_subtitleStreams[_this->m_currentSubtitleStream] = subs;
1567
1568                 g_free (g_lang);
1569         }
1570
1571         gstCBsubtitleLink(subs.type, _this);
1572 }
1573
1574 void eServiceMP3::gstCBsubtitleLink(subtype_t type, gpointer user_data)
1575 {
1576         eServiceMP3 *_this = (eServiceMP3*)user_data;
1577         
1578         if ( type == stVOB )
1579         {
1580                 GstPad *ghostpad = gst_element_get_static_pad(_this->m_gst_subtitlebin, "sink");
1581                 GstElement *dvdsubdec = gst_bin_get_by_name(GST_BIN(_this->m_gst_subtitlebin), "vobsubtitle_decoder");
1582                 GstPad *subdecsinkpad = gst_element_get_static_pad (dvdsubdec, "sink");
1583                 int ret = gst_ghost_pad_set_target((GstGhostPad*)ghostpad, subdecsinkpad);
1584                 GstElement *appsink = gst_bin_get_by_name(GST_BIN(_this->m_gst_subtitlebin), "subtitle_sink");
1585                 ret += gst_element_link(dvdsubdec, appsink);
1586                 eDebug("gstCBsubtitleLink:: dvdsubdec=%p, subdecsinkpad=%p, ghostpad=%p, set target & link=%i", dvdsubdec, subdecsinkpad, ghostpad, ret);
1587         }
1588         else if ( type < stVOB && type > stUnknown )
1589         {
1590                 GstPad *ghostpad = gst_element_get_static_pad(_this->m_gst_subtitlebin, "sink");
1591                 GstElement *appsink = gst_bin_get_by_name(GST_BIN(_this->m_gst_subtitlebin), "subtitle_sink");
1592                 GstPad *appsinkpad = gst_element_get_static_pad (appsink, "sink");
1593                 GstElement *dvdsubdec = gst_bin_get_by_name(GST_BIN(_this->m_gst_subtitlebin), "vobsubtitle_decoder");
1594                 gst_element_unlink(dvdsubdec, appsink);
1595                 int ret = gst_ghost_pad_set_target((GstGhostPad*)ghostpad, appsinkpad);
1596                 eDebug("gstCBsubtitleLink:: appsink=%p, appsinkpad=%p, ghostpad=%p, set target=%i", appsink, appsinkpad, ghostpad, ret);
1597         }
1598         else
1599         {
1600                 eDebug("gstCBsubtitleLink:: unsupported subtitles");
1601         }
1602 }
1603
1604 gboolean eServiceMP3::gstCBsubtitleDrop(GstPad *pad, GstBuffer *buffer, gpointer user_data)
1605 {
1606         eDebug("gstCBsubtitleDrop");
1607         
1608         gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer);
1609         gint64 duration_ns = GST_BUFFER_DURATION(buffer);
1610         size_t len = GST_BUFFER_SIZE(buffer);
1611
1612         unsigned char line[len+1];
1613         memcpy(line, GST_BUFFER_DATA(buffer), len);
1614         line[len] = 0;
1615         eDebug("dropping buffer '%s' ", line);
1616         return false;
1617 }
1618
1619
1620 void eServiceMP3::pullSubtitle()
1621 {
1622         GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_subtitlebin), "subtitle_sink");
1623 //      GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
1624
1625         if (appsink)
1626         {
1627                 while (m_subs_to_pull && m_subtitle_pages.size() < 2)
1628                 {
1629                         GstBuffer *buffer;
1630                         {
1631                                 eSingleLocker l(m_subs_to_pull_lock);
1632                                 --m_subs_to_pull;
1633                                 g_signal_emit_by_name (appsink, "pull-buffer", &buffer);
1634                         }
1635                         if (buffer)
1636                         {
1637                                 gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer);
1638                                 gint64 duration_ns = GST_BUFFER_DURATION(buffer);
1639                                 size_t len = GST_BUFFER_SIZE(buffer);
1640                                 eDebug("pullSubtitle m_subtitleStreams[m_currentSubtitleStream].type=%i",m_subtitleStreams[m_currentSubtitleStream].type);
1641                                 
1642                                 if ( m_subtitleStreams[m_currentSubtitleStream].type )
1643                                 {
1644                                         if ( m_subtitleStreams[m_currentSubtitleStream].type < stVOB )
1645                                         {
1646                                                 unsigned char line[len+1];
1647                                                 memcpy(line, GST_BUFFER_DATA(buffer), len);
1648                                                 line[len] = 0;
1649                                                 eDebug("got new text subtitle @ buf_pos = %lld ns (in pts=%lld): '%s' ", buf_pos, buf_pos/11111, line);
1650                                                 ePangoSubtitlePage* page = new ePangoSubtitlePage;
1651                                                 gRGB rgbcol(0xD0,0xD0,0xD0);
1652                                                 page->m_elements.push_back(ePangoSubtitlePageElement(rgbcol, (const char*)line));
1653                                                 page->show_pts = buf_pos / 11111L;
1654                                                 page->m_timeout = duration_ns / 1000000;
1655                                                 SubtitlePage subtitlepage;
1656                                                 subtitlepage.pango_page = page;
1657                                                 subtitlepage.vob_page = NULL;
1658                                                 m_subtitle_pages.push_back(subtitlepage);
1659                                                 pushSubtitles();
1660                                         }
1661                                         else
1662                                         {
1663                                                 eDebug("got new subpicture @ buf_pos = %lld ns (in pts=%lld), duration=%lld ns, len=%i bytes. ", buf_pos, buf_pos/11111, duration_ns, len);
1664                                                 eVobSubtitlePage* page = new eVobSubtitlePage;
1665                                                 eSize size = eSize(720, 576); 
1666                                                 page->m_pixmap = new gPixmap(size, 32, 0);
1667         //                                      ePtr<gPixmap> pixmap;
1668         //                                      pixmap = new gPixmap(size, 32, 1); /* allocate accel surface (if possible) */
1669                                                 memcpy(page->m_pixmap->surface->data, GST_BUFFER_DATA(buffer), len);
1670                                                 page->show_pts = buf_pos / 11111L;
1671                                                 page->m_timeout = duration_ns / 1000;
1672                                                 SubtitlePage subtitlepage;
1673                                                 subtitlepage.vob_page = page;
1674                                                 subtitlepage.pango_page = NULL;
1675                                                 m_subtitle_pages.push_back(subtitlepage);
1676                                                 pushSubtitles();
1677                                         }
1678                                 }
1679                                 gst_buffer_unref(buffer);
1680                         }
1681                 }
1682                 gst_object_unref(appsink);
1683         }
1684         else
1685                 eDebug("no subtitle sink!");
1686 }
1687
1688 void eServiceMP3::pushSubtitles()
1689 {
1690         pts_t running_pts;
1691         while ( !m_subtitle_pages.empty() )
1692         {
1693                 SubtitlePage frontpage = m_subtitle_pages.front();
1694                 gint64 diff_ms = 0;
1695                 
1696                 getPlayPosition(running_pts);
1697         
1698                 if ( frontpage.pango_page != 0 )
1699                 {
1700                         diff_ms = ( frontpage.pango_page->show_pts - running_pts ) / 90;
1701                         eDebug("eServiceMP3::pushSubtitles TEXT show_pts = %lld  running_pts = %lld  diff = %lld", frontpage.pango_page->show_pts, running_pts, diff_ms);
1702                 }
1703                 
1704                 if ( frontpage.vob_page != 0 )
1705                 {
1706                         diff_ms = ( frontpage.vob_page->show_pts - running_pts ) / 90;
1707                         eDebug("eServiceMP3::pushSubtitles VOB show_pts = %lld  running_pts = %lld  diff = %lld", frontpage.vob_page->show_pts, running_pts, diff_ms);
1708                 }
1709                 
1710                 if ( diff_ms < -100 )
1711                 {
1712                         GstFormat fmt = GST_FORMAT_TIME;
1713                         gint64 now;
1714                         if ( gst_element_query_position(m_gst_playbin, &fmt, &now) != -1 )
1715                         {
1716                                 now /= 11111;
1717                                 diff_ms = abs((now - running_pts) / 90);
1718                                 eDebug("diff < -100ms check decoder/pipeline diff: decoder: %lld, pipeline: %lld, diff: %lld", running_pts, now, diff_ms);
1719                                 if (diff_ms > 100000)
1720                                 {
1721                                         eDebug("high decoder/pipeline difference.. assume decoder has now started yet.. check again in 1sec");
1722                                         m_subtitle_sync_timer->start(1000, true);
1723                                         break;
1724                                 }
1725                         }
1726                         else
1727                                 eDebug("query position for decoder/pipeline check failed!");
1728                         eDebug("subtitle to late... drop");
1729                         m_subtitle_pages.pop_front();
1730                 }
1731                 else if ( diff_ms > 20 )
1732                 {
1733                         eDebug("start recheck timer");
1734                         m_subtitle_sync_timer->start(diff_ms > 1000 ? 1000 : diff_ms, true);
1735                         break;
1736                 }
1737                 else // immediate show
1738                 {
1739                         if ( m_subtitle_widget )
1740                         {
1741                                 if ( frontpage.pango_page != 0)
1742                                 {
1743                                         eDebug("immediate show pango subtitle line");
1744                                         m_subtitle_widget->setPage(*(frontpage.pango_page));
1745                                 }
1746                                 else if ( frontpage.vob_page != 0)
1747                                 {
1748                                         m_subtitle_widget->setPixmap(frontpage.vob_page->m_pixmap, eRect(0, 0, 720, 576));
1749                                         eDebug("blit vobsub pixmap... hide in %i ms", frontpage.vob_page->m_timeout);
1750                                         m_subtitle_hide_timer->start(frontpage.vob_page->m_timeout, true);
1751                                 }
1752                                 m_subtitle_widget->show();
1753                         }
1754                         m_subtitle_pages.pop_front();
1755                 }
1756         }
1757         if (m_subtitle_pages.empty())
1758                 pullSubtitle();
1759 }
1760
1761 void eServiceMP3::hideSubtitles()
1762 {
1763         eDebug("eServiceMP3::hideSubtitles()");
1764         if ( m_subtitle_widget )
1765                 m_subtitle_widget->hide();
1766 }
1767
1768 RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple)
1769 {
1770         eDebug ("eServiceMP3::enableSubtitles m_currentSubtitleStream=%i",m_currentSubtitleStream);
1771         ePyObject entry;
1772         int tuplesize = PyTuple_Size(tuple);
1773         int pid, type;
1774         gint text_pid = 0;
1775         eSingleLocker l(m_subs_to_pull_lock);
1776
1777 //      GstPad *pad = 0;
1778 //      g_signal_emit_by_name (m_gst_playbin, "get-text-pad", m_currentSubtitleStream, &pad);
1779 //      gst_element_get_static_pad(m_gst_subtitlebin, "sink");
1780 //      gulong subprobe_handler_id = gst_pad_add_buffer_probe (pad, G_CALLBACK (gstCBsubtitleDrop), NULL);
1781
1782         if (!PyTuple_Check(tuple))
1783                 goto error_out;
1784         if (tuplesize < 1)
1785                 goto error_out;
1786         entry = PyTuple_GET_ITEM(tuple, 1);
1787         if (!PyInt_Check(entry))
1788                 goto error_out;
1789         pid = PyInt_AsLong(entry);
1790         entry = PyTuple_GET_ITEM(tuple, 2);
1791         if (!PyInt_Check(entry))
1792                 goto error_out;
1793         type = PyInt_AsLong(entry);
1794
1795         eDebug ("eServiceMP3::enableSubtitles new pid=%i",pid);
1796         if (m_currentSubtitleStream != pid)
1797         {
1798                 g_object_set (G_OBJECT (m_gst_playbin), "current-text", pid, NULL);
1799                 eDebug ("eServiceMP3::enableSubtitles g_object_set current-text = %i", pid);
1800                 m_currentSubtitleStream = pid;
1801                 m_subs_to_pull = 0;
1802                 m_subtitle_pages.clear();
1803         }
1804
1805         m_subtitle_widget = 0;
1806         m_subtitle_widget = new eSubtitleWidget(parent);
1807         m_subtitle_widget->resize(parent->size()); /* full size */
1808
1809         g_object_get (G_OBJECT (m_gst_playbin), "current-text", &text_pid, NULL);
1810
1811         eDebug ("eServiceMP3::switched to subtitle stream %i", text_pid);
1812 //      gst_pad_remove_buffer_probe (pad, subprobe_handler_id);
1813
1814         m_event((iPlayableService*)this, evUpdatedInfo);
1815
1816         return 0;
1817
1818 error_out:
1819         eDebug("eServiceMP3::enableSubtitles needs a tuple as 2nd argument!\n"
1820                 "for gst subtitles (2, subtitle_stream_count, subtitle_type)");
1821         return -1;
1822 }
1823
1824 RESULT eServiceMP3::disableSubtitles(eWidget *parent)
1825 {
1826         eDebug("eServiceMP3::disableSubtitles");
1827         m_subtitle_pages.clear();
1828         eDebug("eServiceMP3::disableSubtitles cleared");
1829         delete m_subtitle_widget;
1830         eDebug("eServiceMP3::disableSubtitles deleted");
1831         m_subtitle_widget = 0;
1832         eDebug("eServiceMP3::disableSubtitles nulled");
1833         return 0;
1834 }
1835
1836 PyObject *eServiceMP3::getCachedSubtitle()
1837 {
1838 //      eDebug("eServiceMP3::getCachedSubtitle");
1839         Py_RETURN_NONE;
1840 }
1841
1842 PyObject *eServiceMP3::getSubtitleList()
1843 {
1844         eDebug("eServiceMP3::getSubtitleList");
1845         ePyObject l = PyList_New(0);
1846         int stream_idx = 0;
1847         
1848         for (std::vector<subtitleStream>::iterator IterSubtitleStream(m_subtitleStreams.begin()); IterSubtitleStream != m_subtitleStreams.end(); ++IterSubtitleStream)
1849         {
1850                 subtype_t type = IterSubtitleStream->type;
1851                 ePyObject tuple = PyTuple_New(5);
1852                 eDebug("eServiceMP3::getSubtitleList idx=%i type=%i, code=%s", stream_idx, int(type), (IterSubtitleStream->language_code).c_str());
1853                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(2));
1854                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(stream_idx));
1855                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(int(type)));
1856                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(0));
1857                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString((IterSubtitleStream->language_code).c_str()));
1858                 PyList_Append(l, tuple);
1859                 Py_DECREF(tuple);
1860                 stream_idx++;
1861         }
1862         eDebug("eServiceMP3::getSubtitleList finished");
1863         return l;
1864 }
1865
1866 RESULT eServiceMP3::streamed(ePtr<iStreamedService> &ptr)
1867 {
1868         ptr = this;
1869         return 0;
1870 }
1871
1872 PyObject *eServiceMP3::getBufferCharge()
1873 {
1874         ePyObject tuple = PyTuple_New(5);
1875         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(m_bufferInfo.bufferPercent));
1876         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(m_bufferInfo.avgInRate));
1877         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(m_bufferInfo.avgOutRate));
1878         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(m_bufferInfo.bufferingLeft));
1879         PyTuple_SET_ITEM(tuple, 4, PyInt_FromLong(m_buffer_size));
1880         return tuple;
1881 }
1882
1883 int eServiceMP3::setBufferSize(int size)
1884 {
1885         m_buffer_size = size;
1886         g_object_set (G_OBJECT (m_gst_playbin), "buffer-size", m_buffer_size, NULL);
1887         return 0;
1888 }
1889
1890 int eServiceMP3::getAC3Delay()
1891 {
1892         return ac3_delay;
1893 }
1894
1895 int eServiceMP3::getPCMDelay()
1896 {
1897         return pcm_delay;
1898 }
1899
1900 void eServiceMP3::setAC3Delay(int delay)
1901 {
1902         ac3_delay = delay;
1903         if (!m_gst_playbin || m_state != stRunning)
1904                 return;
1905         else
1906         {
1907                 GstElement *sink;
1908                 int config_delay_int = delay;
1909                 g_object_get (G_OBJECT (m_gst_playbin), "video-sink", &sink, NULL);
1910
1911                 if (sink)
1912                 {
1913                         std::string config_delay;
1914                         if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
1915                                 config_delay_int += atoi(config_delay.c_str());
1916                         gst_object_unref(sink);
1917                 }
1918                 else
1919                 {
1920                         eDebug("dont apply ac3 delay when no video is running!");
1921                         config_delay_int = 0;
1922                 }
1923
1924                 g_object_get (G_OBJECT (m_gst_playbin), "audio-sink", &sink, NULL);
1925
1926                 if (sink)
1927                 {
1928                         gchar *name = gst_element_get_name(sink);
1929                         if (strstr(name, "dvbaudiosink"))
1930                                 eTSMPEGDecoder::setHwAC3Delay(config_delay_int);
1931                         g_free(name);
1932                         gst_object_unref(sink);
1933                 }
1934         }
1935 }
1936
1937 void eServiceMP3::setPCMDelay(int delay)
1938 {
1939         pcm_delay = delay;
1940         if (!m_gst_playbin || m_state != stRunning)
1941                 return;
1942         else
1943         {
1944                 GstElement *sink;
1945                 int config_delay_int = delay;
1946                 g_object_get (G_OBJECT (m_gst_playbin), "video-sink", &sink, NULL);
1947
1948                 if (sink)
1949                 {
1950                         std::string config_delay;
1951                         if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
1952                                 config_delay_int += atoi(config_delay.c_str());
1953                         gst_object_unref(sink);
1954                 }
1955                 else
1956                 {
1957                         eDebug("dont apply pcm delay when no video is running!");
1958                         config_delay_int = 0;
1959                 }
1960
1961                 g_object_get (G_OBJECT (m_gst_playbin), "audio-sink", &sink, NULL);
1962
1963                 if (sink)
1964                 {
1965                         gchar *name = gst_element_get_name(sink);
1966                         if (strstr(name, "dvbaudiosink"))
1967                                 eTSMPEGDecoder::setHwPCMDelay(config_delay_int);
1968                         else
1969                         {
1970                                 // this is realy untested..and not used yet
1971                                 gint64 offset = config_delay_int;
1972                                 offset *= 1000000; // milli to nano
1973                                 g_object_set (G_OBJECT (m_gst_playbin), "ts-offset", offset, NULL);
1974                         }
1975                         g_free(name);
1976                         gst_object_unref(sink);
1977                 }
1978         }
1979 }
1980
1981 #else
1982 #warning gstreamer not available, not building media player
1983 #endif