1 /*
2  *  tcextract.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 "tcinfo.h"
26 
27 #include <limits.h>
28 #include "libtc/xio.h"
29 #include "ioaux.h"
30 #include "tc.h"
31 
32 
33 #define EXE "tcextract"
34 
35 #define MAX_BUF 1024
36 
37 int verbose=TC_INFO;
38 
import_exit(int code)39 void import_exit(int code)
40 {
41   if(verbose & TC_DEBUG)
42     tc_log_msg(EXE, "(pid=%d) exit (code %d)", (int) getpid(), code);
43   exit(code);
44 }
45 
46 /* ------------------------------------------------------------
47  *
48  * print a usage/version message
49  *
50  * ------------------------------------------------------------*/
51 
version(void)52 void version(void)
53 {
54     /* print id string to stderr */
55     fprintf(stderr, "%s (%s v%s) (C) 2001-2003 Thomas Oestreich"
56                                    " 2003-2010 Transcode Team\n",
57                     EXE, PACKAGE, VERSION);
58 }
59 
usage(int status)60 static void usage(int status)
61 {
62   version();
63 
64   fprintf(stderr,"\nUsage: %s [options]\n", EXE);
65   fprintf(stderr,"    -i name           input file name [stdin]\n");
66   fprintf(stderr,"    -t magic          file type [autodetect]\n");
67   fprintf(stderr,"    -a track          track number [0]\n");
68   fprintf(stderr,"    -x codec          source codec\n");
69   fprintf(stderr,"    -d mode           verbosity mode\n");
70   fprintf(stderr,"    -C s-e            process only (video frame/audio byte) range [all]\n");
71   fprintf(stderr,"    -f seekfile       seek/index file [off]\n");
72   fprintf(stderr,"    -v                print version\n");
73 
74   exit(status);
75 
76 }
77 
78 
79 /* ------------------------------------------------------------
80  *
81  * universal extract thread frontend
82  *
83  * ------------------------------------------------------------*/
84 
main(int argc,char * argv[])85 int main(int argc, char *argv[])
86 {
87 
88     info_t ipipe;
89 
90     int user=0;
91 
92     long
93 	stream_stype = TC_STYPE_UNKNOWN,
94 	stream_magic = TC_MAGIC_UNKNOWN,
95 	stream_codec = TC_CODEC_UNKNOWN;
96 
97     int ch, done=0, track=0;
98     char *magic=NULL, *codec=NULL, *name=NULL;
99 
100     //proper initialization
101     memset(&ipipe, 0, sizeof(info_t));
102     ipipe.frame_limit[0]=0;
103     ipipe.frame_limit[1]=LONG_MAX;
104 
105     libtc_init(&argc, &argv);
106 
107     while ((ch = getopt(argc, argv, "d:x:i:f:a:vt:C:?h")) != -1) {
108 
109 	switch (ch) {
110 
111 	case 'i':
112 
113 	  if(optarg[0]=='-') usage(EXIT_FAILURE);
114 	  name = optarg;
115 
116 	  break;
117 
118 	case 'd':
119 
120 	  if(optarg[0]=='-') usage(EXIT_FAILURE);
121 	  verbose = atoi(optarg);
122 
123 	  break;
124 
125 	case 'x':
126 
127 	  if(optarg[0]=='-') usage(EXIT_FAILURE);
128 	  codec = optarg;
129 	  break;
130 
131 	case 'f':
132 
133 	  if(optarg[0]=='-') usage(EXIT_FAILURE);
134 	  ipipe.nav_seek_file = optarg;
135 
136 	  break;
137 
138 	case 't':
139 
140 	  if(optarg[0]=='-') usage(EXIT_FAILURE);
141 	  magic = optarg;
142 	  user=1;
143 
144 	  break;
145 
146 	case 'a':
147 
148 	  if(optarg[0]=='-') usage(EXIT_FAILURE);
149 	  track = strtol(optarg, NULL, 0);
150 	  break;
151 
152         case 'C':
153 
154           if(optarg[0]=='-') usage(EXIT_FAILURE);
155           if (2 != sscanf(optarg,"%ld-%ld", &ipipe.frame_limit[0], &ipipe.frame_limit[1])) usage(EXIT_FAILURE);
156           if (ipipe.frame_limit[0] > ipipe.frame_limit[1])
157           {
158                 tc_log_error(EXE, "Invalid -C options");
159                 usage(EXIT_FAILURE);
160           }
161           break;
162 
163 	case 'v':
164 	  version();
165 	  exit(0);
166 	  break;
167 
168 	case 'h':
169 	  usage(EXIT_SUCCESS);
170 	default:
171 	  usage(EXIT_FAILURE);
172 	}
173     }
174 
175     ac_init(AC_ALL);
176 
177     /* ------------------------------------------------------------
178      *
179      * fill out defaults for info structure
180      *
181      * ------------------------------------------------------------*/
182 
183     // assume defaults
184     if(name==NULL) stream_stype=TC_STYPE_STDIN;
185 
186     // no autodetection yet
187     if(codec==NULL && magic==NULL) {
188       tc_log_error(EXE, "invalid codec %s", codec);
189       usage(EXIT_FAILURE);
190     }
191 
192     if(codec==NULL) codec="";
193 
194     // do not try to mess with the stream
195     if(stream_stype!=TC_STYPE_STDIN) {
196 
197       if(tc_file_check(name)) exit(1);
198 
199       if((ipipe.fd_in = xio_open(name, O_RDONLY))<0) {
200 	tc_log_perror(EXE, "file open");
201 	return(-1);
202       }
203 
204       stream_magic = fileinfo(ipipe.fd_in, 0);
205 
206       if(verbose & TC_DEBUG)
207 	tc_log_msg(EXE, "(pid=%d) %s", getpid(), filetype(stream_magic));
208 
209     } else ipipe.fd_in = STDIN_FILENO;
210 
211     if(verbose & TC_DEBUG)
212 	tc_log_msg(EXE, "(pid=%d) starting, doing %s", getpid(), codec);
213 
214     // fill out defaults for info structure
215     ipipe.fd_out = STDOUT_FILENO;
216 
217     ipipe.magic   = stream_magic;
218     ipipe.stype   = stream_stype;
219     ipipe.codec   = stream_codec;
220     ipipe.track   = track;
221     ipipe.select  = TC_VIDEO;
222 
223     ipipe.verbose = verbose;
224 
225     ipipe.name = name;
226 
227     /* ------------------------------------------------------------
228      *
229      * codec specific section
230      *
231      * note: user provided magic values overwrite autodetection!
232      *
233      * ------------------------------------------------------------*/
234 
235     if(magic==NULL) magic="";
236 
237     // OGM
238 
239     if (ipipe.magic == TC_MAGIC_OGG) {
240 
241 	// dummy for video
242 	if(strcmp(codec, "raw")==0) ipipe.codec = TC_CODEC_RGB;
243 	if((strcmp(codec, "vorbis")==0) || (strcmp(codec, "ogg")==0)) {
244 	    ipipe.codec = TC_CODEC_VORBIS;
245 	    ipipe.select = TC_AUDIO;
246 	}
247 	if(strcmp(codec, "mp3")==0) {
248 	    ipipe.codec = TC_CODEC_MP3;
249 	    ipipe.select = TC_AUDIO;
250 	}
251 	if(strcmp(codec, "pcm")==0) {
252 	    ipipe.codec = TC_CODEC_PCM;
253 	    ipipe.select = TC_AUDIO;
254 	}
255 
256 	extract_ogm(&ipipe);
257 	done = 1;
258     }
259 
260     // MPEG2
261     if(strcmp(codec,"mpeg2")==0) {
262 
263       ipipe.codec = TC_CODEC_MPEG2;
264 
265       if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
266       if(strcmp(magic, "m2v")==0) ipipe.magic = TC_MAGIC_M2V;
267       if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
268 
269       extract_mpeg2(&ipipe);
270       done = 1;
271     }
272 
273     // PCM
274     if(strcmp(codec,"pcm")==0) {
275 
276 	ipipe.codec = TC_CODEC_PCM;
277 	ipipe.select = TC_AUDIO;
278 
279 	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
280 	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
281 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
282 	if(strcmp(magic, "wav")==0) ipipe.magic = TC_MAGIC_WAV;
283 
284 	extract_pcm(&ipipe);
285 	done = 1;
286     }
287 
288     // SUBTITLE (private_stream_1)
289     if(strcmp(codec,"ps1")==0) {
290 
291 	ipipe.codec = TC_CODEC_PS1;
292 	ipipe.select = TC_AUDIO;
293 
294 	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
295 	if(strcmp(magic, "vdr")==0) ipipe.magic = TC_MAGIC_VDR;
296 
297 	extract_ac3(&ipipe);
298 	done = 1;
299     }
300 
301 
302     // DV
303     if(strcmp(codec,"dv")==0) {
304 
305 	ipipe.codec = TC_CODEC_DV;
306 
307 	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
308 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
309 
310 	extract_dv(&ipipe);
311 	done = 1;
312     }
313 
314 
315     // RGB
316     if(strcmp(codec,"rgb")==0) {
317 
318 	ipipe.codec = TC_CODEC_RGB;
319 
320 	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
321 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
322 	if(strcmp(magic, "wav")==0) ipipe.magic = TC_MAGIC_WAV;
323 
324 	extract_rgb(&ipipe);
325 	done = 1;
326     }
327 
328 
329     // DTS
330     if(strcmp(codec,"dts")==0) {
331 
332 	ipipe.codec = TC_CODEC_DTS;
333 	ipipe.select = TC_AUDIO;
334 
335 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
336 	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
337 
338 	extract_ac3(&ipipe);
339 	done = 1;
340     }
341 
342     // AC3
343     if(strcmp(codec,"ac3")==0) {
344 
345 	ipipe.codec = TC_CODEC_AC3;
346 	ipipe.select = TC_AUDIO;
347 
348 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
349 	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
350 
351 	extract_ac3(&ipipe);
352 	done = 1;
353     }
354 
355     // MP3
356     if(strcmp(codec,"mp3")==0 || strcmp(codec,"mp2")==0) {
357 
358 	ipipe.codec = TC_CODEC_MP3;
359 	ipipe.select = TC_AUDIO;
360 
361 	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
362 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
363 	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
364 
365 	extract_mp3(&ipipe);
366 	done = 1;
367     }
368 
369     // YUV420P
370     if(strcmp(codec,"yuv420p")==0) {
371 
372 	ipipe.codec = TC_CODEC_YUV420P;
373 
374 	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
375 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
376 	if(strcmp(magic, "yuv4mpeg")==0) ipipe.magic = TC_MAGIC_YUV4MPEG;
377 
378 	extract_yuv(&ipipe);
379 	done = 1;
380     }
381 
382     // YUV422P
383     if(strcmp(codec,"yuv422p")==0) {
384 
385 	ipipe.codec = TC_CODEC_YUV422P;
386 
387 	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
388 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
389 	if(strcmp(magic, "yuv4mpeg")==0) ipipe.magic = TC_MAGIC_YUV4MPEG;
390 
391 	extract_yuv(&ipipe);
392 	done = 1;
393     }
394 
395     // UYVY
396     if(strcmp(codec,"uyvy")==0) {
397 
398 	ipipe.codec = TC_CODEC_UYVY;
399 
400 	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
401 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
402 
403 	extract_yuv(&ipipe);
404 	done = 1;
405     }
406 
407 
408     // LZO
409     if(strcmp(codec,"lzo")==0) {
410 
411 	ipipe.codec = TC_CODEC_YUV420P;
412 
413 	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
414 	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
415 
416 	extract_lzo(&ipipe);
417 	done = 1;
418     }
419 
420 
421     // AVI extraction
422 
423     //need to check if there isn't a codec from the input option (if we have a file with TC_MAGIC_AVI and we specify -x pcm we have pcm and rgb output)
424     if ((strcmp(magic, "avi")==0 || ipipe.magic==TC_MAGIC_AVI)&& (codec == NULL)) {
425 
426 	ipipe.magic=TC_MAGIC_AVI;
427 	extract_avi(&ipipe);
428 	done = 1;
429     }
430 
431     if (strcmp(codec, "raw")==0 || strcmp(codec, "video")==0) {
432 	ipipe.select=TC_VIDEO-1;
433 	ipipe.magic=TC_MAGIC_AVI;
434 	extract_avi(&ipipe);
435 	done = 1;
436     }
437 
438 
439     if(!done) {
440 	tc_log_error(EXE, "(pid=%d) unable to handle codec %s", getpid(), codec);
441 	exit(1);
442     }
443 
444     if(ipipe.fd_in != STDIN_FILENO) xio_close(ipipe.fd_in);
445 
446     return(0);
447 }
448 
449 #include "libtc/static_xio.h"
450