1 /*
2  *  extract_pcm.c
3  *
4  *  Copyright (C) Thomas Oestreich - June 2001
5  *
6  *  This file is part of transcode, a video stream processing tool
7  *
8  *  transcode is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2, or (at your option)
11  *  any later version.
12  *
13  *  transcode is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with GNU Make; see the file COPYING.  If not, write to
20  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #include "transcode.h"
25 #include "libtc/libtc.h"
26 #include "tcinfo.h"
27 
28 #include <sys/types.h>
29 #include <sys/mman.h>
30 
31 #include "ioaux.h"
32 #include "avilib/wavlib.h"
33 #include "tc.h"
34 
35 #define MAX_BUF 4096
36 static char audio[MAX_BUF];
37 
38 #define BUFFER_SIZE 262144
39 static uint8_t buffer[BUFFER_SIZE];
40 static FILE *in_file, *out_file;
41 
42 static unsigned int track_code;
43 
44 
pes_lpcm_loop(void)45 static void pes_lpcm_loop (void)
46 {
47     static int mpeg1_skip_table[16] = {
48 	     1, 0xffff,      5,     10, 0xffff, 0xffff, 0xffff, 0xffff,
49 	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
50     };
51 
52     uint8_t * buf;
53     uint8_t * end;
54     uint8_t * tmp1=NULL;
55     uint8_t * tmp2=NULL;
56     int complain_loudly;
57 
58     const unsigned *extract_order = 0;
59     unsigned extract_size = 0;
60     unsigned i;
61     unsigned left_over;
62 
63 #ifdef WORDS_BIGENDIAN
64     static const unsigned lpcm_bebe16[4] = { 0,1, 2,3 };
65     static const unsigned lpcm_bebe24[12] = { 0,1,8, 2,3,9 ,4,5,10, 6,7,11 };
66 #else
67     static const unsigned lpcm_bele16[4] = { 1,0, 3,2 };
68     static const unsigned lpcm_bele24[12] = { 8,1,0, 9,3,2 ,10,5,4, 11,7,6 };
69 #endif
70 
71     complain_loudly = 1;
72     buf = buffer;
73     left_over = 0;
74 
75     do {
76       end = buf + fread (buf, 1, buffer + BUFFER_SIZE - buf, in_file);
77       buf = buffer;
78 
79       //scan buffer
80       while (buf + 4 <= end) {
81 
82 	// check for valid start code
83 	if (buf[0] || buf[1] || (buf[2] != 0x01)) {
84 	  if (complain_loudly && (verbose & TC_DEBUG)) {
85 	    tc_log_warn(__FILE__, "missing start code at %#lx",
86 			ftell (in_file) - (end - buf));
87 	    if ((buf[0] == 0) && (buf[1] == 0) && (buf[2] == 0))
88 	      tc_log_warn(__FILE__, "incorrect zero-byte padding detected - ignored");
89 	    complain_loudly = 0;
90 	  }
91 	  buf++;
92 	  continue;
93 	}// check for valid start code
94 
95 	if(verbose & TC_STATS)
96 	  tc_log_msg(__FILE__, "packet code 0x%x", buf[3]);
97 
98 	switch (buf[3]) {
99 
100 	case 0xb9:	/* program end code */
101 	  return;
102 
103 	case 0xba:	/* pack header */
104 
105 	  /* skip */
106 	  if ((buf[4] & 0xc0) == 0x40)	        /* mpeg2 */
107 	    tmp1 = buf + 14 + (buf[13] & 7);
108 	  else if ((buf[4] & 0xf0) == 0x20)	/* mpeg1 */
109 	    tmp1 = buf + 12;
110 	  else if (buf + 5 > end)
111 	    goto copy;
112 	  else {
113 	    tc_log_error(__FILE__, "weird pack header");
114 	    import_exit(1);
115 	  }
116 
117 	  if (tmp1 > end)
118 	    goto copy;
119 	  buf = tmp1;
120 	  break;
121 
122 
123 	case 0xbd:	/* private stream 1 */
124 	  tmp2 = buf + 6 + (buf[4] << 8) + buf[5];
125 	  if (tmp2 > end)
126 	    goto copy;
127 	  if ((buf[6] & 0xc0) == 0x80)	/* mpeg2 */
128 	    tmp1 = buf + 9 + buf[8];
129 	  else {	/* mpeg1 */
130 	    for (tmp1 = buf + 6; *tmp1 == 0xff; tmp1++)
131 	      if (tmp1 == buf + 6 + 16) {
132 		tc_log_warn(__FILE__, "too much stuffing");
133 		buf = tmp2;
134 		break;
135 	      }
136 	    if ((*tmp1 & 0xc0) == 0x40)
137 	      tmp1 += 2;
138 	    tmp1 += mpeg1_skip_table [*tmp1 >> 4];
139 	  }
140 
141 	  if(verbose & TC_STATS)
142 	    tc_log_msg(__FILE__, "track code 0x%x", *tmp1);
143 
144 	  if (*tmp1 == track_code) {
145 
146 	    tmp1++;
147 
148 	    /*
149 	     * Additional audio header consists of:
150 	     *   number of frames
151 	     *   offset to frame start (high byte)
152 	     *   offset to frame start (low byte)
153 	     *
154 	     * followed by LPCM header:
155 	     *   emphasis:1, mute:1, rvd:1, frame number:5
156 	     *   quantization:2, freq:2, rvd:1, channels:3
157 	     *   dynamic range control (0x80=off)
158 	     */
159 
160 	    tmp1 += 3;
161 
162 	    switch ((tmp1[1] >> 6) & 3) {
163 	    case 0: extract_size = 4;
164 #ifdef WORDS_BIGENDIAN
165 		    extract_order = lpcm_bebe16;
166 #else
167 		    extract_order = lpcm_bele16;
168 #endif
169 		    break;
170             case 2: extract_size = 12;
171 #ifdef WORDS_BIGENDIAN
172 		    extract_order = lpcm_bebe24;
173 #else
174 		    extract_order = lpcm_bele24;
175 #endif
176 		    break;
177             default: tc_log_error(__FILE__, "unsupported LPCM quantization");
178 		     import_exit (1);
179             }
180 
181 	    tmp1 += 3;
182 
183 	    if (left_over) {
184 	      while (left_over < extract_size && tmp1 != tmp2)
185 		audio[left_over++] = *tmp1++;
186 	      if (left_over == extract_size) {
187 		for (i = 0; i < extract_size; i++)
188 		  fputc (audio[extract_order[i]], out_file);
189 		left_over = 0;
190 		}
191 	    }
192 
193 	    while ((tmp2 - tmp1) >= extract_size) {
194 	      for (i = 0; i < extract_size; i++)
195 		fputc (tmp1[extract_order[i]], out_file);
196 	      tmp1 += extract_size;
197 	      }
198 
199 	    while (tmp1 != tmp2)
200 	      audio[left_over++] = *tmp1++;
201 	  }
202 
203 	  buf = tmp2;
204 	  break;
205 
206 	default:
207 	  if (buf[3] < 0xb9) {
208 	    tc_log_error(__FILE__, "looks like a video stream, not program stream");
209 	    import_exit(1);
210 	  }
211 
212 	  /* skip */
213 	  tmp1 = buf + 6 + (buf[4] << 8) + buf[5];
214 	  if (tmp1 > end)
215 	    goto copy;
216 	  buf = tmp1;
217 	  break;
218 
219 	} //start code selection
220       } //scan buffer
221 
222       if (buf < end) {
223       copy:
224 	/* we only pass here for mpeg1 ps streams */
225 	memmove (buffer, buf, end - buf);
226       }
227       buf = buffer + (end - buf);
228 
229     } while (end == buffer + BUFFER_SIZE);
230 }
231 
232 
233 extern void import_exit(int ret);
234 
235 /* ------------------------------------------------------------
236  *
237  * pcm extract thread
238  *
239  * magic: TC_MAGIC_AVI
240  *        TC_MAGIC_RAW  <-- default
241  *        TC_MAGIC_WAW
242  *        TC_MAGIC_VOB
243  *
244  * ------------------------------------------------------------*/
245 
246 
extract_pcm(info_t * ipipe)247 void extract_pcm(info_t *ipipe)
248 {
249 
250   avi_t *avifile;
251 
252   unsigned long frames, bytes, padding, n;
253 
254   int error=0;
255 
256   WAV wav = NULL;
257 
258 
259   /* ------------------------------------------------------------
260    *
261    * AVI
262    *
263    * ------------------------------------------------------------*/
264 
265   // AVI
266 
267   switch (ipipe->magic) {
268 
269   case TC_MAGIC_AVI:
270 
271     if(ipipe->stype == TC_STYPE_STDIN){
272       tc_log_error(__FILE__, "invalid magic/stype - exit");
273       error=1;
274       break;
275     }
276 
277     // scan file
278     if (ipipe->nav_seek_file) {
279       if(NULL == (avifile = AVI_open_indexfd(ipipe->fd_in,0,ipipe->nav_seek_file))) {
280 	AVI_print_error("AVI open");
281 	break;
282       }
283     } else {
284       if(NULL == (avifile = AVI_open_fd(ipipe->fd_in,1))) {
285 	AVI_print_error("AVI open");
286 	break;
287       }
288     }
289 
290     //set selected for multi-audio AVI-files
291     AVI_set_audio_track(avifile, ipipe->track);
292 
293     // get total audio size
294    bytes=ipipe->frame_limit[1] - ipipe->frame_limit[0];
295    if (ipipe->frame_limit[1] ==LONG_MAX)
296    {
297      bytes = AVI_audio_bytes(avifile);
298    }
299    AVI_set_audio_position(avifile,ipipe->frame_limit[0]);
300 
301     padding = bytes % MAX_BUF;
302     frames = bytes / MAX_BUF;
303     for (n=0; n<frames; ++n) {
304 
305       if(AVI_read_audio(avifile, audio, MAX_BUF)<0) {
306 	error=1;
307 	break;
308       }
309 
310       if(tc_pwrite(ipipe->fd_out, audio, MAX_BUF)!= MAX_BUF) {
311 	error=1;
312 	break;
313       }
314     }
315 
316     if((bytes = AVI_read_audio(avifile, audio, padding)) < padding)
317       error=1;
318 
319     if(tc_pwrite(ipipe->fd_out, audio, bytes)!= bytes) error=1;
320 
321     break;
322 
323   /* ------------------------------------------------------------
324    *
325    * WAV
326    *
327    * ------------------------------------------------------------*/
328 
329   // WAV
330 
331   case TC_MAGIC_WAV:
332 
333     wav = wav_fdopen(ipipe->fd_in, WAV_READ|WAV_PIPE, NULL);
334     if (wav == NULL) {
335       error=1;
336       break;
337     }
338 
339     do {
340       bytes = wav_read_data(wav, audio, MAX_BUF);
341       if(bytes != MAX_BUF) error=1;
342       if(tc_pwrite(ipipe->fd_out, audio, bytes)!= bytes) error=1;
343     } while(!error);
344 
345     wav_close(wav);
346 
347     break;
348 
349     /* ------------------------------------------------------------
350      *
351      * VOB
352      *
353      * ------------------------------------------------------------*/
354 
355     // VOB
356 
357   case TC_MAGIC_VOB:
358 
359       in_file = fdopen(ipipe->fd_in, "r");
360       out_file = fdopen(ipipe->fd_out, "w");
361 
362       track_code = 0xA0 + ipipe->track;
363       pes_lpcm_loop();
364 
365       fclose(in_file);
366       fclose(out_file);
367 
368     break;
369 
370 
371     /* ------------------------------------------------------------
372      *
373      * RAW
374      *
375      * ------------------------------------------------------------*/
376 
377     // RAW
378 
379   case TC_MAGIC_RAW:
380 
381   default:
382 
383       if(ipipe->magic == TC_MAGIC_UNKNOWN)
384 	  tc_log_warn(__FILE__, "no file type specified, assuming %s",
385 		      filetype(TC_MAGIC_RAW));
386 
387    	bytes=ipipe->frame_limit[1] - ipipe->frame_limit[0];
388    	//skip the first ipipe->frame_limit[0] bytes
389 	if (ipipe->frame_limit[0]!=0)
390 		if (lseek(ipipe->fd_in,ipipe->frame_limit[0],SEEK_SET) !=0)
391 		{
392 			error=1;
393 			break;
394 		}
395    	if (ipipe->frame_limit[1] ==LONG_MAX)
396    	{
397     		error=tc_preadwrite(ipipe->fd_in, ipipe->fd_out);
398 	}
399 	else
400    	{
401    		padding = bytes % MAX_BUF;
402    		frames = bytes / MAX_BUF;
403    		for (n=0; n<frames; ++n)
404   		{
405       			if(tc_pread(ipipe->fd_in, audio, MAX_BUF)!= MAX_BUF)
406       			{
407 				error=1;
408 				break;
409       			}
410 			if(tc_pwrite(ipipe->fd_out, audio, MAX_BUF)!= MAX_BUF)
411 			{
412 				error=1;
413 				break;
414       			}
415     		}
416    		if (padding !=0)
417 		{
418       			if(tc_pread(ipipe->fd_in, audio, padding)!= padding)
419       			{
420 				error=1;
421 				break;
422       			}
423 			if(tc_pwrite(ipipe->fd_out, audio, padding)!= padding)
424 			{
425 				error=1;
426 				break;
427       			}
428 		}
429 	}
430 
431       break;
432   }
433 
434   if(error) {
435     tc_log_perror(__FILE__, "error while writing data");
436   	import_exit(error);
437   }
438 }
439 
440 /*************************************************************************/
441 
442 /*
443  * Local variables:
444  *   c-file-style: "stroustrup"
445  *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
446  *   indent-tabs-mode: nil
447  * End:
448  *
449  * vim: expandtab shiftwidth=4:
450  */
451