]> git.vomp.tv Git - vompclient.git/blob - demuxer.cc
DVB Subtitles
[vompclient.git] / demuxer.cc
1 /*
2     Copyright 2005-2008 Mark Calderbank
3     Copyright 2007 Marten Richter (AC3 support)
4
5     This file is part of VOMP.
6
7     VOMP is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     VOMP is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with VOMP; if not, write to the Free Software Foundation, Inc.,
19     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21
22 #include "demuxer.h"
23
24 #include "callback.h"
25 #include "log.h"
26
27 #define DEMUXER_SEQ_HEAD 0x000001B3
28 #define DEMUXER_PIC_HEAD 0x00000101
29 #define SEEK_THRESHOLD 150000 // About 1.5 seconds
30
31 // Statics
32 const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
33 Demuxer* Demuxer::instance = NULL;
34
35 // PESPacket methods
36 PESPacket::PESPacket()
37 {
38   init(0);
39   data[2] = 0x01;
40 }
41
42 void PESPacket::init(UCHAR type, UCHAR sub)
43 {
44   data.resize(6);
45   length = 0; 
46   size = 6;
47   data[3] = type;
48   packetType = type;
49   substream = sub;
50   seq_header = 1; // Unknown seq_header status
51 }
52
53 void PESPacket::truncate()
54 {
55   init(packetType,substream);
56 }
57
58 int PESPacket::write(const UCHAR *buf, int len)
59 {
60   if (length + len > 0xFFFA) return 0;
61   data.insert(data.end(), buf, buf+len);
62   length += len;
63   size += len;
64   data[4] = (length >> 8);
65   data[5] = (length & 0xFF);
66   // We have added data - reset seq_header indicator if necessary
67   if (seq_header == 0) seq_header = 1; // Reset to 'unknown'
68   return 1;
69 }
70
71 ULLONG PESPacket::getPTS() const
72 {
73   if ( ( (packetType >= Demuxer::PESTYPE_AUD0 &&
74           packetType <= Demuxer::PESTYPE_AUDMAX)
75          ||
76          (packetType >= Demuxer::PESTYPE_VID0 &&
77           packetType <= Demuxer::PESTYPE_VIDMAX)
78    ||
79           packetType == Demuxer::PESTYPE_PRIVATE_1
80        )
81        && size >= 14 && data[7] & 0x80)
82   {
83     return ( (ULLONG)(data[ 9] & 0x0E) << 29) |
84            ( (ULLONG)(data[10])        << 22 ) |
85            ( (ULLONG)(data[11] & 0xFE) << 14 ) |
86            ( (ULLONG)(data[12])        <<  7 ) |
87            ( (ULLONG)(data[13] & 0xFE) >>  1 );
88   }
89   else return PTS_INVALID;
90 }
91
92 UCHAR PESPacket::operator[] (UINT index) const
93 {
94   if (index >= size)
95     return 0;
96   else
97     return data[index];
98 }
99
100 UINT PESPacket::findPictureHeader() const
101 {
102   if (size < 12) return 0;
103   UINT pattern = ( ((UINT)data[ 8] << 24) |
104                    ((UINT)data[ 9] << 16) |
105                    ((UINT)data[10] <<  8) |
106                     (UINT)data[11]  );
107   UINT pos = 11;
108   while (pattern != DEMUXER_PIC_HEAD)
109   {
110     if (++pos >= size) return 0;
111     pattern = (pattern << 8) | data[pos];
112   }
113   return pos-3;
114 }
115
116 UINT PESPacket::findSeqHeader() const
117 {
118   if (seq_header != 1) return seq_header;
119   if (size < 12) return 0;
120   UINT pattern = ( ((UINT)data[ 8] << 24) |
121                    ((UINT)data[ 9] << 16) |
122                    ((UINT)data[10] <<  8) |
123                     (UINT)data[11]  );
124   UINT pos = 11;
125   while (pattern != DEMUXER_SEQ_HEAD)
126   {
127     if (++pos >= size)
128     {
129       seq_header = 0;
130       return 0;
131     }
132     pattern = (pattern << 8) | data[pos];
133   }
134   seq_header = pos - 3;
135   return seq_header;
136 }
137
138 // Demuxer methods
139 Demuxer::Demuxer()
140 {
141   if (instance) return;
142   instance = this;
143   initted = false;
144   callback = NULL;
145   arcnt = 0;
146   vid_seeking = aud_seeking = false;
147   video_pts = audio_pts = 0;
148   ispre_1_3_19 = false;
149 }
150
151 Demuxer::~Demuxer()
152 {
153   shutdown();
154   instance = NULL;
155 }
156
157 Demuxer* Demuxer::getInstance()
158 {
159   return instance;
160 }
161
162 int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, ULONG demuxMemoryV, ULONG demuxMemoryA, DVBSubtitles* tsubtitles)
163 {
164   if (!initted)
165   {
166     if ( !videostream.init(video, demuxMemoryV) ||
167          !audiostream.init(audio, demuxMemoryA))
168     {
169       Log::getInstance()->log("Demuxer", Log::CRIT,
170                               "Failed to initialize demuxer");
171       shutdown();
172       return 0;
173     }
174   }
175
176   reset();
177   initted = true;
178   subtitles = tsubtitles;
179   callback = tcallback;
180   return 1;
181 }
182
183 void Demuxer::reset()
184 {
185   Log::getInstance()->log("Demuxer", Log::DEBUG, "Reset called");
186   flush();
187   video_current = audio_current = -1;
188   horizontal_size = vertical_size = 0;
189   aspect_ratio = (enum AspectRatio) 0;
190   frame_rate = bit_rate = 0;
191   ispre_1_3_19 = false;
192
193   for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)
194   {
195     avail_mpaudchan[i] = false;
196   }
197   for (int i = 0; i <= (PESTYPE_SUBSTREAM_AC3MAX - PESTYPE_SUBSTREAM_AC30); i++)
198   {
199     avail_ac3audchan[i] = false;
200   }
201 }
202
203 int Demuxer::shutdown()
204 {
205   videostream.shutdown();
206   audiostream.shutdown();
207   initted = false;
208   return 1;
209 }
210
211 void Demuxer::flush()
212 {
213   Log::getInstance()->log("Demuxer", Log::DEBUG, "Flush called");
214
215   videostream.flush();
216   audiostream.flush();
217 }
218
219 void Demuxer::flushAudio()
220 {
221   audiostream.flush();
222 }
223
224 void Demuxer::seek()
225 {
226   vid_seeking = aud_seeking = true;
227   video_pts = audio_pts = 0;
228 }
229
230 void Demuxer::setAudioStream(int id)
231 {
232   audio_current = id;
233 }
234
235 void Demuxer::setVideoStream(int id)
236 {
237   video_current = id;
238 }
239
240 void Demuxer::setAspectRatio(enum AspectRatio ar)
241 {
242   if (aspect_ratio != ar)
243   {
244     Log::getInstance()->log("Demux", Log::DEBUG,
245                             "Aspect ratio difference signalled");
246     if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal
247     {
248       arcnt = 0;
249       aspect_ratio = ar;
250       if (callback) callback->call(this);
251     }
252   }
253   else
254     arcnt = 0;
255 }
256
257 bool Demuxer::writeAudio()
258 {
259   return audiostream.drain();
260 }
261
262 bool Demuxer::writeVideo()
263 {
264   return videostream.drain();
265 }
266
267 bool Demuxer::submitPacket(PESPacket& packet)
268 {
269   UINT sent = 0;
270   UCHAR packet_type = packet.getPacketType();
271   const std::vector<UCHAR>& packetdata = packet.getData();
272
273   if (packet_type >= PESTYPE_VID0 && packet_type <= PESTYPE_VIDMAX)
274   {
275     if (video_current == -1) video_current = packet_type;
276     if (video_current == packet_type && !vid_seeking)
277       sent = videostream.put(&packetdata[0], packet.getSize(), MPTYPE_VIDEO);
278     else
279       sent = packet.getSize();
280   }
281   else if (packet_type >= PESTYPE_AUD0 && packet_type <= PESTYPE_AUDMAX)
282   {
283     if (audio_current == -1) audio_current = packet_type;
284     avail_mpaudchan[packet_type - PESTYPE_AUD0] = true;
285     if (audio_current == packet_type && !aud_seeking)
286       sent = audiostream.put(&packetdata[0], packet.getSize(), MPTYPE_MPEG_AUDIO);
287     else
288       sent = packet.getSize();
289   }
290   else if (packet_type == PESTYPE_PRIVATE_1 &&
291            packet.getSubstream() >= PESTYPE_SUBSTREAM_AC30 &&
292            packet.getSubstream() <= PESTYPE_SUBSTREAM_AC3MAX)
293   {
294     avail_ac3audchan[packet.getSubstream() - PESTYPE_SUBSTREAM_AC30] = true;
295     if (packet.getSubstream() == audio_current)
296     {
297       sent = audiostream.put(&packetdata[0], packet.getSize(), (ispre_1_3_19)? MPTYPE_AC3_PRE13 : MPTYPE_AC3);
298     }
299     else
300     {
301       sent = packet.getSize();
302     }
303   }
304   else
305   {
306     sent = packet.getSize();
307   }
308
309   if (sent < packet.getSize()) // Stream is full.
310     return false;
311   else
312     return true;
313 }
314
315 void Demuxer::parsePacketDetails(PESPacket& packet)
316 {
317   if (packet.getPacketType() >= PESTYPE_AUD0 &&
318       packet.getPacketType() <= PESTYPE_AUDMAX)
319   {
320     // Extract audio PTS if it exists
321     if (packet.hasPTS())
322     {
323       audio_pts = packet.getPTS();
324       // We continue to seek on the audio if the video PTS that we
325       // are trying to match is ahead of the audio PTS by at most
326       // SEEK_THRESHOLD. We consider the possibility of PTS wrap.
327       if (aud_seeking && !vid_seeking &&
328           !( (video_pts_seek > audio_pts &&
329               video_pts_seek - audio_pts < SEEK_THRESHOLD)
330               ||
331              (video_pts_seek < audio_pts &&
332               video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))
333       {
334         aud_seeking = 0;
335         Log::getInstance()->log("Demuxer", Log::DEBUG,
336             "Leaving  audio sync: Audio PTS = %llu", audio_pts);
337       }
338     }
339   }
340   else if (packet.getPacketType() == PESTYPE_PRIVATE_1) // Private stream
341   {
342     //Inspired by vdr's device.c
343     int payload_begin = packet[8]+9;
344     unsigned char substream_id = packet[payload_begin];
345     unsigned char substream_type = substream_id & 0xF0;
346     unsigned char substream_index = substream_id & 0x1F;
347 pre_1_3_19_Recording: //This is for old recordings stuff and live TV
348     if (ispre_1_3_19)
349     {
350       substream_id = PESTYPE_PRIVATE_1;
351       substream_type = 0x80;
352       substream_index = 0;
353     }
354     switch (substream_type)
355     {
356       case 0x20://SPU
357       case 0x30://SPU
358         break;
359       case 0xA0: //LPCM //not supported yet, is there any LPCM transmissio out there?
360         break;
361       case 0x80: //ac3, currently only one ac3 track per recording supported
362         packet.setSubstream(substream_type+substream_index);
363
364         // Extract audio PTS if it exists
365         if (packet.hasPTS())
366         {
367           audio_pts = packet.getPTS();
368           // We continue to seek on the audio if the video PTS that we
369           // are trying to match is ahead of the audio PTS by at most
370           // SEEK_THRESHOLD. We consider the possibility of PTS wrap.
371           if (aud_seeking && !vid_seeking &&
372               !( (video_pts_seek > audio_pts &&
373                   video_pts_seek - audio_pts < SEEK_THRESHOLD)
374               ||
375               (video_pts_seek < audio_pts &&
376                     video_pts_seek + (1LL<<33) - audio_pts < SEEK_THRESHOLD) ))
377           {
378             aud_seeking = 0;
379             Log::getInstance()->log("Demuxer", Log::DEBUG, "Leaving  audio sync: Audio PTS = %llu", audio_pts);
380           }
381         }
382         break;
383       default:
384         if (!ispre_1_3_19)
385         {
386           ispre_1_3_19=true; //switching to compat mode and live tv mode
387           goto pre_1_3_19_Recording;
388         }
389         else
390         {
391           packet.setSubstream(0);
392         }
393         break;
394     }
395   }
396   else if (packet.getPacketType() >= PESTYPE_VID0 &&
397            packet.getPacketType() <= PESTYPE_VIDMAX)
398   {
399     // Extract video PTS if it exists
400     if (packet.hasPTS()) video_pts = packet.getPTS();
401
402     // If there is a sequence header, extract information
403     UINT pos = packet.findSeqHeader();
404     if (pos > 1)
405     {
406       pos += 4;
407       if (pos+6 >= packet.getSize()) return;
408       horizontal_size = ((int)packet[pos] << 4) | ((int)packet[pos+1] >> 4);
409       vertical_size = (((int)packet[pos+1] & 0xf) << 8) | (int)packet[pos+2];
410       setAspectRatio((enum AspectRatio)(packet[pos+3] >> 4));
411       frame_rate = packet[pos+3] & 0x0f;
412       if (frame_rate >= 1 && frame_rate <= 8)
413         frame_rate = FrameRates[frame_rate];
414       else
415         frame_rate = 0;
416       bit_rate = ((int)packet[pos+4] << 10) |
417                  ((int)packet[pos+5] << 2) |
418                  ((int)packet[pos+6] >> 6);
419       if (vid_seeking)
420       {
421         vid_seeking = 0;
422         video_pts_seek = video_pts;
423         Log::getInstance()->log("Demuxer", Log::DEBUG,
424             "Entering audio sync: Video PTS = %llu", video_pts);
425         Log::getInstance()->log("Demuxer", Log::DEBUG,
426             "Entering audio sync: Audio PTS = %llu", audio_pts);
427       }
428       return;
429     }
430   }
431 }
432
433 UINT Demuxer::stripAudio(UCHAR* buf, UINT len)
434 {
435   UINT read_pos = 0, write_pos = 0;
436   UINT pattern, packet_length;
437   if (len < 4) return 0;
438   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
439   while (read_pos + 7 <= len)
440   {
441     pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];
442     if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))
443       read_pos++;
444     else
445     {
446       packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;
447       if (read_pos + packet_length > len)
448         read_pos = len;
449       else
450       {
451         if (read_pos != write_pos)
452           memmove(buf+write_pos, buf+read_pos, packet_length);
453         read_pos += packet_length;
454         write_pos += packet_length;
455         pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)
456                                         | (buf[read_pos+2]);
457       }
458     }
459   }
460   return write_pos;
461 }
462
463 bool Demuxer::scanForVideo(UCHAR* buf, UINT len)
464 {
465   UINT pos = 3;
466   UINT pattern;
467   if (len < 4) return false;
468   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
469   while (pos < len)
470   {
471     pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];
472     if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))
473       return true;
474   }
475   return false;
476 }
477
478 bool* Demuxer::getmpAudioChannels()
479 {
480   return avail_mpaudchan;
481 }
482
483 bool* Demuxer::getac3AudioChannels()
484 {
485   return avail_ac3audchan;
486 }
487
488 int Demuxer::getselAudioChannel()
489 {
490   return audio_current;
491 }
492
493 void Demuxer::setAudioChannel(int aud_channel)
494 {
495   audio_current = aud_channel;
496 }