2 Copyright 2005-2006 Mark Calderbank
4 This file is part of VOMP.
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.
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.
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
24 #if __BYTE_ORDER == __BIG_ENDIAN
25 #define DEMUXER_SEQ_HEAD 0x000001B3
27 #define DEMUXER_SEQ_HEAD 0xB3010000
30 const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
32 Demuxer* Demuxer::instance = NULL;
49 Demuxer* Demuxer::getInstance()
54 int Demuxer::init(Callback* tcallback)
58 if ( !videostream.init(demuxMemoryV) ||
59 !audiostream.init(demuxMemoryA))
61 Log::getInstance()->log("Demuxer", Log::CRIT, "Failed to initialize demuxer");
66 videostream.setDrainTarget(Video::getInstance());
67 audiostream.setDrainTarget(Audio::getInstance());
80 video_current = audio_current = -1;
81 horizontal_size = vertical_size = 0;
82 aspect_ratio = (enum AspectRatio) 0;
83 frame_rate = bit_rate = 0;
86 int Demuxer::shutdown()
88 videostream.shutdown();
89 audiostream.shutdown();
100 void Demuxer::flushAudio()
107 vid_seeking = aud_seeking = true;
108 video_pts = audio_pts = 0;
111 void Demuxer::setAudioStream(int id)
116 void Demuxer::setVideoStream(int id)
121 void Demuxer::setAspectRatio(enum AspectRatio ar)
123 if (aspect_ratio != ar)
125 Log::getInstance()->log("Demux", Log::DEBUG, "Aspect ratio difference signalled");
126 if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal
130 callback->call(this);
137 int Demuxer::writeAudio(int fd)
139 return audiostream.drain(fd);
142 int Demuxer::writeVideo(int fd)
144 return videostream.drain(fd);
147 int Demuxer::writeAudio(DrainTarget* dt)
149 return audiostream.drain(dt);
152 int Demuxer::writeVideo(DrainTarget* dt)
154 return videostream.drain(dt);
158 Demuxer::PESPacket::PESPacket()
166 void Demuxer::PESPacket::init(UCHAR type)
168 length = submitted = 0;
169 size = 6; closed = false;
171 data[4] = data[5] = 0;
175 int Demuxer::PESPacket::write(UCHAR *buf, int len)
177 if (closed) return 0;
178 if (length + len > 0xFFFA) return 0;
179 memcpy(data+length+6, buf, len);
182 data[4] = (length >> 8);
183 data[5] = (length & 0xFF);
187 int Demuxer::PESPacket::submit()
189 if (submitted >= size) return 0;
190 if (!closed) parseDetails();
193 Demuxer* dx = Demuxer::getInstance();
195 if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
197 if (dx->video_current == -1) dx->video_current = packetType;
198 if (dx->video_current == packetType && !dx->vid_seeking)
199 sent = dx->videostream.put(data+submitted, size-submitted);
201 sent = size-submitted;
203 else if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
205 if (dx->audio_current == -1) dx->audio_current = packetType;
206 if (dx->audio_current == packetType & !dx->aud_seeking)
207 sent = dx->audiostream.put(data+submitted, size-submitted);
209 sent = size-submitted;
213 sent = size-submitted;
217 if (submitted < size) // Stream is full.
223 void Demuxer::PESPacket::parseDetails()
225 Demuxer* dx = Demuxer::getInstance();
226 if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
228 // Extract audio PTS if it exists
229 if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
231 dx->audio_pts = ( (ULLONG)(data[9] & 0x0E) << 29 ) |
232 ( (ULLONG)(data[10]) << 22 ) |
233 ( (ULLONG)(data[11] & 0xFE) << 14 ) |
234 ( (ULLONG)(data[12]) << 7 ) |
235 ( (ULLONG)(data[13] & 0xFE) >> 1 );
236 if (dx->aud_seeking && !dx->vid_seeking &&
237 dx->audio_pts >= dx->video_pts_seek)
240 Log::getInstance()->log("Demuxer", Log::DEBUG,
241 "Leaving audio sync: Audio PTS = %llu", dx->audio_pts);
245 else if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
247 // Extract video PTS if it exists
248 if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
250 dx->video_pts = ( (ULLONG)(data[9] & 0x0E) << 29 ) |
251 ( (ULLONG)(data[10]) << 22 ) |
252 ( (ULLONG)(data[11] & 0xFE) << 14 ) |
253 ( (ULLONG)(data[12]) << 7 ) |
254 ( (ULLONG)(data[13] & 0xFE) >> 1 );
257 // Now, scan for a sequence header and extract information
258 UINT pos = 9; // Start searching from byte 9
259 while (pos < size - 5)
261 UINT pattern = *(UINT*)(data+pos);
262 if (pattern == DEMUXER_SEQ_HEAD)
265 if (pos+6 >= size) return;
266 dx->horizontal_size = ((int)data[pos] << 4) | ((int)data[pos+1] >> 4);
267 dx->vertical_size = (((int)data[pos+1] & 0xf) << 8) | (int)data[pos+2];
268 dx->setAspectRatio((enum AspectRatio)(data[pos+3] >> 4));
269 dx->frame_rate = data[pos+3] & 0x0f;
270 if (dx->frame_rate >= 1 && dx->frame_rate <= 8)
271 dx->frame_rate = FrameRates[dx->frame_rate];
274 dx->bit_rate = ((int)data[pos+4] << 10) |
275 ((int)data[pos+5] << 2) |
276 ((int)data[pos+6] >> 6);
280 dx->video_pts_seek = dx->video_pts;
281 Log::getInstance()->log("Demuxer", Log::DEBUG,
282 "Entering audio sync: Video PTS = %llu", dx->video_pts);
283 Log::getInstance()->log("Demuxer", Log::DEBUG,
284 "Entering audio sync: Audio PTS = %llu", dx->audio_pts);