1 /*
2 * lpcmstrm_in.c: LPCM Audio strem class members handling scanning and
3 * buffering raw input stream.
4 *
5 * Takes a *RAW* LPCM stream as input.
6 * This is *signed* linear 16, 20, or 24-bit sample PCM.
7 * Samples are stored msb first.
8 * How 20-bit samples are allocated to bytes? I just don't know, but
9 * believe 4 bits are appended after the lsb (samples are msb-byte aligned).
10 *
11 * Copyright (C) 2001 Andrew Stevens <andrew.stevens@philips.com>
12 * Copyright (C) 2000,2001 Brent Byeler for original header-structure
13 * parsing code.
14 *
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of version 2 of the GNU General Public License
18 * as published by the Free Software Foundation.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 */
29
30 #include <config.h>
31 #include <math.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "audiostrm.hpp"
36 #include "interact.hpp"
37 #include "multiplexor.hpp"
38
39
40 const unsigned int LPCMStream::default_buffer_size = 58*1024;
41 const unsigned int LPCMStream::ticks_per_frame_90kHz = 150;
42
43
LPCMStream(IBitStream & ibs,LpcmParams * parms,Multiplexor & into)44 LPCMStream::LPCMStream(IBitStream &ibs, LpcmParams *parms, Multiplexor &into) :
45 AudioStream( ibs, into ),
46 parms(parms)
47 {
48 num_frames = 0;
49 }
50
51
52
53
Probe(IBitStream & bs)54 bool LPCMStream::Probe(IBitStream &bs )
55 {
56 const char *last_dot = strrchr( bs.StreamName(), '.' );
57 return
58 last_dot != NULL
59 && strcmp( last_dot+1, "lpcm") == 0;
60
61 }
62
63
64 /*************************************************************************
65 *
66 * Reads initial stream parameters and displays feedback banner to users
67 *
68 *************************************************************************/
69
70
Init(const int _stream_num)71 void LPCMStream::Init ( const int _stream_num)
72
73 {
74 stream_num = _stream_num;
75 header_skip = 0;
76 MuxStream::Init( PRIVATE_STR_1,
77 1, // Buffer scale
78 default_buffer_size,
79 false,
80 muxinto.buffers_in_audio,
81 muxinto.always_buffers_in_audio
82 );
83
84 // This seems to be necessary not only for some software players but
85 // for some standalone players too. Yuck... shades of the VCD audio
86 // sectors.
87 min_pes_header_len = 10;
88 mjpeg_info ("Scanning for header info: LPCM Audio stream %02x (%s)",
89 stream_num,
90 bs.StreamName()
91 );
92
93
94 AU_start = bs.bitcount();
95
96 // This is a dummy debug version that simply assumes 48kHz
97 // two channel 16 bit sample LPCM
98
99 samples_per_second = parms->SamplesPerSec();
100 channels = parms->Channels();
101 bits_per_sample = parms->BitsPerSample();
102 bytes_per_frame =
103 samples_per_second * channels * bits_per_sample / 8
104 * ticks_per_frame_90kHz
105 / 90000;
106 frame_index = 0;
107 dynamic_range_code = 0x80;
108
109 /* Presentation/decoding time-stamping */
110 access_unit.start = AU_start;
111 access_unit.length = bytes_per_frame;
112 access_unit.PTS = static_cast<clockticks>(decoding_order) *
113 (CLOCKS_per_90Kth_sec * ticks_per_frame_90kHz);
114 access_unit.DTS = access_unit.PTS;
115 access_unit.dorder = decoding_order;
116 decoding_order++;
117 aunits.Append( access_unit );
118
119 OutputHdrInfo();
120 }
121
NominalBitRate()122 unsigned int LPCMStream::NominalBitRate()
123 {
124 return samples_per_second * channels * bits_per_sample;
125 }
126
127
128
FillAUbuffer(unsigned int frames_to_buffer)129 void LPCMStream::FillAUbuffer(unsigned int frames_to_buffer )
130 {
131 last_buffered_AU += frames_to_buffer;
132 mjpeg_debug( "Scanning %d MPEG LPCM audio frames to frame %d",
133 frames_to_buffer, last_buffered_AU );
134
135 while ( !bs.eos()
136 && decoding_order < last_buffered_AU
137 && !muxinto.AfterMaxPTS(access_unit.PTS) )
138 {
139 int skip=access_unit.length;
140 bs.SeekFwdBits( skip );
141 prev_offset = AU_start;
142 AU_start = bs.bitcount();
143 if( AU_start - prev_offset != access_unit.length*8 )
144 {
145 mjpeg_warn("Discarding incomplete final frame LPCM stream %d",
146 stream_num);
147 aunits.DropLast();
148 --decoding_order;
149 break;
150 }
151
152 // Here we would check for header data but LPCM has no headers...
153 if( bs.eos() )
154 break;
155
156 access_unit.start = AU_start;
157 access_unit.length = bytes_per_frame;
158 access_unit.PTS = static_cast<clockticks>(decoding_order) *
159 (CLOCKS_per_90Kth_sec * ticks_per_frame_90kHz);
160 access_unit.DTS = access_unit.PTS;
161 access_unit.dorder = decoding_order;
162 decoding_order++;
163 aunits.Append( access_unit );
164 num_frames++;
165
166 num_syncword++;
167
168 if (num_syncword >= old_frames+10 )
169 {
170 mjpeg_debug ("Got %d frame headers.", num_syncword);
171 old_frames=num_syncword;
172 }
173 mjpeg_debug( "Got frame %d\n", decoding_order );
174
175 }
176 last_buffered_AU = decoding_order;
177 eoscan = bs.eos() || muxinto.AfterMaxPTS(access_unit.PTS);
178 }
179
180
181
Close()182 void LPCMStream::Close()
183 {
184 stream_length = AU_start / 8;
185 mjpeg_info ("AUDIO_STATISTICS: %02x", stream_id);
186 mjpeg_info ("Audio stream length %lld bytes.", stream_length);
187 mjpeg_info ("Frames : %8u ", num_frames);
188 }
189
190 /*************************************************************************
191 OutputAudioInfo
192 gibt gesammelte Informationen zu den Audio Access Units aus.
193
194 Prints information on audio access units
195 *************************************************************************/
196
OutputHdrInfo()197 void LPCMStream::OutputHdrInfo ()
198 {
199 mjpeg_info("LPCM AUDIO STREAM:");
200
201 mjpeg_info ("Bit rate : %8u bytes/sec (%u) bit/sec)",
202 NominalBitRate()/8, NominalBitRate() );
203 mjpeg_info ("Channels : %d", channels);
204 mjpeg_info ("Bits per sample: %d", bits_per_sample );
205 mjpeg_info ("Frequency : %d Hz", samples_per_second );
206
207 }
208
209
210 unsigned int
ReadPacketPayload(uint8_t * dst,unsigned int to_read)211 LPCMStream::ReadPacketPayload(uint8_t *dst, unsigned int to_read)
212 {
213 unsigned int header_size = LPCMStream::StreamHeaderSize();
214 bitcount_t read_start = bs.GetBytePos();
215 unsigned int bytes_read = bs.GetBytes( dst+header_size,
216 to_read-header_size );
217 bs.Flush( read_start );
218
219 clockticks decode_time;
220 bool starting_frame_found = false;
221 uint8_t starting_frame_index = 0;
222
223 int starting_frame_offset =
224 (new_au_next_sec || au_unsent > bytes_read )
225 ? 0
226 : au_unsent;
227
228 unsigned int frames = 0;
229 unsigned int bytes_muxed = bytes_read;
230
231 if (bytes_muxed == 0 || MuxCompleted() )
232 {
233 goto completion;
234 }
235
236
237 /* Work through what's left of the current frames and the
238 following frames's updating the info until we reach a point where
239 an frame had to be split between packets.
240
241 The DTS/PTS field for the packet in this case would have been
242 given the that for the first AU to start in the packet.
243
244 */
245
246 decode_time = RequiredDTS();
247 while (au_unsent < bytes_muxed)
248 {
249 assert( bytes_muxed > 1 );
250 bufmodel.Queued(au_unsent, decode_time);
251 bytes_muxed -= au_unsent;
252 if( new_au_next_sec )
253 {
254 ++frames;
255 if( ! starting_frame_found )
256 {
257 starting_frame_index = static_cast<uint8_t>(au->dorder % 20);
258 starting_frame_found = true;
259 }
260 }
261 if( !NextAU() )
262 {
263 goto completion;
264 }
265 new_au_next_sec = true;
266 decode_time = RequiredDTS();
267 };
268
269 // We've now reached a point where the current AU overran or
270 // fitted exactly. We need to distinguish the latter case so we
271 // can record whether the next packet starts with the tail end of
272 // // an already started frame or a new one. We need this info to
273 // decide what PTS/DTS info to write at the start of the next
274 // packet.
275
276 if (au_unsent > bytes_muxed)
277 {
278 if( new_au_next_sec )
279 ++frames;
280 bufmodel.Queued( bytes_muxed, decode_time);
281 au_unsent -= bytes_muxed;
282 new_au_next_sec = false;
283 }
284 else // if (au_unsent == bytes_muxed)
285 {
286 bufmodel.Queued(bytes_muxed, decode_time);
287 if( new_au_next_sec )
288 ++frames;
289 new_au_next_sec = NextAU();
290 }
291 completion:
292 // Generate the LPCM header...
293 // Note the index counts from the low byte of the offset so
294 // the smallest value is 1!
295 dst[0] = LPCM_SUB_STR_0 + stream_num;
296 dst[1] = frames;
297 dst[2] = (starting_frame_offset+4)>>8;
298 dst[3] = (starting_frame_offset+4)&0xff;
299 unsigned int bps_code;
300 switch( bits_per_sample )
301 {
302 case 16 : bps_code = 0; break;
303 case 20 : bps_code = 1; break;
304 case 24 : bps_code = 2; break;
305 default : bps_code = 3; break;
306 }
307 dst[4] = starting_frame_index;
308 unsigned int bsf_code = (samples_per_second == 48000) ? 0 : 1;
309 unsigned int channels_code = channels - 1;
310 dst[5] = (bps_code << 6) | (bsf_code << 4) | channels_code;
311 dst[6] = dynamic_range_code;
312 return bytes_read+header_size;
313 }
314
315
316
317 /*
318 * Local variables:
319 * c-file-style: "stroustrup"
320 * tab-width: 4
321 * indent-tabs-mode: nil
322 * End:
323 */
324