needed changes for dm800/dm8000 drivers >= 20090720
[enigma2-plugins.git] / vlcplayer / src / servicets / servicets.cpp
1 /*******************************************************************************
2  VLC Player Plugin by A. Lätsch 2007
3
4  This is free software; you can redistribute it and/or modify it under
5  the terms of the GNU General Public License as published by the Free
6  Software Foundation; either version 2, or (at your option) any later
7  version.
8 ********************************************************************************/
9
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <string>
14 #include <sys/socket.h>
15 #include <netdb.h>
16 #include <signal.h>
17 #include <time.h>
18 #include "servicets.h"
19 #include <lib/base/eerror.h>
20 #include <lib/base/object.h>
21 #include <lib/base/ebase.h>
22 #include <servicets.h>
23 #include <lib/service/service.h>
24 #include <lib/base/init_num.h>
25 #include <lib/base/init.h>
26 #include <lib/dvb/decoder.h>
27
28 #include <lib/dvb/pmt.h>
29
30 #define MAX(a,b) ((a) > (b) ? (a) : (b))
31
32 /********************************************************************/
33 /* eServiceFactoryTS                                                */
34 /********************************************************************/
35
36 eServiceFactoryTS::eServiceFactoryTS()
37 {
38         ePtr<eServiceCenter> sc;
39
40         eServiceCenter::getPrivInstance(sc);
41         if (sc)
42         {
43                 std::list<std::string> extensions;
44                 sc->addServiceFactory(eServiceFactoryTS::id, this, extensions);
45         }
46 }
47
48 eServiceFactoryTS::~eServiceFactoryTS()
49 {
50         ePtr<eServiceCenter> sc;
51
52         eServiceCenter::getPrivInstance(sc);
53         if (sc)
54                 sc->removeServiceFactory(eServiceFactoryTS::id);
55 }
56
57 DEFINE_REF(eServiceFactoryTS)
58
59 // iServiceHandler
60 RESULT eServiceFactoryTS::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
61 {
62         ptr = new eServiceTS(ref);
63         return 0;
64 }
65
66 RESULT eServiceFactoryTS::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
67 {
68         ptr=0;
69         return -1;
70 }
71
72 RESULT eServiceFactoryTS::list(const eServiceReference &, ePtr<iListableService> &ptr)
73 {
74         ptr=0;
75         return -1;
76 }
77
78 RESULT eServiceFactoryTS::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
79 {
80         ptr = 0;
81         return -1;
82 }
83
84 RESULT eServiceFactoryTS::offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr)
85 {
86         ptr = 0;
87         return -1;
88 }
89
90
91 /********************************************************************/
92 /* TSAudioInfo                                            */
93 /********************************************************************/
94 DEFINE_REF(TSAudioInfo);
95
96 void TSAudioInfo::addAudio(int pid, std::string lang, std::string desc, int type) {
97         StreamInfo as;
98         as.description = desc;
99         as.language = lang;
100         as.pid = pid;
101         as.type = type;
102         audioStreams.push_back(as);
103 }
104
105
106 /********************************************************************/
107 /* eServiceTS                                                       */
108 /********************************************************************/
109
110 eServiceTS::eServiceTS(const eServiceReference &url): m_pump(eApp, 1)
111 {
112         eDebug("ServiceTS construct!");
113         m_filename = url.path.c_str();
114         m_vpid = url.getData(0) == 0 ? 0x44 : url.getData(0);
115         m_apid = url.getData(1) == 0 ? 0x45 : url.getData(1);
116         m_state = stIdle;
117         m_audioInfo = 0;
118         m_destfd = -1;
119 }
120
121 eServiceTS::~eServiceTS()
122 {
123         eDebug("ServiceTS destruct!");
124         stop();
125 }
126
127 DEFINE_REF(eServiceTS);
128
129 size_t crop(char *buf)
130 {
131         size_t len = strlen(buf) - 1;
132         while (len > 0 && (buf[len] == '\r' || buf[len] == '\n')) {
133                 buf[len--] = '\0';
134         }
135         return len;
136 }
137
138 static int getline(char** pbuffer, size_t* pbufsize, int fd)
139 {
140         size_t i = 0;
141         int rc;
142         while (true) {
143                 if (i >= *pbufsize) {
144                         char *newbuf = (char*)realloc(*pbuffer, (*pbufsize)+1024);
145                         if (newbuf == NULL)
146                                 return -ENOMEM;
147                         *pbuffer = newbuf;
148                         *pbufsize = (*pbufsize)+1024;
149                 }
150                 rc = ::read(fd, (*pbuffer)+i, 1);
151                 if (rc <= 0 || (*pbuffer)[i] == '\n')
152                 {
153                         (*pbuffer)[i] = '\0';
154                         return rc <= 0 ? -1 : i;
155                 }
156                 if ((*pbuffer)[i] != '\r') i++;
157         }
158 }
159
160 int eServiceTS::openHttpConnection(std::string url)
161 {
162         std::string host;
163         int port = 80;
164         std::string uri;
165
166         int slash = url.find("/", 7);
167         if (slash > 0) {
168                 host = url.substr(7, slash-7);
169                 uri = url.substr(slash, url.length()-slash);
170         } else {
171                 host = url.substr(7, url.length()-7);
172                 uri = "";
173         }
174         int dp = host.find(":");
175         if (dp == 0) {
176                 port = atoi(host.substr(1, host.length()-1).c_str());
177                 host = "localhost";
178         } else if (dp > 0) {
179                 port = atoi(host.substr(dp+1, host.length()-dp-1).c_str());
180                 host = host.substr(0, dp);
181         }
182
183         struct hostent* h = gethostbyname(host.c_str());
184         if (h == NULL || h->h_addr_list == NULL)
185                 return -1;
186         int fd = socket(PF_INET, SOCK_STREAM, 0);
187         if (fd == -1)
188                 return -1;
189
190         struct sockaddr_in addr;
191         addr.sin_family = AF_INET;
192         addr.sin_addr.s_addr = *((in_addr_t*)h->h_addr_list[0]);
193         addr.sin_port = htons(port);
194
195         eDebug("connecting to %s", url.c_str());
196
197         if (connect(fd, (sockaddr*)&addr, sizeof(addr)) == -1) {
198                 std::string msg = "connect failed for: " + url;
199                 eDebug(msg.c_str());
200                 return -1;
201         }
202
203         std::string request = "GET ";
204         request.append(uri).append(" HTTP/1.1\n");
205         request.append("Host: ").append(host).append("\n");
206         request.append("Accept: */*\n");
207         request.append("Connection: close\n");
208         request.append("\n");
209         //eDebug(request.c_str());
210         write(fd, request.c_str(), request.length());
211
212         int rc;
213         size_t buflen = 1000;
214         char* linebuf = (char*)malloc(1000);
215
216         rc = getline(&linebuf, &buflen, fd);
217         //eDebug("RECV(%d): %s", rc, linebuf);
218         if (rc <= 0)
219         {
220                 close(fd);
221                 free(linebuf);
222                 return -1;
223         }
224
225         char proto[100];
226         int statuscode = 0;
227         char statusmsg[100];
228         rc = sscanf(linebuf, "%99s %d %99s", proto, &statuscode, statusmsg);
229         if (rc != 3 || statuscode != 200) {
230                 eDebug("wrong response: \"200 OK\" expected.");
231                 free(linebuf);
232                 close(fd);
233                 return -1;
234         }
235         eDebug("proto=%s, code=%d, msg=%s", proto, statuscode, statusmsg);
236         while (rc > 0)
237         {
238                 rc = getline(&linebuf, &buflen, fd);
239                 //eDebug("RECV(%d): %s", rc, linebuf);
240         }
241         free(linebuf);
242
243         return fd;
244 }
245
246 RESULT eServiceTS::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
247 {
248         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
249         return 0;
250 }
251
252 RESULT eServiceTS::start()
253 {
254         ePtr<eDVBResourceManager> rmgr;
255         eDVBResourceManager::getInstance(rmgr);
256         eDVBChannel dvbChannel(rmgr, 0);
257         if (m_destfd == -1)
258         {
259                 m_destfd = ::open("/dev/misc/pvr", O_WRONLY);
260                 if (m_destfd < 0) {
261                         eDebug("Cannot open /dev/misc/pvr");
262                         return -1;
263                 }
264         }
265         if (dvbChannel.getDemux(m_decodedemux, iDVBChannel::capDecode) != 0) {
266                 eDebug("Cannot allocate decode-demux");
267                 return -1;
268         }
269         if (m_decodedemux->getMPEGDecoder(m_decoder, 1) != 0) {
270                 eDebug("Cannot allocate MPEGDecoder");
271                 return -1;
272         }
273         m_decoder->setVideoPID(m_vpid, eDVBVideo::MPEG2);
274         m_decoder->setAudioPID(m_apid, eDVBAudio::aMPEG);
275         m_streamthread = new eStreamThread();
276         CONNECT(m_streamthread->m_event, eServiceTS::recv_event);
277         m_decoder->pause();
278         if (unpause() != 0) return -1;
279         m_state = stRunning;
280         m_event(this, evStart);
281         return 0;
282 }
283
284 RESULT eServiceTS::stop()
285 {
286         if (m_destfd >= 0)
287                 ::close(m_destfd);
288         if (m_state != stRunning)
289                 return -1;
290         printf("TS: %s stop\n", m_filename.c_str());
291         m_streamthread->stop();
292         m_decodedemux->flush();
293         m_state = stStopped;
294         m_audioInfo = 0;
295         return 0;
296 }
297
298 void eServiceTS::recv_event(int evt)
299 {
300         eDebug("eServiceTS::recv_event: %d", evt);
301         switch (evt) {
302         case eStreamThread::evtEOS:
303                 m_decodedemux->flush();
304                 m_state = stStopped;
305                 m_event((iPlayableService*)this, evEOF);
306                 break;
307         case eStreamThread::evtReadError:
308         case eStreamThread::evtWriteError:
309                 m_decoder->pause();
310                 m_state = stStopped;
311                 m_event((iPlayableService*)this, evEOF);
312                 break;
313         case eStreamThread::evtSOS:
314                 m_event((iPlayableService*)this, evSOF);
315                 break;
316         case eStreamThread::evtStreamInfo:
317                 bool wasnull = !m_audioInfo;
318                 m_streamthread->getAudioInfo(m_audioInfo);
319                 if (m_audioInfo)
320                         eDebug("[servicets] %d audiostreams found", m_audioInfo->audioStreams.size());
321                 if (m_audioInfo && wasnull) {
322                         int sel = getCurrentTrack();
323                         if (sel < 0)
324                                 selectTrack(0);
325                         else if (m_audioInfo->audioStreams[sel].type != eDVBAudio::aMPEG)
326                                 selectTrack(sel);
327                 }
328                 break;
329         }
330 }
331
332 RESULT eServiceTS::pause(ePtr<iPauseableService> &ptr)
333 {
334         ptr = this;
335         return 0;
336 }
337
338 // iPausableService
339 RESULT eServiceTS::pause()
340 {
341         m_streamthread->stop();
342         m_decoder->pause();
343         return 0;
344 }
345
346 RESULT eServiceTS::unpause()
347 {
348         int is_streaming = !strncmp(m_filename.c_str(), "http://", 7);
349         int srcfd = -1;
350         if (is_streaming) {
351                 srcfd = openHttpConnection(m_filename);
352         } else {
353                 srcfd = ::open(m_filename.c_str(), O_RDONLY);
354         }
355         if (srcfd < 0) {
356                 eDebug("Cannot open source stream: %s", m_filename.c_str());
357                 return 1;
358         }
359         m_decodedemux->flush();
360         m_streamthread->start(srcfd, m_destfd);
361         m_decoder->play();
362         return 0;
363 }
364
365 // iSeekableService
366 RESULT eServiceTS::seek(ePtr<iSeekableService> &ptr)
367 {
368         ptr = this;
369         return 0;
370 }
371
372 RESULT eServiceTS::getLength(pts_t &pts)
373 {
374         return 0;
375 }
376
377 RESULT eServiceTS::seekTo(pts_t to)
378 {
379         return 0;
380 }
381
382 RESULT eServiceTS::seekRelative(int direction, pts_t to)
383 {
384         return 0;
385 }
386
387 RESULT eServiceTS::getPlayPosition(pts_t &pts)
388 {
389         return 0;
390 }
391
392 RESULT eServiceTS::setTrickmode(int trick)
393 {
394         return -1;
395 }
396
397 RESULT eServiceTS::isCurrentlySeekable()
398 {
399         return 1;
400 }
401
402 RESULT eServiceTS::info(ePtr<iServiceInformation>&i)
403 {
404         i = this;
405         return 0;
406 }
407
408 RESULT eServiceTS::getName(std::string &name)
409 {
410         name = m_filename;
411         size_t n = name.rfind('/');
412         if (n != std::string::npos)
413                 name = name.substr(n + 1);
414         return 0;
415 }
416
417 int eServiceTS::getInfo(int w)
418 {
419         return resNA;
420 }
421
422 std::string eServiceTS::getInfoString(int w)
423 {
424         return "";
425 }
426
427 int eServiceTS::getNumberOfTracks() {
428         if (m_audioInfo)
429                 return (int)m_audioInfo->audioStreams.size();
430         else
431                 return 0;
432 }
433
434 RESULT eServiceTS::selectTrack(unsigned int i) {
435         if (m_audioInfo) {
436                 m_apid = m_audioInfo->audioStreams[i].pid;
437                 eDebug("[servicets] audio track %d PID 0x%02x type %d\n", i, m_apid, m_audioInfo->audioStreams[i].type);
438                 m_decoder->setAudioPID(m_apid, m_audioInfo->audioStreams[i].type);
439                 if (m_state == stRunning)
440                         m_decoder->set();
441                 return 0;
442         } else {
443                 return -1;
444         }
445 }
446
447 RESULT eServiceTS::getTrackInfo(struct iAudioTrackInfo &info, unsigned int n) {
448         if (m_audioInfo) {
449                 info.m_pid = m_audioInfo->audioStreams[n].pid;
450                 info.m_description = m_audioInfo->audioStreams[n].description;
451                 info.m_language = m_audioInfo->audioStreams[n].language;
452                 return 0;
453         } else {
454                 return -1;
455         }
456 }
457
458 int eServiceTS::getCurrentTrack() {
459         if (m_audioInfo) {
460                 for (size_t i = 0; i < m_audioInfo->audioStreams.size(); i++) {
461                         if (m_apid == m_audioInfo->audioStreams[i].pid) {
462                                 return i;
463                         }
464                 }
465         }
466         return -1;
467 }
468
469 /********************************************************************/
470 /* eStreamThread                                                       */
471 /********************************************************************/
472
473 DEFINE_REF(eStreamThread)
474
475 eStreamThread::eStreamThread(): m_messagepump(eApp, 0) {
476         CONNECT(m_messagepump.recv_msg, eStreamThread::recvEvent);
477 }
478 eStreamThread::~eStreamThread() {
479 }
480
481 void eStreamThread::start(int srcfd, int destfd) {
482         m_srcfd = srcfd;
483         m_destfd = destfd;
484         m_stop = false;
485         m_audioInfo = 0;
486         run(IOPRIO_CLASS_RT);
487 }
488
489 void eStreamThread::stop() {
490         m_stop = true;
491         kill();
492 }
493
494 void eStreamThread::recvEvent(const int &evt)
495 {
496         m_event(evt);
497 }
498
499 RESULT eStreamThread::getAudioInfo(ePtr<TSAudioInfo> &ptr)
500 {
501         ptr = m_audioInfo;
502         return 0;
503 }
504
505 #define REGISTRATION_DESCRIPTOR 5
506 #define LANGUAGE_DESCRIPTOR 10
507
508 std::string eStreamThread::getDescriptor(unsigned char buf[], int buflen, int type)
509 {
510         int desc_len;
511         while (buflen > 1) {
512                 desc_len = buf[1];
513                 if (buf[0] == type) {
514                         char str[21];
515                         if (desc_len > 20) desc_len = 20;
516                         strncpy(str, (char*)buf+2, desc_len);
517                         str[desc_len] = '\0';
518                         return std::string(str);
519                 } else {
520                         buflen -= desc_len+2;
521                         buf += desc_len+2;
522                 }
523         }
524         return "";
525 }
526
527 bool eStreamThread::scanAudioInfo(unsigned char buf[], int len)
528 {
529         if (len < 1880)
530                 return false;
531
532         int adaptfield, pmtpid, offset;
533         unsigned char pmt[1188];
534         int pmtsize = 0;
535
536         for (int a=0; a < len - 188*4; a++) {
537                 if ( buf[a] != 0x47 || buf[a + 188] != 0x47 || buf[a + 376] != 0x47 )
538                         continue; // TS Header
539
540                 if ((0x40 & buf[a + 1]) == 0) // start
541                         continue;
542
543                 if ((0xC0 & buf[a + 3]) != 0) // scrambling
544                         continue;
545
546                 adaptfield = (0x30 & buf[a + 3]) >> 4;
547
548                 if ((adaptfield & 1) == 0) // adapt - no payload
549                         continue;
550
551                 offset = adaptfield == 3 ? 1 + (0xFF & buf[a + 4]) : 0; //adaptlength
552
553                 if (buf[a + offset + 4] != 0 || buf[a + offset + 5] != 2 || (0xF0 & buf[a + offset + 6]) != 0xB0)
554                 {
555                         a += 187;
556                         continue;
557                 }
558
559                 pmtpid = (0x1F & buf[a + 1])<<8 | (0xFF & buf[a + 2]);
560                 memcpy(pmt + pmtsize, buf + a + 4 + offset, 184 - offset);
561                 pmtsize += 184 - offset;
562
563                 if (pmtsize >= 1000)
564                         break;
565         }
566
567         if (pmtsize == 0) return false;
568
569         int pmtlen = (0x0F & pmt[2]) << 8 | (0xFF & pmt[3]);
570         std::string lang;
571         std::string pd_type;
572         ePtr<TSAudioInfo> ainfo = new TSAudioInfo();
573
574         for (int b=8; b < pmtlen-4 && b < pmtsize-6; b++)
575         {
576                 if ( (0xe0 & pmt[b+1]) != 0xe0 )
577                         continue;
578
579                 int pid = (0x1F & pmt[b+1])<<8 | (0xFF & pmt[b+2]);
580
581                 switch(pmt[b])
582                 {
583                 case 1:
584                 case 2: // MPEG Video
585                         //addVideo(pid, "MPEG2");
586                         break;
587
588                 case 0x1B: // H.264 Video
589                         //addVideo(pid, "H.264");
590                         break;
591
592                 case 3:
593                 case 4: // MPEG Audio
594                         lang = getDescriptor(pmt+b+5, pmt[b+4], LANGUAGE_DESCRIPTOR);
595                         ainfo->addAudio(pid, lang, "MPEG", eDVBAudio::aMPEG);
596                         break;
597
598                 case 0x80:
599                 case 0x81:  //private data of AC3 in ATSC
600                 case 0x82:
601                 case 0x83:
602                 case 6:
603                         lang = getDescriptor(pmt+b+5, pmt[b+4], LANGUAGE_DESCRIPTOR);
604                         pd_type = getDescriptor(pmt+b+5, pmt[b+4], REGISTRATION_DESCRIPTOR);
605                         if (pd_type == "AC-3")
606                                 ainfo->addAudio(pid, lang, pd_type, eDVBAudio::aAC3);
607                         break;
608                 }
609                 b += 4 + pmt[b+4];
610         }
611         if (ainfo->audioStreams.size() > 0) {
612                 m_audioInfo = ainfo;
613                 return true;
614         } else {
615                 return false;
616         }
617 }
618
619 void eStreamThread::thread() {
620         const int bufsize = 40000;
621         unsigned char buf[bufsize];
622         bool eof = false;
623         fd_set rfds;
624         fd_set wfds;
625         struct timeval timeout;
626         int rc,r,w,maxfd;
627         time_t next_scantime = 0;
628         bool sosSend = false;
629
630         r = w = 0;
631         hasStarted();
632         eDebug("eStreamThread started");
633         while (!m_stop) {
634                 pthread_testcancel();
635                 FD_ZERO(&rfds);
636                 FD_ZERO(&wfds);
637                 maxfd = 0;
638                 timeout.tv_sec = 1;
639                 timeout.tv_usec = 0;
640                 if (r < bufsize) {
641                         FD_SET(m_srcfd, &rfds);
642                         maxfd = MAX(maxfd, m_srcfd);
643                 }
644                 if (w < r) {
645                         FD_SET(m_destfd, &wfds);
646                         maxfd = MAX(maxfd, m_destfd);
647                 }
648                 rc = select(maxfd+1, &rfds, &wfds, NULL, &timeout);
649                 if (rc == 0) {
650                         eDebug("eStreamThread::thread: timeout!");
651                         continue;
652                 }
653                 if (rc < 0) {
654                         eDebug("eStreamThread::thread: error in select (%d)", errno);
655                         break;
656                 }
657                 if (FD_ISSET(m_srcfd, &rfds)) {
658                         rc = ::read(m_srcfd, buf+r, bufsize - r);
659                         if (rc < 0) {
660                                 eDebug("eStreamThread::thread: error in read (%d)", errno);
661                                 m_messagepump.send(evtReadError);
662                                 break;
663                         } else if (rc == 0) {
664                                 eof = true;
665                         } else {
666                                 if (!sosSend) {
667                                         sosSend = true;
668                                         m_messagepump.send(evtSOS);
669                                 }
670                                 r += rc;
671                                 if (r == bufsize) eDebug("eStreamThread::thread: buffer full");
672                         }
673                 }
674                 if (FD_ISSET(m_destfd, &wfds) && (w < r) && ((r > bufsize/4) || eof)) {
675                         rc = ::write(m_destfd, buf+w, r-w);
676                         if (rc < 0) {
677                                 eDebug("eStreamThread::thread: error in write (%d)", errno);
678                                 m_messagepump.send(evtWriteError);
679                                 break;
680                         }
681                         w += rc;
682                         //eDebug("eStreamThread::thread: buffer r=%d w=%d",r,w);
683                         if (w == r) {
684                                 if (time(0) >= next_scantime) {
685                                         if (scanAudioInfo(buf, r)) {
686                                                 m_messagepump.send(evtStreamInfo);
687                                                 next_scantime = time(0) + 1;
688                                         }
689                                 }
690                                 w = r = 0;
691                         }
692                 }
693                 if (eof && (r==w)) {
694                         ::close(m_srcfd);
695                         m_srcfd = -1;
696                         m_messagepump.send(evtEOS);
697                         break;
698                 }
699         }
700         eDebug("eStreamThread end");
701 }
702
703 void eStreamThread::thread_finished() {
704         if (m_srcfd >= 0) ::close(m_srcfd);
705         eDebug("eStreamThread closed");
706 }
707
708 eAutoInitPtr<eServiceFactoryTS> init_eServiceFactoryTS(eAutoInitNumbers::service+1, "eServiceFactoryTS");
709
710 PyMODINIT_FUNC
711 initservicets(void)
712 {
713         Py_InitModule("servicets", NULL);
714 }