1 /*
2  * extract_dca.c
3  * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
4  * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
5  *
6  * This file is part of libdca, a free DTS Coherent Acoustics stream decoder.
7  * See http://www.videolan.org/developers/libdca.html for updates.
8  *
9  * libdca is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * libdca is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the
21  * Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <getopt.h>
32 #ifdef HAVE_IO_H
33 #include <fcntl.h>
34 #include <io.h>
35 #endif
36 #include <inttypes.h>
37 
38 //#define trace(...) { fprintf (stderr, __VA_ARGS__); }
39 #define trace(fmt,...)
40 
41 #define BUFFER_SIZE 4096
42 static uint8_t buffer[BUFFER_SIZE];
43 static FILE * in_file;
44 static int demux_track = 0x80;
45 static int demux_pid = 0;
46 static int demux_pes = 0;
47 
print_usage(char ** argv)48 static void print_usage (char ** argv)
49 {
50     trace ( "usage: %s [-h] [-s <track>] [-t <pid>] <file>\n"
51 	     "\t-h\tdisplay help\n"
52 	     "\t-s\tset track number (0-7 or 0x80-0x87)\n"
53 	     "\t-t\tuse transport stream demultiplexer, pid 0x10-0x1ffe\n"
54 	     "\t-T\tuse transport stream PES demultiplexer\n",
55 	     argv[0]);
56 
57     exit (1);
58 }
59 
handle_args(int argc,char ** argv)60 static void handle_args (int argc, char ** argv)
61 {
62     int c;
63     char * s;
64 
65     while ((c = getopt (argc, argv, "hs:t:T")) != -1)
66 	switch (c) {
67 	case 's':
68 	    demux_track = strtol (optarg, &s, 0);
69 	    if (demux_track < 0x80)
70 		demux_track += 0x80;
71 	    if (demux_track < 0x80 || demux_track > 0x87 || *s) {
72 		trace ( "Invalid track number: %s\n", optarg);
73 		print_usage (argv);
74 	    }
75 	    break;
76 
77 	case 't':
78 	    demux_pid = strtol (optarg, &s, 0);
79 	    if (demux_pid < 0x10 || demux_pid > 0x1ffe || *s) {
80 		trace ( "Invalid pid: %s\n", optarg);
81 		print_usage (argv);
82 	    }
83 	    break;
84 
85 	case 'T':
86 	    demux_pes = 1;
87 	    break;
88 
89 	default:
90 	    print_usage (argv);
91 	}
92 
93     if (optind < argc) {
94 	in_file = fopen (argv[optind], "rb");
95 	if (!in_file) {
96 	    trace ( "%s - could not open file %s\n", strerror (errno),
97 		     argv[optind]);
98 	    exit (1);
99 	}
100     } else
101 	in_file = stdin;
102 }
103 
104 #define DEMUX_PAYLOAD_START 1
demux(uint8_t * buf,uint8_t * end,int flags)105 static int demux (uint8_t * buf, uint8_t * end, int flags)
106 {
107     static int mpeg1_skip_table[16] = {
108 	0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
109     };
110 
111     /*
112      * the demuxer keeps some state between calls:
113      * if "state" = DEMUX_HEADER, then "head_buf" contains the first
114      *     "bytes" bytes from some header.
115      * if "state" == DEMUX_DATA, then we need to copy "bytes" bytes
116      *     of ES data before the next header.
117      * if "state" == DEMUX_SKIP, then we need to skip "bytes" bytes
118      *     of data before the next header.
119      *
120      * NEEDBYTES makes sure we have the requested number of bytes for a
121      * header. If we dont, it copies what we have into head_buf and returns,
122      * so that when we come back with more data we finish decoding this header.
123      *
124      * DONEBYTES updates "buf" to point after the header we just parsed.
125      */
126 
127 #define DEMUX_HEADER 0
128 #define DEMUX_DATA 1
129 #define DEMUX_SKIP 2
130     static int state = DEMUX_SKIP;
131     static int state_bytes = 0;
132     static uint8_t head_buf[268];
133 
134     uint8_t * header;
135     int bytes;
136     int len;
137 
138 #define NEEDBYTES(x)						\
139     do {							\
140 	int missing;						\
141 								\
142 	missing = (x) - bytes;					\
143 	if (missing > 0) {					\
144 	    if (header == head_buf) {				\
145 		if (missing <= end - buf) {			\
146 		    memcpy (header + bytes, buf, missing);	\
147 		    buf += missing;				\
148 		    bytes = (x);				\
149 		} else {					\
150 		    memcpy (header + bytes, buf, end - buf);	\
151 		    state_bytes = bytes + end - buf;		\
152 		    return 0;					\
153 		}						\
154 	    } else {						\
155 		memcpy (head_buf, header, bytes);		\
156 		state = DEMUX_HEADER;				\
157 		state_bytes = bytes;				\
158 		return 0;					\
159 	    }							\
160 	}							\
161     } while (0)
162 
163 #define DONEBYTES(x)		\
164     do {			\
165 	if (header != head_buf)	\
166 	    buf = header + (x);	\
167     } while (0)
168 
169     if (flags & DEMUX_PAYLOAD_START)
170 	goto payload_start;
171     switch (state) {
172     case DEMUX_HEADER:
173 	if (state_bytes > 0) {
174 	    header = head_buf;
175 	    bytes = state_bytes;
176 	    goto continue_header;
177 	}
178 	break;
179     case DEMUX_DATA:
180 	if (demux_pid || (state_bytes > end - buf)) {
181 	    fwrite (buf, end - buf, 1, stdout);
182 	    state_bytes -= end - buf;
183 	    return 0;
184 	}
185 	fwrite (buf, state_bytes, 1, stdout);
186 	buf += state_bytes;
187 	break;
188     case DEMUX_SKIP:
189 	if (demux_pid || (state_bytes > end - buf)) {
190 	    state_bytes -= end - buf;
191 	    return 0;
192 	}
193 	buf += state_bytes;
194 	break;
195     }
196 
197     while (1) {
198 	if (demux_pid) {
199 	    state = DEMUX_SKIP;
200 	    return 0;
201 	}
202     payload_start:
203 	header = buf;
204 	bytes = end - buf;
205     continue_header:
206 	NEEDBYTES (4);
207 	if (header[0] || header[1] || (header[2] != 1)) {
208 	    if (demux_pid) {
209 		state = DEMUX_SKIP;
210 		return 0;
211 	    } else if (header != head_buf) {
212 		buf++;
213 		goto payload_start;
214 	    } else {
215 		header[0] = header[1];
216 		header[1] = header[2];
217 		header[2] = header[3];
218 		bytes = 3;
219 		goto continue_header;
220 	    }
221 	}
222 	if (demux_pid || demux_pes) {
223 	    if (header[3] != 0xbd) {
224 		trace ( "bad stream id %x\n", header[3]);
225 		exit (1);
226 	    }
227 	    NEEDBYTES (9);
228 	    if ((header[6] & 0xc0) != 0x80) {	/* not mpeg2 */
229 		trace ( "bad multiplex - not mpeg2\n");
230 		exit (1);
231 	    }
232 	    len = 9 + header[8];
233 	    NEEDBYTES (len);
234 	    DONEBYTES (len);
235 	    bytes = 6 + (header[4] << 8) + header[5] - len;
236 	    if (bytes > end - buf) {
237 		fwrite (buf, end - buf, 1, stdout);
238 		state = DEMUX_DATA;
239 		state_bytes = bytes - (end - buf);
240 		return 0;
241 	    } else if (bytes > 0) {
242 		fwrite (buf, bytes, 1, stdout);
243 		buf += bytes;
244 	    }
245 	} else switch (header[3]) {
246 	case 0xb9:	/* program end code */
247 	    /* DONEBYTES (4); */
248 	    /* break;         */
249 	    return 1;
250 	case 0xba:	/* pack header */
251 	    NEEDBYTES (5);
252 	    if ((header[4] & 0xc0) == 0x40) {	/* mpeg2 */
253 		NEEDBYTES (14);
254 		len = 14 + (header[13] & 7);
255 		NEEDBYTES (len);
256 		DONEBYTES (len);
257 		/* header points to the mpeg2 pack header */
258 	    } else if ((header[4] & 0xf0) == 0x20) {	/* mpeg1 */
259 		NEEDBYTES (12);
260 		DONEBYTES (12);
261 		/* header points to the mpeg1 pack header */
262 	    } else {
263 		trace ( "weird pack header\n");
264 		DONEBYTES (5);
265 	    }
266 	    break;
267 	case 0xbd:	/* private stream 1 */
268 	    NEEDBYTES (7);
269 	    if ((header[6] & 0xc0) == 0x80) {	/* mpeg2 */
270 		NEEDBYTES (9);
271 		len = 10 + header[8];
272 		NEEDBYTES (len);
273 		/* header points to the mpeg2 pes header */
274 	    } else {	/* mpeg1 */
275 		len = 7;
276 		while ((header-1)[len] == 0xff) {
277 		    len++;
278 		    NEEDBYTES (len);
279 		    if (len == 23) {
280 			trace ( "too much stuffing\n");
281 			break;
282 		    }
283 		}
284 		if (((header-1)[len] & 0xc0) == 0x40) {
285 		    len += 2;
286 		    NEEDBYTES (len);
287 		}
288 		len += mpeg1_skip_table[(header - 1)[len] >> 4] + 1;
289 		NEEDBYTES (len);
290 		/* header points to the mpeg1 pes header */
291 	    }
292 	    if ((header-1)[len] != demux_track) {
293 		DONEBYTES (len);
294 		bytes = 6 + (header[4] << 8) + header[5] - len;
295 		if (bytes <= 0)
296 		    continue;
297 		goto skip;
298 	    }
299 	    len += 3;
300 	    NEEDBYTES (len);
301 	    DONEBYTES (len);
302 	    bytes = 6 + (header[4] << 8) + header[5] - len;
303 	    if (bytes > end - buf) {
304 		fwrite (buf, end - buf, 1, stdout);
305 		state = DEMUX_DATA;
306 		state_bytes = bytes - (end - buf);
307 		return 0;
308 	    } else if (bytes > 0) {
309 		fwrite (buf, bytes, 1, stdout);
310 		buf += bytes;
311 	    }
312 	    break;
313 	default:
314 	    if (header[3] < 0xb9) {
315 		trace (
316 			 "looks like a video stream, not system stream\n");
317 		exit (1);
318 	    } else {
319 		NEEDBYTES (6);
320 		DONEBYTES (6);
321 		bytes = (header[4] << 8) + header[5];
322 	    skip:
323 		if (bytes > end - buf) {
324 		    state = DEMUX_SKIP;
325 		    state_bytes = bytes - (end - buf);
326 		    return 0;
327 		}
328 		buf += bytes;
329 	    }
330 	}
331     }
332 }
333 
ps_loop(void)334 static void ps_loop (void)
335 {
336     uint8_t * end;
337 
338     do {
339 	end = buffer + fread (buffer, 1, BUFFER_SIZE, in_file);
340 	if (demux (buffer, end, 0))
341 	    break;	/* hit program_end_code */
342     } while (end == buffer + BUFFER_SIZE);
343 }
344 
ts_loop(void)345 static void ts_loop (void)
346 {
347     uint8_t * buf;
348     uint8_t * nextbuf;
349     uint8_t * data;
350     uint8_t * end;
351     int pid;
352 
353     buf = buffer;
354     while (1) {
355 	end = buf + fread (buf, 1, buffer + BUFFER_SIZE - buf, in_file);
356 	buf = buffer;
357 	for (; (nextbuf = buf + 188) <= end; buf = nextbuf) {
358 	    if (*buf != 0x47) {
359 		trace ( "bad sync byte\n");
360 		nextbuf = buf + 1;
361 		continue;
362 	    }
363 	    pid = ((buf[1] << 8) + buf[2]) & 0x1fff;
364 	    if (pid != demux_pid)
365 		continue;
366 	    data = buf + 4;
367 	    if (buf[3] & 0x20) {	/* buf contains an adaptation field */
368 		data = buf + 5 + buf[4];
369 		if (data > nextbuf)
370 		    continue;
371 	    }
372 	    if (buf[3] & 0x10)
373 		demux (data, nextbuf,
374 		       (buf[1] & 0x40) ? DEMUX_PAYLOAD_START : 0);
375 	}
376 	if (end != buffer + BUFFER_SIZE)
377 	    break;
378 	memcpy (buffer, buf, end - buf);
379 	buf = buffer + (end - buf);
380     }
381 }
382 
main(int argc,char ** argv)383 int main (int argc, char ** argv)
384 {
385 #ifdef HAVE_IO_H
386     setmode (fileno (stdin), O_BINARY);
387     setmode (fileno (stdout), O_BINARY);
388 #endif
389 
390     handle_args (argc, argv);
391 
392     if (demux_pid)
393 	ts_loop ();
394     else
395 	ps_loop ();
396 
397     return 0;
398 }
399