]> git.vomp.tv Git - vompclient.git/blob - demuxer.cc
Windows updates
[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 }
55
56 Demuxer::~Demuxer()
57 {
58   shutdown();
59   instance = NULL;
60 }
61
62 Demuxer* Demuxer::getInstance()
63 {
64   return instance;
65 }
66
67 int Demuxer::init(Callback* tcallback, DrainTarget* audio, DrainTarget* video, ULONG demuxMemoryV, ULONG demuxMemoryA)
68 {
69   if (!initted)
70   {
71     if ( !videostream.init(video, demuxMemoryV) ||
72          !audiostream.init(audio, demuxMemoryA))
73     {
74       Log::getInstance()->log("Demuxer", Log::CRIT,
75                               "Failed to initialize demuxer");
76       shutdown();
77       return 0;
78     }
79   }
80
81   reset();
82   initted = true;
83   callback = tcallback;
84   return 1;
85 }
86
87 void Demuxer::reset()
88 {
89   flush();
90   video_current = audio_current = -1;
91   horizontal_size = vertical_size = 0;
92   aspect_ratio = (enum AspectRatio) 0;
93   frame_rate = bit_rate = 0;
94
95   for (int i = 0; i <= (PESTYPE_AUDMAX - PESTYPE_AUD0); i++)
96   {
97     avail_mpaudchan[i] = false;
98   }
99 }
100
101 int Demuxer::shutdown()
102 {
103   videostream.shutdown();
104   audiostream.shutdown();
105   initted = false;
106   return 1;
107 }
108
109 void Demuxer::flush()
110 {
111   videostream.flush();
112   audiostream.flush();
113 }
114
115 void Demuxer::flushAudio()
116 {
117   audiostream.flush();
118 }
119
120 void Demuxer::seek()
121 {
122   vid_seeking = aud_seeking = true;
123   video_pts = audio_pts = 0;
124 }
125
126 void Demuxer::setAudioStream(int id)
127 {
128   audio_current = id;
129 }
130
131 void Demuxer::setVideoStream(int id)
132 {
133   video_current = id;
134 }
135
136 void Demuxer::setAspectRatio(enum AspectRatio ar)
137 {
138   if (aspect_ratio != ar)
139   {
140     Log::getInstance()->log("Demux", Log::DEBUG,
141                             "Aspect ratio difference signalled");
142     if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal
143     {
144       arcnt = 0;
145       aspect_ratio = ar;
146       if (callback) callback->call(this);
147     }
148   }
149   else
150     arcnt = 0;
151 }
152
153 bool Demuxer::writeAudio()
154 {
155   return audiostream.drain();
156 }
157
158 bool Demuxer::writeVideo()
159 {
160   return videostream.drain();
161 }
162
163 Demuxer::PESPacket::PESPacket()
164 {
165   data[0] = 0x00;
166   data[1] = 0x00;
167   data[2] = 0x01;
168   init(0);
169 }
170
171 void Demuxer::PESPacket::init(UCHAR type)
172 {
173   length = submitted = 0;
174   size = 6; closed = false;
175   data[3] = type;
176   data[4] = data[5] = 0;
177   packetType = type;
178   pts = PTS_INVALID;
179   seq_header = false;
180 }
181
182 void Demuxer::PESPacket::truncate()
183 {
184   init(packetType);
185 }
186
187 int Demuxer::PESPacket::write(UCHAR *buf, int len)
188 {
189   if (closed) return 0;
190   if (length + len > 0xFFFA) return 0;
191   memcpy(data+length+6, buf, len);
192   length += len;
193   size += len;
194   data[4] = (length >> 8);
195   data[5] = (length & 0xFF);
196   return 1;
197 }
198
199 int Demuxer::PESPacket::submit()
200 {
201   if (submitted >= size) return 0;
202   if (!closed) parseDetails();
203
204   closed = true;
205   Demuxer* dx = Demuxer::getInstance();
206   int sent;
207   if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
208   {
209     if (dx->video_current == -1) dx->video_current = packetType;
210     if (dx->video_current == packetType && !dx->vid_seeking)
211       sent = dx->videostream.put(data+submitted, size-submitted);
212     else
213       sent = size-submitted;
214   }
215   else if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
216   {
217     if (dx->audio_current == -1) dx->audio_current = packetType;
218
219     dx->avail_mpaudchan[packetType-PESTYPE_AUD0]=true;
220
221     //Log::getInstance()->log("PESPacket", Log::DEBUG, "%i", dx->audio_current);
222     if (dx->audio_current == packetType && !dx->aud_seeking)
223       sent = dx->audiostream.put(data+submitted, size-submitted);
224     else
225       sent = size-submitted;
226   }
227   else
228   {
229     sent = size-submitted;
230   }
231
232   submitted += sent;
233   if (submitted < size) // Stream is full.
234     return 0;
235   else
236     return 1;
237 }
238
239 void Demuxer::PESPacket::parseDetails()
240 {
241   Demuxer* dx = Demuxer::getInstance();
242   if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
243   {
244     // Extract audio PTS if it exists
245     if ( size >= 14 && (data[7] & 0x80) ) // PTS_DTS_flags indicate PTS
246     {
247       dx->audio_pts = pts = ( (ULLONG)(data[9] & 0x0E)  << 29 ) |
248                             ( (ULLONG)(data[10])        << 22 ) |
249                             ( (ULLONG)(data[11] & 0xFE) << 14 ) |
250                             ( (ULLONG)(data[12])        <<  7 ) |
251                             ( (ULLONG)(data[13] & 0xFE) >>  1 );
252
253       // We continue to seek on the audio if the video PTS that we
254       // are trying to match is ahead of the audio PTS by at most
255       // SEEK_THRESHOLD. We consider the possibility of PTS wrap.
256       if (dx->aud_seeking && !dx->vid_seeking &&
257           !( (dx->video_pts_seek > dx->audio_pts &&
258               dx->video_pts_seek - dx->audio_pts < SEEK_THRESHOLD)
259               ||
260              (dx->video_pts_seek < dx->audio_pts &&
261               dx->video_pts_seek + (1LL<<33) -
262                                    dx->audio_pts < SEEK_THRESHOLD) ))
263       {
264         dx->aud_seeking = 0;
265         Log::getInstance()->log("Demuxer", Log::DEBUG,
266             "Leaving  audio sync: Audio PTS = %llu", dx->audio_pts);
267       }
268     }
269   }
270   else if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
271   {
272     // Extract video PTS if it exists
273     if ( size >= 14 && (data[7] & 0x80) ) // PTS_DTS_flags indicate PTS
274     {
275       dx->video_pts = pts = ( (ULLONG)(data[9] & 0x0E)  << 29 ) |
276                             ( (ULLONG)(data[10])        << 22 ) |
277                             ( (ULLONG)(data[11] & 0xFE) << 14 ) |
278                             ( (ULLONG)(data[12])        <<  7 ) |
279                             ( (ULLONG)(data[13] & 0xFE) >>  1 );
280     }
281
282     // Now, scan for a sequence header and extract information
283     UINT pos = 9; // Start searching from byte 9
284     while (pos < size - 5)
285     {
286       UINT pattern = *(UINT*)(data+pos);
287       if (pattern == DEMUXER_SEQ_HEAD)
288       {
289         seq_header = true;
290         pos += 4;
291         if (pos+6 >= size) return;
292         dx->horizontal_size = ((int)data[pos] << 4) | ((int)data[pos+1] >> 4);
293         dx->vertical_size = (((int)data[pos+1] & 0xf) << 8) | (int)data[pos+2];
294         dx->setAspectRatio((enum AspectRatio)(data[pos+3] >> 4));
295         dx->frame_rate = data[pos+3] & 0x0f;
296         if (dx->frame_rate >= 1 && dx->frame_rate <= 8)
297           dx->frame_rate = FrameRates[dx->frame_rate];
298         else
299           dx->frame_rate = 0;
300         dx->bit_rate = ((int)data[pos+4] << 10) |
301                    ((int)data[pos+5] << 2) |
302                    ((int)data[pos+6] >> 6);
303         if (dx->vid_seeking)
304         {
305           dx->vid_seeking = 0;
306           dx->video_pts_seek = dx->video_pts;
307           Log::getInstance()->log("Demuxer", Log::DEBUG,
308               "Entering audio sync: Video PTS = %llu", dx->video_pts);
309           Log::getInstance()->log("Demuxer", Log::DEBUG,
310               "Entering audio sync: Audio PTS = %llu", dx->audio_pts);
311         }
312         return;
313       }
314       else pos++;
315     }
316   }
317 }
318
319 UINT Demuxer::PESPacket::findPictureHeader()
320 {
321   if (size < 12) return 0;
322   UINT pattern = *(UINT*)(data+8);
323   UINT pos = 11;
324   while (pattern != DEMUXER_PIC_HEAD)
325   {
326     if (++pos >= size) return 0;
327     pattern = (pattern << 8) | data[pos];
328   }
329   return pos-3;
330 }
331
332 UINT Demuxer::stripAudio(UCHAR* buf, UINT len)
333 {
334   UINT read_pos = 0, write_pos = 0;
335   UINT pattern, packet_length;
336   if (len < 4) return 0;
337   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
338   while (read_pos + 7 <= len)
339   {
340     pattern = ((pattern & 0xFFFFFF) << 8) | buf[read_pos+3];
341     if (pattern < (0x100|PESTYPE_VID0) || pattern > (0x100|PESTYPE_VIDMAX))
342       read_pos++;
343     else
344     {
345       packet_length = ((buf[read_pos+4] << 8) | (buf[read_pos+5])) + 6;
346       if (read_pos + packet_length > len)
347         read_pos = len;
348       else
349       {
350         if (read_pos != write_pos)
351           memmove(buf+write_pos, buf+read_pos, packet_length);
352         read_pos += packet_length;
353         write_pos += packet_length;
354         pattern = (buf[read_pos] << 16) | (buf[read_pos+1] << 8)
355                                         | (buf[read_pos+2]);
356       }
357     }
358   }
359   return write_pos;
360 }
361
362 bool Demuxer::scanForVideo(UCHAR* buf, UINT len)
363 {
364   UINT pos = 3;
365   UINT pattern;
366   if (len < 4) return false;
367   pattern = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
368   while (pos < len)
369   {
370     pattern = ((pattern & 0xFFFFFF) << 8) | buf[pos++];
371     if (pattern >= (0x100|PESTYPE_VID0) && pattern <= (0x100|PESTYPE_VIDMAX))
372       return true;
373   }
374   return false;
375 }
376
377 bool* Demuxer::getmpAudioChannels()
378 {
379   return avail_mpaudchan;
380 }
381
382 int Demuxer::getselAudioChannel()
383 {
384   return audio_current;
385 }
386
387 void Demuxer::setmpAudioChannel(int aud_channel)
388 {
389   audio_current = aud_channel;
390 }