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