]> git.vomp.tv Git - vompclient.git/blob - demuxer.cc
Demuxer redesign
[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 #include <endian.h>
23
24 #if __BYTE_ORDER == __BIG_ENDIAN
25 #define DEMUXER_SEQ_HEAD 0x000001B3
26 #else
27 #define DEMUXER_SEQ_HEAD 0xB3010000
28 #endif
29
30 const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
31
32 Demuxer* Demuxer::instance = NULL;
33
34 Demuxer::Demuxer()
35 {
36   if (instance) return;
37   instance = this;
38   initted = false;
39   callback = NULL;
40   arcnt = 0;
41 }
42
43 Demuxer::~Demuxer()
44 {
45   shutdown();
46   instance = NULL;
47 }
48
49 Demuxer* Demuxer::getInstance()
50 {
51   return instance;
52 }
53
54 int Demuxer::init(Callback* tcallback)
55 {
56   if (!initted)
57   {
58     if ( !videostream.init(demuxMemoryV) ||
59          !audiostream.init(demuxMemoryA))
60     {
61       Log::getInstance()->log("Demuxer", Log::CRIT, "Failed to initialize demuxer");
62       shutdown();
63       return 0;
64     }
65 #ifdef NEW_DEMUXER
66     videostream.setDrainTarget(Video::getInstance());
67     audiostream.setDrainTarget(Audio::getInstance());
68 #endif
69   }
70
71   reset();
72   initted = true;
73   callback = tcallback;
74   return 1;
75 }
76
77 void Demuxer::reset()
78 {
79   flush();
80   video_current = audio_current = -1;
81   horizontal_size = vertical_size = 0;
82   aspect_ratio = (enum AspectRatio) 0;
83   frame_rate = bit_rate = 0;
84 }
85
86 int Demuxer::shutdown()
87 {
88   videostream.shutdown();
89   audiostream.shutdown();
90   initted = false;
91   return 1;
92 }
93
94 void Demuxer::flush()
95 {
96   videostream.flush();
97   audiostream.flush();
98 }
99
100 void Demuxer::flushAudio()
101 {
102   audiostream.flush();
103 }
104
105 void Demuxer::seek()
106 {
107   vid_seeking = aud_seeking = true;
108   video_pts = audio_pts = 0;
109 }
110
111 void Demuxer::setAudioStream(int id)
112 {
113   audio_current = id;
114 }
115
116 void Demuxer::setVideoStream(int id)
117 {
118   video_current = id;
119 }
120
121 void Demuxer::setAspectRatio(enum AspectRatio ar)
122 {
123   if (aspect_ratio != ar)
124   {
125     Log::getInstance()->log("Demux", Log::DEBUG, "Aspect ratio difference signalled");
126     if (++arcnt > 3) // avoid changing aspect ratio if glitch in signal
127     {
128       arcnt = 0;
129       aspect_ratio = ar;
130       callback->call(this);
131     }
132   }
133   else
134     arcnt = 0;
135 }
136 #ifndef NEW_DEMUXER
137 int Demuxer::writeAudio(int fd)
138 {
139   return audiostream.drain(fd);
140 }
141
142 int Demuxer::writeVideo(int fd)
143 {
144   return videostream.drain(fd);
145 }
146 #else
147 int Demuxer::writeAudio(DrainTarget* dt)
148 {
149   return audiostream.drain(dt);
150 }
151
152 int Demuxer::writeVideo(DrainTarget* dt)
153 {
154   return videostream.drain(dt);
155 }
156 #endif
157
158 Demuxer::PESPacket::PESPacket()
159 {
160   data[0] = 0x00;
161   data[1] = 0x00;
162   data[2] = 0x01;
163   init(0);
164 }
165
166 void Demuxer::PESPacket::init(UCHAR type)
167 {
168   length = submitted = 0;
169   size = 6; closed = false;
170   data[3] = type;
171   data[4] = data[5] = 0;
172   packetType = type;
173 }
174
175 int Demuxer::PESPacket::write(UCHAR *buf, int len)
176 {
177   if (closed) return 0;
178   if (length + len > 0xFFFA) return 0;
179   memcpy(data+length+6, buf, len);
180   length += len;
181   size += len;
182   data[4] = (length >> 8);
183   data[5] = (length & 0xFF);
184   return 1;
185 }
186
187 int Demuxer::PESPacket::submit()
188 {
189   if (submitted >= size) return 0;
190   if (!closed) parseDetails();
191
192   closed = true;
193   Demuxer* dx = Demuxer::getInstance();
194   int sent;
195   if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
196   {
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);
200     else
201       sent = size-submitted;
202   }
203   else if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
204   {
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);
208     else
209       sent = size-submitted;
210   }
211   else
212   {
213     sent = size-submitted;
214   }
215
216   submitted += sent;
217   if (submitted < size) // Stream is full.
218     return 0;
219   else
220     return 1;
221 }
222
223 void Demuxer::PESPacket::parseDetails()
224 {
225   Demuxer* dx = Demuxer::getInstance();
226   if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
227   {
228     // Extract audio PTS if it exists
229     if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
230     {
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)
238       {
239         dx->aud_seeking = 0;
240         Log::getInstance()->log("Demuxer", Log::DEBUG,
241             "Leaving  audio sync: Audio PTS = %llu", dx->audio_pts);
242       }
243     }
244   }
245   else if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
246   {
247     // Extract video PTS if it exists
248     if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
249     {
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 );
255     }
256
257     // Now, scan for a sequence header and extract information
258     UINT pos = 9; // Start searching from byte 9
259     while (pos < size - 5)
260     {
261       UINT pattern = *(UINT*)(data+pos);
262       if (pattern == DEMUXER_SEQ_HEAD)
263       {
264         pos += 4;
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];
272         else
273           dx->frame_rate = 0;
274         dx->bit_rate = ((int)data[pos+4] << 10) |
275                    ((int)data[pos+5] << 2) |
276                    ((int)data[pos+6] >> 6);
277         if (dx->vid_seeking)
278         {
279           dx->vid_seeking = 0;
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);
285         }
286         return;
287       }
288       else pos++;
289     }
290   }
291 }