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