]> git.vomp.tv Git - vompclient.git/blob - demuxer.cc
Windows port changes
[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
37
38 const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
39
40 Demuxer* Demuxer::instance = NULL;
41
42 Demuxer::Demuxer()
43 {
44   if (instance) return;
45   instance = this;
46   initted = false;
47   callback = NULL;
48   arcnt = 0;
49   vid_seeking = aud_seeking = false;
50   video_pts = audio_pts = 0;
51 }
52
53 Demuxer::~Demuxer()
54 {
55   shutdown();
56   instance = NULL;
57 }
58
59 Demuxer* Demuxer::getInstance()
60 {
61   return instance;
62 }
63
64 int Demuxer::init(Callback* tcallback)
65 {
66   if (!initted)
67   {
68     if ( !videostream.init(demuxMemoryV) ||
69          !audiostream.init(demuxMemoryA))
70     {
71       Log::getInstance()->log("Demuxer", Log::CRIT, "Failed to initialize demuxer");
72       shutdown();
73       return 0;
74     }
75 #ifdef NEW_DEMUXER
76     videostream.setDrainTarget(Video::getInstance());
77     audiostream.setDrainTarget(Audio::getInstance());
78 #endif
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
96 int Demuxer::shutdown()
97 {
98   videostream.shutdown();
99   audiostream.shutdown();
100   initted = false;
101   return 1;
102 }
103
104 void Demuxer::flush()
105 {
106   videostream.flush();
107   audiostream.flush();
108 }
109
110 void Demuxer::flushAudio()
111 {
112   audiostream.flush();
113 }
114
115 void Demuxer::seek()
116 {
117   vid_seeking = aud_seeking = true;
118   video_pts = audio_pts = 0;
119 }
120
121 void Demuxer::setAudioStream(int id)
122 {
123   audio_current = id;
124 }
125
126 void Demuxer::setVideoStream(int id)
127 {
128   video_current = id;
129 }
130
131 void Demuxer::setAspectRatio(enum AspectRatio ar)
132 {
133   if (aspect_ratio != ar)
134   {
135     Log::getInstance()->log("Demux", Log::DEBUG, "Aspect ratio difference signalled");
136     if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal
137     {
138       arcnt = 0;
139       aspect_ratio = ar;
140       callback->call(this);
141     }
142   }
143   else
144     arcnt = 0;
145 }
146 #ifndef NEW_DEMUXER
147 int Demuxer::writeAudio(int fd)
148 {
149   return audiostream.drain(fd);
150 }
151
152 int Demuxer::writeVideo(int fd)
153 {
154   return videostream.drain(fd);
155 }
156 #else
157 int Demuxer::writeAudio(DrainTarget* dt)
158 {
159   return audiostream.drain(dt);
160 }
161
162 int Demuxer::writeVideo(DrainTarget* dt)
163 {
164   return videostream.drain(dt);
165 }
166 #endif
167
168 Demuxer::PESPacket::PESPacket()
169 {
170   data[0] = 0x00;
171   data[1] = 0x00;
172   data[2] = 0x01;
173   init(0);
174 }
175
176 void Demuxer::PESPacket::init(UCHAR type)
177 {
178   length = submitted = 0;
179   size = 6; closed = false;
180   data[3] = type;
181   data[4] = data[5] = 0;
182   packetType = type;
183 }
184
185 int Demuxer::PESPacket::write(UCHAR *buf, int len)
186 {
187   if (closed) return 0;
188   if (length + len > 0xFFFA) return 0;
189   memcpy(data+length+6, buf, len);
190   length += len;
191   size += len;
192   data[4] = (length >> 8);
193   data[5] = (length & 0xFF);
194   return 1;
195 }
196 #ifndef NEW_DEMUXER
197 int Demuxer::PESPacket::submit()
198 #else
199 int Demuxer::PESPacket::submit(ULLONG cur_pos)
200 #endif
201 {
202   if (submitted >= size) return 0;
203   if (!closed) parseDetails();
204
205   closed = true;
206   Demuxer* dx = Demuxer::getInstance();
207   int sent;
208   if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
209   {
210     if (dx->video_current == -1) dx->video_current = packetType;
211     if (dx->video_current == packetType && !dx->vid_seeking)
212 #ifndef NEW_DEMUXER
213       sent = dx->videostream.put(data+submitted, size-submitted);
214 #else
215     sent = dx->videostream.put(data+submitted, size-submitted,cur_pos);
216 #endif
217     else
218       sent = size-submitted;
219   }
220   else if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
221   {
222     if (dx->audio_current == -1) dx->audio_current = packetType;
223     if (dx->audio_current == packetType && !dx->aud_seeking)
224 #ifndef NEW_DEMUXER
225       sent = dx->audiostream.put(data+submitted, size-submitted);
226 #else
227       sent = dx->audiostream.put(data+submitted, size-submitted,cur_pos);
228 #endif
229     else
230       sent = size-submitted;
231   }
232   else
233   {
234     sent = size-submitted;
235   }
236
237   submitted += sent;
238   if (submitted < size) // Stream is full.
239     return 0;
240   else
241     return 1;
242 }
243
244 void Demuxer::PESPacket::parseDetails()
245 {
246   Demuxer* dx = Demuxer::getInstance();
247   if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
248   {
249     // Extract audio PTS if it exists
250     if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
251     {
252       dx->audio_pts = ( (ULLONG)(data[9] & 0x0E) << 29 ) |
253                       ( (ULLONG)(data[10])        << 22 ) |
254                       ( (ULLONG)(data[11] & 0xFE) << 14 ) |
255                       ( (ULLONG)(data[12])        <<  7 ) |
256                       ( (ULLONG)(data[13] & 0xFE) >>  1 );
257       if (dx->aud_seeking && !dx->vid_seeking &&
258           dx->audio_pts >= dx->video_pts_seek)
259       {
260         dx->aud_seeking = 0;
261         Log::getInstance()->log("Demuxer", Log::DEBUG,
262             "Leaving  audio sync: Audio PTS = %llu", dx->audio_pts);
263       }
264     }
265   }
266   else if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
267   {
268     // Extract video PTS if it exists
269     if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
270     {
271       dx->video_pts = ( (ULLONG)(data[9] & 0x0E) << 29 ) |
272                       ( (ULLONG)(data[10])        << 22 ) |
273                       ( (ULLONG)(data[11] & 0xFE) << 14 ) |
274                       ( (ULLONG)(data[12])        <<  7 ) |
275                       ( (ULLONG)(data[13] & 0xFE) >>  1 );
276     }
277
278     // Now, scan for a sequence header and extract information
279     UINT pos = 9; // Start searching from byte 9
280     while (pos < size - 5)
281     {
282       UINT pattern = *(UINT*)(data+pos);
283       if (pattern == DEMUXER_SEQ_HEAD)
284       {
285         pos += 4;
286         if (pos+6 >= size) return;
287         dx->horizontal_size = ((int)data[pos] << 4) | ((int)data[pos+1] >> 4);
288         dx->vertical_size = (((int)data[pos+1] & 0xf) << 8) | (int)data[pos+2];
289         dx->setAspectRatio((enum AspectRatio)(data[pos+3] >> 4));
290         dx->frame_rate = data[pos+3] & 0x0f;
291         if (dx->frame_rate >= 1 && dx->frame_rate <= 8)
292           dx->frame_rate = FrameRates[dx->frame_rate];
293         else
294           dx->frame_rate = 0;
295         dx->bit_rate = ((int)data[pos+4] << 10) |
296                    ((int)data[pos+5] << 2) |
297                    ((int)data[pos+6] >> 6);
298         if (dx->vid_seeking)
299         {
300           dx->vid_seeking = 0;
301           dx->video_pts_seek = dx->video_pts;
302           Log::getInstance()->log("Demuxer", Log::DEBUG,
303               "Entering audio sync: Video PTS = %llu", dx->video_pts);
304           Log::getInstance()->log("Demuxer", Log::DEBUG,
305               "Entering audio sync: Audio PTS = %llu", dx->audio_pts);
306         }
307         return;
308       }
309       else pos++;
310     }
311   }
312 }