fixed: Ticket #9821, Segmentation fault in VNSIDemux.cpp
[xbmc:xbmc-antiquated.git] / xbmc / pvrclients / vdr-vnsi / VNSIDemux.cpp
1 /*
2  *      Copyright (C) 2010 Alwin Esch (Team XBMC)
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #define __STDC_CONSTANT_MACROS
23 #include <stdint.h>
24 #include <limits.h>
25 #include <libavcodec/avcodec.h> // For codec id's
26 #include "VNSIDemux.h"
27 #include "tools.h"
28 #include "responsepacket.h"
29 #include "requestpacket.h"
30 #include "vdrcommand.h"
31
32 cVNSIDemux::cVNSIDemux()
33   : m_startup(false)
34   , m_channel(0)
35   , m_StatusCount(0)
36 {
37   m_Streams.nstreams = 0;
38 }
39
40 cVNSIDemux::~cVNSIDemux()
41 {
42   Close();
43 }
44
45 bool cVNSIDemux::Open(const PVR_CHANNEL &channelinfo)
46 {
47   m_channel = channelinfo.number;
48
49   if(!m_session.Open(g_szHostname, g_iPort, g_iConnectTimeout, "XBMC Live stream receiver"))
50     return false;
51
52   cRequestPacket vrp;
53   if (!vrp.init(VDR_CHANNELSTREAM_OPEN) ||
54       !vrp.add_U32(m_channel) ||
55       !m_session.ReadSuccess(&vrp))
56   {
57     XBMC->Log(LOG_ERROR, "cVNSIDemux::Open - Can't open channel %i - %s", m_channel, channelinfo.name);
58     return false;
59   }
60
61   m_StatusCount = 0;
62   m_startup = true;
63
64   while (m_Streams.nstreams == 0 && m_StatusCount == 0)
65   {
66     DemuxPacket* pkg = Read();
67     if(!pkg)
68     {
69       Close();
70       return false;
71     }
72     PVR->FreeDemuxPacket(pkg);
73   }
74
75   return true;
76 }
77
78 void cVNSIDemux::Close()
79 {
80   cRequestPacket vrp;
81   m_session.Close();
82 }
83
84 bool cVNSIDemux::GetStreamProperties(PVR_STREAMPROPS* props)
85 {
86   props->nstreams = m_Streams.nstreams;
87   for (int i = 0; i < m_Streams.nstreams; i++)
88   {
89     props->stream[i].id           = m_Streams.stream[i].id;
90     props->stream[i].physid       = m_Streams.stream[i].physid;
91     props->stream[i].codec_type   = m_Streams.stream[i].codec_type;
92     props->stream[i].codec_id     = m_Streams.stream[i].codec_id;
93     props->stream[i].height       = m_Streams.stream[i].height;
94     props->stream[i].width        = m_Streams.stream[i].width;
95     props->stream[i].language[0]  = m_Streams.stream[i].language[0];
96     props->stream[i].language[1]  = m_Streams.stream[i].language[1];
97     props->stream[i].language[2]  = m_Streams.stream[i].language[2];
98     props->stream[i].language[3]  = m_Streams.stream[i].language[3];
99     props->stream[i].identifier   = m_Streams.stream[i].identifier;
100   }
101   return (props->nstreams > 0);
102 }
103
104 void cVNSIDemux::Abort()
105 {
106   m_Streams.nstreams = 0;
107   m_session.Abort();
108 }
109
110 DemuxPacket* cVNSIDemux::Read()
111 {
112   cResponsePacket *resp;
113   while ((resp = m_session.ReadMessage(3)))
114   {
115     if (resp->getChannelID() == CHANNEL_STREAM)
116     {
117       if (resp->getOpCodeID() == VDR_STREAM_CHANGE)
118       {
119         StreamChange(resp);
120         if (!m_startup)
121         {
122           DemuxPacket* pkt  = PVR->AllocateDemuxPacket(0);
123           pkt->iStreamId    = DMX_SPECIALID_STREAMCHANGE;
124           delete resp;
125           return pkt;
126         }
127         else
128           m_startup = false;
129       }
130       else if (resp->getOpCodeID() == VDR_STREAM_STATUS)
131         StreamStatus(resp);
132       else if (resp->getOpCodeID() == VDR_STREAM_SIGNALINFO)
133         StreamSignalInfo(resp);
134       else if (resp->getOpCodeID() == VDR_STREAM_CONTENTINFO)
135       {
136         StreamContentInfo(resp);
137         DemuxPacket* pkt = PVR->AllocateDemuxPacket(sizeof(PVR_STREAMPROPS));
138         memcpy(pkt->pData, &m_Streams, sizeof(PVR_STREAMPROPS));
139         pkt->iStreamId  = DMX_SPECIALID_STREAMINFO;
140         pkt->iSize      = sizeof(PVR_STREAMPROPS);
141         delete resp;
142         return pkt;
143       }
144       else if (resp->getOpCodeID() == VDR_STREAM_MUXPKT)
145       {
146         void   *bin       = resp->getUserData();
147         size_t  binlen    = resp->getUserDataLength();
148
149         DemuxPacket* pkt = PVR->AllocateDemuxPacket(binlen);
150
151         memcpy(pkt->pData, bin, binlen);
152
153         pkt->iSize      = binlen;
154         pkt->duration   = (double)resp->getDuration() * DVD_TIME_BASE / 1000000;
155         pkt->dts        = (double)resp->getDTS() * DVD_TIME_BASE / 1000000;
156         pkt->pts        = (double)resp->getPTS() * DVD_TIME_BASE / 1000000;
157         pkt->iStreamId  = -1;
158         for(int i = 0; i < m_Streams.nstreams; i++)
159         {
160           if(m_Streams.stream[i].physid == (int)resp->getStreamID())
161           {
162             pkt->iStreamId = i;
163             break;
164           }
165         }
166
167         free(bin);
168         delete resp;
169         return pkt;
170       }
171     }
172
173     break;
174   }
175
176   if (resp)
177   {
178     delete resp;
179     return PVR->AllocateDemuxPacket(0);
180   }
181   return NULL;
182 }
183
184 bool cVNSIDemux::SwitchChannel(const PVR_CHANNEL &channelinfo)
185 {
186   XBMC->Log(LOG_DEBUG, "changing to channel %d", channelinfo.number);
187
188   cRequestPacket vrp;
189   if (!vrp.init(VDR_CHANNELSTREAM_OPEN) || !vrp.add_U32(channelinfo.number) || !m_session.ReadSuccess(&vrp))
190   {
191     XBMC->Log(LOG_ERROR, "cVNSIDemux::SetChannel - failed to set channel");
192   }
193   else
194   {
195     m_channel           = channelinfo.number;
196     m_Streams.nstreams  = 0;
197     m_startup           = true;
198     while (m_Streams.nstreams == 0 && m_StatusCount == 0)
199     {
200       DemuxPacket* pkg = Read();
201       if(!pkg)
202         return false;
203       PVR->FreeDemuxPacket(pkg);
204     }
205     return true;
206   }
207   return false;
208 }
209
210 bool cVNSIDemux::GetSignalStatus(PVR_SIGNALQUALITY &qualityinfo)
211 {
212   if (m_Quality.fe_name.IsEmpty())
213     return false;
214
215   strncpy(qualityinfo.frontend_name, m_Quality.fe_name.c_str(), sizeof(qualityinfo.frontend_name));
216   strncpy(qualityinfo.frontend_status, m_Quality.fe_status.c_str(), sizeof(qualityinfo.frontend_status));
217   qualityinfo.signal = (uint16_t)m_Quality.fe_signal;
218   qualityinfo.snr = (uint16_t)m_Quality.fe_snr;
219   qualityinfo.ber = (uint32_t)m_Quality.fe_ber;
220   qualityinfo.unc = (uint32_t)m_Quality.fe_unc;
221   qualityinfo.video_bitrate = 0;
222   qualityinfo.audio_bitrate = 0;
223   qualityinfo.dolby_bitrate = 0;
224
225   return true;
226 }
227
228 void cVNSIDemux::StreamChange(cResponsePacket *resp)
229 {
230   m_Streams.nstreams = 0;
231
232   while (!resp->end())
233   {
234     uint32_t    index = resp->extract_U32();
235     const char* type  = resp->extract_String();
236
237     DEVDBG("cVNSIDemux::StreamChange - id: %d, type: %s", index, type);
238
239     m_Streams.stream[m_Streams.nstreams].fpsscale         = 0;
240     m_Streams.stream[m_Streams.nstreams].fpsrate          = 0;
241     m_Streams.stream[m_Streams.nstreams].height           = 0;
242     m_Streams.stream[m_Streams.nstreams].width            = 0;
243     m_Streams.stream[m_Streams.nstreams].aspect           = 0.0;
244
245     m_Streams.stream[m_Streams.nstreams].channels         = 0;
246     m_Streams.stream[m_Streams.nstreams].samplerate       = 0;
247     m_Streams.stream[m_Streams.nstreams].blockalign       = 0;
248     m_Streams.stream[m_Streams.nstreams].bitrate          = 0;
249     m_Streams.stream[m_Streams.nstreams].bits_per_sample  = 0;
250
251     if(!strcmp(type, "AC3"))
252     {
253       const char *language = resp->extract_String();
254
255       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
256       m_Streams.stream[m_Streams.nstreams].physid     = index;
257       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_AUDIO;
258       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_AC3;
259       m_Streams.stream[m_Streams.nstreams].language[0]= language[0];
260       m_Streams.stream[m_Streams.nstreams].language[1]= language[1];
261       m_Streams.stream[m_Streams.nstreams].language[2]= language[2];
262       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
263       m_Streams.stream[m_Streams.nstreams].identifier = -1;
264       m_Streams.nstreams++;
265     }
266     else if(!strcmp(type, "MPEG2AUDIO"))
267     {
268       const char *language = resp->extract_String();
269
270       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
271       m_Streams.stream[m_Streams.nstreams].physid     = index;
272       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_AUDIO;
273       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_MP2;
274       m_Streams.stream[m_Streams.nstreams].language[0]= language[0];
275       m_Streams.stream[m_Streams.nstreams].language[1]= language[1];
276       m_Streams.stream[m_Streams.nstreams].language[2]= language[2];
277       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
278       m_Streams.stream[m_Streams.nstreams].identifier = -1;
279       m_Streams.nstreams++;
280     }
281     else if(!strcmp(type, "AAC"))
282     {
283       const char *language = resp->extract_String();
284
285       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
286       m_Streams.stream[m_Streams.nstreams].physid     = index;
287       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_AUDIO;
288       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_AAC;
289       m_Streams.stream[m_Streams.nstreams].language[0]= language[0];
290       m_Streams.stream[m_Streams.nstreams].language[1]= language[1];
291       m_Streams.stream[m_Streams.nstreams].language[2]= language[2];
292       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
293       m_Streams.stream[m_Streams.nstreams].identifier = -1;
294       m_Streams.nstreams++;
295     }
296     else if(!strcmp(type, "DTS"))
297     {
298       const char *language = resp->extract_String();
299
300       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
301       m_Streams.stream[m_Streams.nstreams].physid     = index;
302       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_AUDIO;
303       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_DTS;
304       m_Streams.stream[m_Streams.nstreams].language[0]= language[0];
305       m_Streams.stream[m_Streams.nstreams].language[1]= language[1];
306       m_Streams.stream[m_Streams.nstreams].language[2]= language[2];
307       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
308       m_Streams.stream[m_Streams.nstreams].identifier = -1;
309       m_Streams.nstreams++;
310     }
311     else if(!strcmp(type, "EAC3"))
312     {
313       const char *language = resp->extract_String();
314
315       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
316       m_Streams.stream[m_Streams.nstreams].physid     = index;
317       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_AUDIO;
318       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_EAC3;
319       m_Streams.stream[m_Streams.nstreams].language[0]= language[0];
320       m_Streams.stream[m_Streams.nstreams].language[1]= language[1];
321       m_Streams.stream[m_Streams.nstreams].language[2]= language[2];
322       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
323       m_Streams.stream[m_Streams.nstreams].identifier = -1;
324       m_Streams.nstreams++;
325     }
326     else if(!strcmp(type, "MPEG2VIDEO"))
327     {
328       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
329       m_Streams.stream[m_Streams.nstreams].physid     = index;
330       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_VIDEO;
331       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_MPEG2VIDEO;
332       m_Streams.stream[m_Streams.nstreams].fpsscale   = resp->extract_U32();
333       m_Streams.stream[m_Streams.nstreams].fpsrate    = resp->extract_U32();
334       m_Streams.stream[m_Streams.nstreams].height     = resp->extract_U32();
335       m_Streams.stream[m_Streams.nstreams].width      = resp->extract_U32();
336       m_Streams.stream[m_Streams.nstreams].aspect     = resp->extract_Double();
337       m_Streams.stream[m_Streams.nstreams].language[0]= 0;
338       m_Streams.stream[m_Streams.nstreams].language[1]= 0;
339       m_Streams.stream[m_Streams.nstreams].language[2]= 0;
340       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
341       m_Streams.stream[m_Streams.nstreams].identifier = -1;
342       m_Streams.nstreams++;
343     }
344     else if(!strcmp(type, "H264"))
345     {
346       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
347       m_Streams.stream[m_Streams.nstreams].physid     = index;
348       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_VIDEO;
349       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_H264;
350       m_Streams.stream[m_Streams.nstreams].fpsscale   = resp->extract_U32();
351       m_Streams.stream[m_Streams.nstreams].fpsrate    = resp->extract_U32();
352       m_Streams.stream[m_Streams.nstreams].height     = resp->extract_U32();
353       m_Streams.stream[m_Streams.nstreams].width      = resp->extract_U32();
354       m_Streams.stream[m_Streams.nstreams].aspect     = resp->extract_Double();
355       m_Streams.stream[m_Streams.nstreams].language[0]= 0;
356       m_Streams.stream[m_Streams.nstreams].language[1]= 0;
357       m_Streams.stream[m_Streams.nstreams].language[2]= 0;
358       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
359       m_Streams.stream[m_Streams.nstreams].identifier = -1;
360       m_Streams.nstreams++;
361     }
362     else if(!strcmp(type, "DVBSUB"))
363     {
364       const char *language    = resp->extract_String();
365       uint32_t composition_id = resp->extract_U32();
366       uint32_t ancillary_id   = resp->extract_U32();
367
368       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
369       m_Streams.stream[m_Streams.nstreams].physid     = index;
370       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_SUBTITLE;
371       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_DVB_SUBTITLE;
372       m_Streams.stream[m_Streams.nstreams].language[0]= language[0];
373       m_Streams.stream[m_Streams.nstreams].language[1]= language[1];
374       m_Streams.stream[m_Streams.nstreams].language[2]= language[2];
375       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
376       m_Streams.stream[m_Streams.nstreams].identifier = (composition_id & 0xffff) | ((ancillary_id & 0xffff) << 16);
377       m_Streams.nstreams++;
378     }
379     else if(!strcmp(type, "TEXTSUB"))
380     {
381       const char *language = resp->extract_String();
382
383       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
384       m_Streams.stream[m_Streams.nstreams].physid     = index;
385       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_SUBTITLE;
386       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_TEXT;
387       m_Streams.stream[m_Streams.nstreams].language[0]= language[0];
388       m_Streams.stream[m_Streams.nstreams].language[1]= language[1];
389       m_Streams.stream[m_Streams.nstreams].language[2]= language[2];
390       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
391       m_Streams.stream[m_Streams.nstreams].identifier = -1;
392       m_Streams.nstreams++;
393     }
394     else if(!strcmp(type, "TELETEXT"))
395     {
396       m_Streams.stream[m_Streams.nstreams].id         = m_Streams.nstreams;
397       m_Streams.stream[m_Streams.nstreams].physid     = index;
398       m_Streams.stream[m_Streams.nstreams].codec_type = CODEC_TYPE_SUBTITLE;
399       m_Streams.stream[m_Streams.nstreams].codec_id   = CODEC_ID_DVB_TELETEXT;
400       m_Streams.stream[m_Streams.nstreams].language[0]= 0;
401       m_Streams.stream[m_Streams.nstreams].language[1]= 0;
402       m_Streams.stream[m_Streams.nstreams].language[2]= 0;
403       m_Streams.stream[m_Streams.nstreams].language[3]= 0;
404       m_Streams.stream[m_Streams.nstreams].identifier = -1;
405       m_Streams.nstreams++;
406     }
407
408     if (m_Streams.nstreams >= PVR_STREAM_MAX_STREAMS)
409     {
410       XBMC->Log(LOG_ERROR, "cVNSIDemux::StreamChange - max amount of streams reached");
411       break;
412     }
413   }
414 }
415
416 void cVNSIDemux::StreamStatus(cResponsePacket *resp)
417 {
418   const char* status = resp->extract_String();
419   if(status == NULL)
420     m_Status = "";
421   else
422   {
423     m_StatusCount++;
424     m_Status = status;
425     XBMC->Log(LOG_DEBUG, "cVNSIDemux::StreamStatus - %s", status);
426     XBMC->QueueNotification(QUEUE_INFO, status);
427   }
428 }
429
430 void cVNSIDemux::StreamSignalInfo(cResponsePacket *resp)
431 {
432   m_Quality.fe_name   = resp->extract_String();
433   m_Quality.fe_status = resp->extract_String();
434   m_Quality.fe_snr    = resp->extract_U32();
435   m_Quality.fe_signal = resp->extract_U32();
436   m_Quality.fe_ber    = resp->extract_U32();
437   m_Quality.fe_unc    = resp->extract_U32();
438 }
439
440 void cVNSIDemux::StreamContentInfo(cResponsePacket *resp)
441 {
442   for (int i = 0; i < m_Streams.nstreams && !resp->end(); i++)
443   {
444     uint32_t index = resp->extract_U32();
445     if (index == m_Streams.stream[i].physid)
446     {
447       if (m_Streams.stream[i].codec_type == CODEC_TYPE_AUDIO)
448       {
449         const char *language = resp->extract_String();
450         m_Streams.stream[i].channels          = resp->extract_U32();
451         m_Streams.stream[i].samplerate        = resp->extract_U32();
452         m_Streams.stream[i].blockalign        = resp->extract_U32();
453         m_Streams.stream[i].bitrate           = resp->extract_U32();
454         m_Streams.stream[i].bits_per_sample   = resp->extract_U32();
455         m_Streams.stream[i].language[0]       = language[0];
456         m_Streams.stream[i].language[1]       = language[1];
457         m_Streams.stream[i].language[2]       = language[2];
458         m_Streams.stream[i].language[3]       = 0;
459       }
460       else if (m_Streams.stream[i].codec_type == CODEC_TYPE_VIDEO)
461       {
462         m_Streams.stream[i].fpsscale         = resp->extract_U32();
463         m_Streams.stream[i].fpsrate          = resp->extract_U32();
464         m_Streams.stream[i].height           = resp->extract_U32();
465         m_Streams.stream[i].width            = resp->extract_U32();
466         m_Streams.stream[i].aspect           = resp->extract_Double();
467       }
468       else if (m_Streams.stream[i].codec_type == CODEC_TYPE_SUBTITLE)
469       {
470         const char *language    = resp->extract_String();
471         uint32_t composition_id = resp->extract_U32();
472         uint32_t ancillary_id   = resp->extract_U32();
473         m_Streams.stream[i].identifier = (composition_id & 0xffff) | ((ancillary_id & 0xffff) << 16);
474         m_Streams.stream[i].language[0]= language[0];
475         m_Streams.stream[i].language[1]= language[1];
476         m_Streams.stream[i].language[2]= language[2];
477         m_Streams.stream[i].language[3]= 0;
478       }
479     }
480   }
481 }