1 /*
2  *  transcode.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 "decoder.h"
26 #include "encoder.h"
27 #include "dl_loader.h"
28 #include "framebuffer.h"
29 #include "counter.h"
30 #include "frame_threads.h"
31 #include "filter.h"
32 #include "probe.h"
33 #include "socket.h"
34 #include "split.h"
35 
36 #include "libtc/xio.h"
37 #include "libtc/libtc.h"
38 #include "libtc/cfgfile.h"
39 #include "libtc/tccodecs.h"
40 #include "libtc/ratiocodes.h"
41 
42 #include <ctype.h>
43 #include <math.h>
44 
45 #include "cmdline.h"
46 
47 
48 /* ------------------------------------------------------------
49  *
50  * default options
51  *
52  * ------------------------------------------------------------*/
53 
54 
55 int pcmswap     = TC_FALSE;
56 int rgbswap     = TC_FALSE;
57 int rescale     = TC_FALSE;
58 int im_clip     = TC_FALSE;
59 int ex_clip     = TC_FALSE;
60 int pre_im_clip = TC_FALSE;
61 int post_ex_clip= TC_FALSE;
62 int flip        = TC_FALSE;
63 int mirror      = TC_FALSE;
64 int resize1     = TC_FALSE;
65 int resize2     = TC_FALSE;
66 int decolor     = TC_FALSE;
67 int zoom        = TC_FALSE;
68 int dgamma      = TC_FALSE;
69 int keepasr     = TC_FALSE;
70 int fast_resize = TC_FALSE;
71 
72 // global information structure
73 static vob_t *vob = NULL;
74 int verbose = TC_INFO;
75 
76 //-------------------------------------------------------------
77 // core parameter
78 
79 int tc_buffer_delay_dec  = -1;
80 int tc_buffer_delay_enc  = -1;
81 int tc_cluster_mode      =  0;
82 int tc_decoder_delay     =  0;
83 int tc_progress_meter    =  -1;  // so we know whether it's set by the user
84 int tc_progress_rate     =  1;
85 int tc_accel             = AC_ALL;    //acceleration code
86 unsigned int tc_avi_limit = (unsigned int)-1;
87 pid_t tc_probe_pid       = 0;
88 int tc_niceness          = 0;
89 
90 int max_frame_buffer = TC_FRAME_BUFFER;
91 int max_frame_threads = TC_FRAME_THREADS;
92 
93 //-------------------------------------------------------------
94 
95 
96 /*************************************************************************/
97 /*********************** Exported utility routines ***********************/
98 /*************************************************************************/
99 
100 /**
101  * version:  Print a version message.  The message is only printed for the
102  * first call.
103  *
104  * Parameters:
105  *     None.
106  * Return value:
107  *     None.
108  */
109 
version(void)110 void version(void)
111 {
112     static int tcversion = 0;
113     if (tcversion++)
114         return;
115     fprintf(stderr, "%s v%s (C) 2001-2003 Thomas Oestreich,"
116                               " 2003-2010 Transcode Team\n",
117                               PACKAGE, VERSION);
118 }
119 
120 /*************************************************************************/
121 
122 /**
123  * tc_get_vob:  Return a pointer to the global vob_t data structure.
124  *
125  * Parameters:
126  *     None.
127  * Return value:
128  *     A pointer to the global vob_t data structure.
129  */
130 
tc_get_vob()131 vob_t *tc_get_vob()
132 {
133     return vob;
134 }
135 
136 /*************************************************************************/
137 
138 /**
139  * validate_source_path:  Check whether the given string represents a valid
140  * source pathname.
141  *
142  * Parameters:
143  *     path: String to check.
144  * Return value:
145  *     Nonzero if the string is a valid source pathname, else zero.
146  * Side effects:
147  *     Prints an error message using tc_error() if the string is not a
148  *     valid pathname.
149  */
150 
validate_source_path(const char * path)151 static int validate_source_path(const char *path)
152 {
153     struct stat st;
154 
155     if (!path || !*path) {
156         tc_error("No filename given");
157         return 0;
158     }
159     if (strcmp(path, "-") == 0)  // allow stdin (maybe also /dev/stdin? FIXME)
160         return 1;
161     if (*path == '!' || *path == ':')  /* from transcode.c -- why? */
162         return 1;
163     if (xio_stat(path, &st) == 0)
164         return 1;
165     tc_error("Invalid filename \"%s\": %s", path, strerror(errno));
166     return 0;
167 }
168 
169 /*************************************************************************/
170 
tc_next_video_in_file(vob_t * vob)171 int tc_next_video_in_file(vob_t *vob)
172 {
173     vob->video_in_file = tc_glob_next(vob->video_in_files);
174     if (vob->video_in_file != NULL) {
175         return TC_OK;
176     }
177     return TC_ERROR;
178 }
179 
tc_next_audio_in_file(vob_t * vob)180 int tc_next_audio_in_file(vob_t *vob)
181 {
182     vob->audio_in_file = tc_glob_next(vob->audio_in_files);
183     if (vob->audio_in_file != NULL) {
184         return TC_OK;
185     }
186     return TC_ERROR;
187 }
188 
tc_has_more_video_in_file(vob_t * vob)189 int tc_has_more_video_in_file(vob_t *vob)
190 {
191     int ret = TC_FALSE;
192 
193     if (core_mode == TC_MODE_DIRECTORY) {
194         ret = tc_glob_has_more(vob->video_in_files);
195     }
196     return ret;
197 }
198 
tc_has_more_audio_in_file(vob_t * vob)199 int tc_has_more_audio_in_file(vob_t *vob)
200 {
201     int ret = TC_FALSE;
202 
203     if (core_mode == TC_MODE_DIRECTORY) {
204         ret = tc_glob_has_more(vob->audio_in_files);
205     }
206     return ret;
207 }
208 
209 /*************************************************************************/
210 /*********************** Internal utility routines ***********************/
211 /*************************************************************************/
212 
213 /*************************************************************************/
214 /*********************** Event thread support ****************************/
215 /*************************************************************************/
216 
217 static pthread_t event_thread_id = (pthread_t)0;
218 static const char *signame = "unknown signal";
219 
tc_stop_all(void)220 static void tc_stop_all(void)
221 {
222     tc_stop();
223     tc_framebuffer_interrupt();
224 }
225 
event_handler(int sig)226 static void event_handler(int sig)
227 {
228     switch (sig) {
229       case SIGINT:
230         signame = "SIGINT";
231         break;
232       case SIGTERM:
233         signame = "SIGTERM";
234         break;
235       case SIGPIPE:
236         signame = "SIGPIPE";
237         break;
238     }
239 
240     tc_interrupt();
241     tc_framebuffer_interrupt();
242 }
243 
244 /**
245  * event_thread:  Thread that watches for certain termination signals,
246  * terminating the transcode process cleanly.
247  *
248  * Parameters:
249  *     None.
250  * Return value:
251  *     None.
252  */
253 
event_thread(void * blocked_)254 static void *event_thread(void* blocked_)
255 {
256     struct sigaction handler;
257     sigset_t *blocked = blocked_;
258 
259     /* catch everything */
260     pthread_sigmask(SIG_UNBLOCK, blocked, NULL); /* XXX */
261 
262     /* install handlers, mutually exclusive */
263     memset(&handler, 0, sizeof(struct sigaction));
264     handler.sa_flags   = 0;
265     handler.sa_mask    = *blocked;
266     handler.sa_handler = event_handler;
267 
268     sigaction(SIGINT,  &handler, NULL); // XXX
269     sigaction(SIGTERM, &handler, NULL); // XXX
270 /*  sigaction(SIGPIPE, &handler, NULL); */// XXX
271 
272     /* Loop waiting for external events */
273     for (;;) {
274         pthread_testcancel();
275 
276         tc_socket_wait();
277 
278         if (tc_interrupted()) {
279             if (verbose & TC_INFO)
280                 tc_log_info(PACKAGE, "(sighandler) %s received", signame);
281 
282             /* Kill the tcprobe process if it's running */
283             if (tc_probe_pid > 0)
284                 kill(tc_probe_pid, SIGTERM);
285         }
286         pthread_testcancel();
287     }
288     return NULL;
289 }
290 
291 /*************************************************************************/
292 
293 /**
294  * stop_event_thread:  Ensure that the event handling thread is destroyed.
295  *
296  * Parameters:
297  *     None.
298  * Return value:
299  *     None.
300  */
301 
stop_event_thread(void)302 static void stop_event_thread(void)
303 {
304     if (event_thread_id) {
305         void *thread_status = NULL;
306 
307 //        pthread_kill(event_thread_id, SIGINT);
308         pthread_cancel(event_thread_id);
309         pthread_join(event_thread_id, &thread_status);
310     }
311 }
312 
313 /*************************************************************************/
314 /*************************************************************************/
315 
316 /**
317  * load_all_filters:  Loads all filters specified by the -J option.
318  *
319  * Parameters:
320  *     filter_list: String containing filter list from -J option.
321  * Return value:
322  *     None.
323  * Side effects:
324  *     Destroys `filter_list'.
325  */
326 
load_all_filters(char * filter_list)327 static void load_all_filters(char *filter_list)
328 {
329     if (!filter_list)
330         return;
331 
332     while (*filter_list) {
333         char *s = filter_list + strcspn(filter_list, ",");
334         char *options;
335 
336         while (*s && s > filter_list && s[-1] == '\\')
337             s += 1 + strcspn(s+1, ",");
338         if (*s)
339             *s++ = 0;
340         options = strchr(filter_list, '=');
341         if (options)
342             *options++ = 0;
343         tc_filter_add(filter_list, options);
344         filter_list = s;
345     }
346 }
347 
348 /*************************************************************************/
349 
350 /**
351  * transcode_init:  initialize the transcoding engine.
352  *
353  * Parameters:
354  *      vob: Pointer to the global vob_t data structure.
355  * Return value:
356  *     0 on success, -1 on error.
357  */
358 
transcode_init(vob_t * vob,TCEncoderBuffer * tc_ringbuffer)359 static int transcode_init(vob_t *vob, TCEncoderBuffer *tc_ringbuffer)
360 {
361     /* load import modules and check capabilities */
362     if (tc_import_init(vob, im_aud_mod, im_vid_mod) < 0) {
363         tc_log_error(PACKAGE, "failed to init import modules");
364         return -1;
365     }
366 
367     /* load and initialize filters */
368     tc_filter_init();
369     load_all_filters(plugins_string);
370 
371     /* load export modules and check capabilities
372      * (only create a TCModule factory if a multiplex module was given) */
373     if (tc_export_init(tc_ringbuffer,
374                        ex_mplex_mod
375                           ? tc_new_module_factory(vob->mod_path,verbose)
376                           : NULL) != TC_OK
377     ) {
378         tc_log_error(PACKAGE, "failed to init export layer");
379         return -1;
380     }
381     if (tc_export_setup(vob, ex_aud_mod, ex_vid_mod, ex_mplex_mod) != TC_OK) {
382         tc_log_error(PACKAGE, "failed to init export modules");
383         return -1;
384     }
385     return 0;
386 }
387 
388 /**
389  * transcode_fini:  finalize (shutdown) the transcoding engine.
390  *
391  * Parameters:
392  *      vob: Pointer to the global vob_t data structure.
393  * Return value:
394  *     0 on success, -1 on error.
395  */
396 
transcode_fini(vob_t * vob)397 static int transcode_fini(vob_t *vob)
398 {
399     /* unload import modules */
400     tc_import_shutdown();
401     /* unload filters */
402     tc_filter_fini();
403     /* unload export modules */
404     tc_export_shutdown();
405 
406     return 0;
407 }
408 
409 /* -------------------------------------------------------------
410  * single file continuous or interval mode
411  * ------------------------------------------------------------*/
412 
413 /* globals: frame_a, frame_b */
transcode_mode_default(vob_t * vob)414 static int transcode_mode_default(vob_t *vob)
415 {
416     struct fc_time *tstart = NULL;
417 
418     tc_start();
419 
420     // init decoder and open the source
421     if (0 != vob->ttime->vob_offset) {
422         vob->vob_offset = vob->ttime->vob_offset;
423     }
424     if (tc_import_open(vob) < 0)
425         tc_error("failed to open input source");
426 
427     // start the AV import threads that load the frames into transcode
428     // this must be called after tc_import_open
429     tc_import_threads_create(vob);
430 
431     // init encoder
432     if (tc_encoder_init(vob) != TC_OK)
433         tc_error("failed to init encoder");
434 
435     // open output files
436     if (tc_encoder_open(vob) != TC_OK)
437         tc_error("failed to open output");
438 
439     // tell counter about all encoding ranges
440     counter_reset_ranges();
441     if (!tc_cluster_mode) {
442         int last_etf = 0;
443         for (tstart = vob->ttime; tstart; tstart = tstart->next) {
444             if (tstart->etf == TC_FRAME_LAST) {
445                 // variable length range, oh well
446                 counter_reset_ranges();
447                 break;
448             }
449             if (tstart->stf > last_etf)
450                 counter_add_range(last_etf, tstart->stf-1, 0);
451             counter_add_range(tstart->stf, tstart->etf-1, 1);
452             last_etf = tstart->etf;
453         }
454     }
455 
456     // get start interval
457     tstart = vob->ttime;
458 
459     while (tstart) {
460         // set frame range (in cluster mode these will already be set)
461         if (!tc_cluster_mode) {
462             frame_a = tstart->stf;
463             frame_b = tstart->etf;
464         }
465         // main encoding loop, returns when done with all frames
466         tc_encoder_loop(vob, frame_a, frame_b);
467 
468         // check for user cancelation request
469         if (tc_interrupted()) {
470             break;
471         }
472 
473         // next range
474         tstart = tstart->next;
475         // see if we're using vob_offset
476         if ((tstart != NULL) && (tstart->vob_offset != 0)) {
477             tc_decoder_delay = 3;
478             tc_import_threads_cancel();
479             tc_import_close();
480             tc_framebuffer_flush();
481             vob->vob_offset = tstart->vob_offset;
482             vob->sync = sync_seconds;
483             if (tc_import_open(vob) < 0)
484                 tc_error("failed to open input source");
485             tc_import_threads_create(vob);
486         }
487     }
488     tc_stop_all();
489 
490     // close output files
491     tc_encoder_close();
492     // stop encoder
493     tc_encoder_stop();
494     // cancel import threads
495     tc_import_threads_cancel();
496     // stop decoder and close the source
497     tc_import_close();
498 
499     return TC_OK;
500 }
501 
502 
503 /* ------------------------------------------------------------
504  * split output AVI file
505  * ------------------------------------------------------------*/
506 
507 /* globals: frame_a, frame_b, splitavi_frames, base */
transcode_mode_avi_split(vob_t * vob)508 static int transcode_mode_avi_split(vob_t *vob)
509 {
510     char buf[TC_BUF_MAX];
511     int fa, fb, ch1 = 0;
512 
513     tc_start();
514 
515     // init decoder and open the source
516     if (tc_import_open(vob) < 0)
517         tc_error("failed to open input source");
518 
519     // start the AV import threads that load the frames into transcode
520     tc_import_threads_create(vob);
521 
522     // encoder init
523     if (tc_encoder_init(vob) != TC_OK)
524         tc_error("failed to init encoder");
525 
526     // need to loop for ch1
527     ch1 = 0;
528 
529     do {
530         if (!strlen(base))
531             strlcpy(base, vob->video_out_file, TC_BUF_MIN);
532 
533         // create new filename
534         tc_snprintf(buf, sizeof(buf), "%s%03d.avi", base, ch1++);
535         vob->video_out_file = buf;
536         vob->audio_out_file = buf;
537 
538         // open output
539         if (tc_encoder_open(vob) != TC_OK)
540             tc_error("failed to open output");
541 
542         fa = frame_a;
543         fb = frame_a + splitavi_frames;
544 
545         tc_encoder_loop(vob, fa, ((fb > frame_b) ? frame_b : fb));
546 
547         // close output
548         tc_encoder_close();
549 
550         // restart
551         frame_a += splitavi_frames;
552         if (frame_a >= frame_b)
553             break;
554 
555         if (verbose & TC_DEBUG)
556             tc_log_msg(PACKAGE, "import status=%d", tc_import_status());
557 
558         // check for user cancelation request
559         if (tc_interrupted())
560             break;
561 
562     } while (tc_import_status());
563 
564     tc_stop_all();
565 
566     tc_encoder_stop();
567 
568     // cancel import threads
569     tc_import_threads_cancel();
570     // stop decoder and close the source
571     tc_import_close();
572 
573     return TC_OK;
574 }
575 
576 
577 /* globals: frame_a, frame_b */
transcode_mode_directory(vob_t * vob)578 static int transcode_mode_directory(vob_t *vob)
579 {
580     struct fc_time *tstart = NULL;
581 
582     tc_start();
583 
584     if (strcmp(vob->audio_in_file, vob->video_in_file) != 0)
585         tc_error("directory mode DOES NOT support separate audio files (A=%s|V=%s)",
586                  vob->audio_in_file, vob->video_in_file);
587 
588     tc_multi_import_threads_create(vob);
589 
590     if (tc_encoder_init(vob) != TC_OK)
591         tc_error("failed to init encoder");
592     if (tc_encoder_open(vob) != TC_OK)
593         tc_error("failed to open output");
594 
595     // tell counter about all encoding ranges
596     counter_reset_ranges();
597     if (!tc_cluster_mode) {
598         int last_etf = 0;
599         for (tstart = vob->ttime; tstart; tstart = tstart->next) {
600             if (tstart->etf == TC_FRAME_LAST) {
601                 // variable length range, oh well
602                 counter_reset_ranges();
603                 break;
604             }
605             if (tstart->stf > last_etf)
606                 counter_add_range(last_etf, tstart->stf-1, 0);
607             counter_add_range(tstart->stf, tstart->etf-1, 1);
608             last_etf = tstart->etf;
609         }
610     }
611 
612     // get start interval
613     for (tstart = vob->ttime;
614          tstart != NULL && !tc_interrupted();
615          tstart = tstart->next) {
616         // set frame range (in cluster mode these will already be set)
617         if (!tc_cluster_mode) {
618             frame_a = tstart->stf;
619             frame_b = tstart->etf;
620         }
621         // main encoding loop, returns when done with all frames
622         tc_encoder_loop(vob, frame_a, frame_b);
623     }
624 
625     tc_stop_all();
626 
627     tc_encoder_close();
628     tc_encoder_stop();
629     tc_multi_import_threads_cancel();
630 
631     return TC_OK;
632 }
633 
634 /* ---------------------------------------------------------------
635  * VOB PSU mode: transcode and split based on program stream units
636  * --------------------------------------------------------------*/
637 
638 /* globals: frame_a, frame_b */
transcode_mode_psu(vob_t * vob,const char * psubase)639 static int transcode_mode_psu(vob_t *vob, const char *psubase)
640 {
641     char buf[TC_BUF_MAX];
642     int fa, fb, psu_cur = vob->vob_psu_num1;
643 
644     if (tc_encoder_init(vob) != TC_OK)
645         tc_error("failed to init encoder");
646 
647     // open output
648     if (no_split) {
649         vob->video_out_file = psubase;
650         if (tc_encoder_open(vob) != TC_OK)
651             tc_error("failed to open output");
652     }
653 
654     tc_decoder_delay = 3;
655 
656     counter_on();
657 
658     for (;;) {
659         int ret;
660 
661         memset(buf, 0, sizeof buf);
662         if (!no_split) {
663             // create new filename
664             tc_snprintf(buf, sizeof(buf), psubase, psu_cur);
665             // update vob structure
666             vob->video_out_file = buf;
667 
668             if (verbose & TC_INFO)
669                 tc_log_info(PACKAGE, "using output filename %s",
670                             vob->video_out_file);
671         }
672 
673         // get seek/frame information for next PSU
674         // need to process whole PSU
675         vob->vob_chunk = 0;
676         vob->vob_chunk_max = 1;
677 
678         ret = split_stream(vob, nav_seek_file, psu_cur, &fa, &fb, 0);
679 
680         if (verbose & TC_DEBUG)
681             tc_log_msg(PACKAGE,"processing PSU %d, -L %d -c %d-%d %s (ret=%d)",
682                        psu_cur, vob->vob_offset, fa, fb, buf, ret);
683 
684         // exit condition
685         if (ret < 0 || psu_cur == vob->vob_psu_num2)
686             break;
687 
688         // do not process units with a small frame number, assume it is junk
689         if ((fb-fa) > psu_frame_threshold) {
690             tc_start();
691 
692             // start new decoding session with updated vob structure
693             // this starts the full decoder setup, including the threads
694             if (tc_import_open(vob) < 0)
695                 tc_error("failed to open input source");
696 
697             // start the AV import threads that load the frames into transcode
698             tc_import_threads_create(vob);
699 
700             // frame threads may need a reboot too.
701             tc_frame_threads_init(vob, max_frame_threads, max_frame_threads);
702 
703             // open new output file
704             if (!no_split) {
705                 if (tc_encoder_open(vob) != TC_OK)
706                     tc_error("failed to open output");
707             }
708 
709             // core
710             // we try to encode more frames and let the decoder safely
711             // drain the queue to avoid threads not stopping
712 
713             tc_encoder_loop(vob, fa, TC_FRAME_LAST);
714 
715             // close output file
716             if (!no_split) {
717                 if (tc_encoder_close() != TC_OK)
718                     tc_warn("failed to close encoder - non fatal");
719             }
720 
721             if (verbose >= TC_CLEANUP) {
722                 // for debug
723                 vframe_dump_status();
724                 aframe_dump_status();
725             }
726 
727             // cancel import threads
728             tc_import_threads_cancel();
729             // stop decoder and close the source
730             tc_import_close();
731 
732             // flush all buffers before we proceed to next PSU
733             tc_framebuffer_flush();
734 
735             vob->psu_offset += (double) (fb-fa);
736         } else {
737             if (verbose & TC_INFO)
738                 tc_log_info(PACKAGE, "skipping PSU %d with %d frame(s)",
739                             psu_cur, fb-fa);
740 
741         }
742 
743         psu_cur++;
744         if (tc_interrupted())
745             break;
746     } //next PSU
747 
748     // close output
749     if (no_split) {
750         if (tc_encoder_close() != TC_OK)
751             tc_warn("failed to close encoder - non fatal");
752     }
753 
754     tc_stop_all();
755 
756     tc_encoder_stop();
757 
758     return TC_OK;
759 }
760 
761 /* ------------------------------------------------------------
762  * DVD chapter mode
763  * ------------------------------------------------------------*/
764 
765 /* globals: frame_a, frame_b, chbase */
transcode_mode_dvd(vob_t * vob)766 static int transcode_mode_dvd(vob_t *vob)
767 {
768 #ifdef HAVE_LIBDVDREAD
769     char buf[TC_BUF_MAX];
770     int ch1, ch2;
771 
772     tc_start();
773 
774     if (tc_encoder_init(vob) != TC_OK)
775         tc_error("failed to init encoder");
776 
777     // open output
778     if (no_split) {
779         // create new filename
780         tc_snprintf(buf, sizeof(buf), "%s.avi", chbase);
781         // update vob structure
782         vob->video_out_file = buf;
783         vob->audio_out_file = buf;
784 
785         if (tc_encoder_open(vob) != TC_OK)
786             tc_error("failed to open output");
787     }
788 
789     // 1 sec delay after decoder closing
790     tc_decoder_delay = 1;
791 
792     // loop each chapter
793     ch1 = vob->dvd_chapter1;
794     ch2 = vob->dvd_chapter2;
795 
796     //ch = -1 is allowed but makes no sense
797     if (ch1 < 0)
798         ch1 = 1;
799 
800     for (;;) {
801         vob->dvd_chapter1 = ch1;
802         vob->dvd_chapter2 =  -1;
803 
804         if (!no_split) {
805             // create new filename
806             tc_snprintf(buf, sizeof(buf), "%s-ch%02d.avi", chbase, ch1);
807             // update vob structure
808             vob->video_out_file = buf;
809             vob->audio_out_file = buf;
810         }
811 
812         // start decoding with updated vob structure
813         if (tc_import_open(vob) < 0)
814             tc_error("failed to open input source");
815 
816         // start the AV import threads that load the frames into transcode
817         tc_import_threads_create(vob);
818 
819         if (verbose & TC_DEBUG)
820             tc_log_msg(PACKAGE, "%d chapters for title %d detected",
821                        vob->dvd_max_chapters, vob->dvd_title);
822 
823         // encode
824         if (!no_split) {
825             if (tc_encoder_open(vob) != TC_OK)
826                 tc_error("failed to init encoder");
827         }
828 
829         // main encoding loop, selecting an interval won't work
830         tc_encoder_loop(vob, frame_a, frame_b);
831 
832         if (!no_split) {
833             if (tc_encoder_close() != TC_OK)
834                 tc_warn("failed to close encoder - non fatal");
835         }
836 
837         // cancel import threads
838         tc_import_threads_cancel();
839         // stop decoder and close the source
840         tc_import_close();
841 
842         // flush all buffers before we proceed
843         tc_framebuffer_flush();
844 
845         // exit,  i) if import module could not determine max_chapters
846         //       ii) all chapters are done
847         //      iii) someone hit ^C
848 
849         if (vob->dvd_max_chapters ==- 1
850          || ch1 == vob->dvd_max_chapters || ch1 == ch2
851          || tc_interrupted())
852             break;
853         ch1++;
854     }
855 
856     if (no_split) {
857         if (tc_encoder_close() != TC_OK)
858             tc_warn("failed to close encoder - non fatal");
859     }
860 
861     tc_stop_all();
862     tc_encoder_stop();
863 #endif
864 
865     return TC_OK;
866 }
867 
868 /*************************************************************************/
869 
870 /**
871  * new_vob:  Create a new vob_t structure and fill it with appropriate
872  * values.
873  *
874  * Parameters:
875  *     None.
876  * Return value:
877  *     A pointer to the newly-created vob_t structure, or NULL on error.
878  * Notes:
879  *     On error, errno is valid.
880  */
881 
new_vob(void)882 static vob_t *new_vob(void)
883 {
884     vob_t *vob = tc_malloc(sizeof(vob_t));
885     if (!vob)
886         return NULL;
887 
888     vob->divxbitrate         = VBITRATE;
889     vob->video_max_bitrate   = 0;           /* 0 = set by encoder */
890     vob->divxkeyframes       = VKEYFRAMES;
891     vob->divxquality         = VQUALITY;
892     vob->divxmultipass       = VMULTIPASS;
893     vob->divxcrispness       = VCRISPNESS;
894     vob->m2v_requant         = M2V_REQUANT_FACTOR;
895 
896     vob->min_quantizer       = VMINQUANTIZER;
897     vob->max_quantizer       = VMAXQUANTIZER;
898 
899     vob->rc_period           = RC_PERIOD;
900     vob->rc_reaction_period  = RC_REACTION_PERIOD;
901     vob->rc_reaction_ratio   = RC_REACTION_RATIO;
902 
903     vob->divx5_vbv_prof      = DIVX5_VBV_PROFILE;
904     vob->divx5_vbv_bitrate   = DIVX5_VBV_BITRATE;
905     vob->divx5_vbv_size      = DIVX5_VBV_SIZE;
906     vob->divx5_vbv_occupancy = DIVX5_VBV_OCCUPANCY;
907 
908     vob->mp3bitrate          = ABITRATE;
909     vob->mp3frequency        = 0;
910     vob->mp3quality          = AQUALITY;
911     vob->mp3mode             = AMODE;
912     vob->a_rate              = RATE;
913     vob->a_stream_bitrate    = 0;
914     vob->a_bits              = BITS;
915     vob->a_chan              = CHANNELS;
916     vob->a_padrate           = 0;
917 
918     vob->dm_bits             = 0;
919     vob->dm_chan             = 0;
920 
921     vob->im_a_size           = SIZE_PCM_FRAME;
922     vob->im_v_width          = PAL_W;
923     vob->im_v_height         = PAL_H;
924     vob->im_v_size           = SIZE_RGB_FRAME;
925     vob->ex_a_size           = SIZE_PCM_FRAME;
926     vob->ex_v_width          = PAL_W;
927     vob->ex_v_height         = PAL_H;
928     vob->ex_v_size           = SIZE_RGB_FRAME;
929     vob->a_track             = 0;
930     vob->v_track             = 0;
931     vob->volume              = 0;
932     vob->ac3_gain[0]         = 1.0;
933     vob->ac3_gain[1]         = 1.0;
934     vob->ac3_gain[2]         = 1.0;
935     vob->audio_out_file      = NULL;
936     vob->video_out_file      = NULL;
937     vob->avifile_in          = NULL;
938     vob->avifile_out         = NULL;
939     vob->avi_comment_fd      = -1;
940     vob->nav_seek_file       = NULL;
941     vob->audio_file_flag     = 0;
942     vob->audio_in_file       = NULL;
943     vob->video_in_file       = NULL;
944     vob->clip_count          = 0;
945     vob->ex_a_codec          = CODEC_MP3;  //or fall back to module default
946     vob->ex_v_codec          = CODEC_NULL; //determined by export module type
947     vob->ex_v_fcc            = NULL;
948     vob->ex_a_fcc            = NULL;
949     vob->ex_profile_name     = NULL;
950     vob->fps                 = PAL_FPS;
951     vob->ex_fps              = 0;
952     vob->im_frc              = 0;
953     vob->ex_frc              = 0;
954     vob->pulldown            = 0;
955     vob->im_clip_top         = 0;
956     vob->im_clip_bottom      = 0;
957     vob->im_clip_left        = 0;
958     vob->im_clip_right       = 0;
959     vob->ex_clip_top         = 0;
960     vob->ex_clip_bottom      = 0;
961     vob->ex_clip_left        = 0;
962     vob->ex_clip_right       = 0;
963     vob->resize1_mult        = 32;
964     vob->vert_resize1        = 0;
965     vob->hori_resize1        = 0;
966     vob->resize2_mult        = 32;
967     vob->vert_resize2        = 0;
968     vob->hori_resize2        = 0;
969     vob->sync                = 0;
970     vob->sync_ms             = 0;
971     vob->sync_samples        = 0;
972     vob->dvd_title           = 1;
973     vob->dvd_chapter1        = 1;
974     vob->dvd_chapter2        = -1;
975     vob->dvd_max_chapters    = -1;
976     vob->dvd_angle           = 1;
977     vob->pass_flag           = 0;
978     vob->verbose             = TC_QUIET;
979     vob->antialias           = 0;
980     vob->deinterlace         = 0;
981     vob->decolor             = 0;
982     vob->im_a_codec          = CODEC_PCM;
983     vob->im_v_codec          = CODEC_YUV;
984     vob->mod_path            = MOD_PATH;
985     vob->audiologfile        = NULL;
986     vob->divxlogfile         = NULL;
987     vob->ps_unit             = 0;
988     vob->ps_seq1             = 0;
989     vob->ps_seq2             = TC_FRAME_LAST;
990     vob->a_leap_frame        = TC_LEAP_FRAME;
991     vob->a_leap_bytes        = 0;
992     vob->demuxer             = -1;
993     vob->a_codec_flag        = CODEC_AC3;
994     vob->gamma               = 0.0;
995     vob->encoder_flush       = TC_TRUE;
996     vob->has_video           = 1;
997     vob->has_audio           = 1;
998     vob->has_audio_track     = 1;
999     vob->lang_code           = 0;
1000     vob->v_format_flag       = 0;
1001     vob->v_codec_flag        = 0;
1002     vob->a_format_flag       = 0;
1003     vob->im_asr              = 0;
1004     vob->im_par              = 0;
1005     vob->im_par_width        = 0;
1006     vob->im_par_height       = 0;
1007     vob->ex_asr              = -1;
1008     vob->ex_par              = 0;
1009     vob->ex_par_width        = 0;
1010     vob->ex_par_height       = 0;
1011     vob->quality             = VQUALITY;
1012     vob->amod_probed         = "null";
1013     vob->vmod_probed         = "null";
1014     vob->amod_probed_xml     = NULL;
1015     vob->vmod_probed_xml     = NULL;
1016     vob->a_vbr               = 0;
1017     vob->pts_start           = 0.0f;
1018     vob->vob_offset          = 0;
1019     vob->vob_chunk           = 0;
1020     vob->vob_chunk_max       = 0;
1021     vob->vob_chunk_num1      = 0;
1022     vob->vob_chunk_num2      = 0;
1023     vob->vob_psu_num1        = 0;
1024     vob->vob_psu_num2        = INT_MAX;
1025     vob->vob_info_file       = NULL;
1026     vob->vob_percentage      = 0;
1027     vob->im_a_string         = NULL;
1028     vob->im_v_string         = NULL;
1029     vob->ex_a_string         = NULL;
1030     vob->ex_v_string         = NULL;
1031     vob->ex_m_string         = NULL;
1032 
1033     vob->reduce_h            = 1;
1034     vob->reduce_w            = 1;
1035 
1036     //-Z
1037     vob->zoom_width          = 0;
1038     vob->zoom_height         = 0;
1039     vob->zoom_filter         = TCV_ZOOM_LANCZOS3;
1040     vob->zoom_interlaced     = 0;
1041 
1042     vob->frame_interval      = 1; // write every frame
1043 
1044     //anti-alias
1045     vob->aa_weight           = TC_DEFAULT_AAWEIGHT;
1046     vob->aa_bias             = TC_DEFAULT_AABIAS;
1047 
1048     vob->a52_mode            = 0;
1049     vob->encode_fields       = TC_ENCODE_FIELDS_PROGRESSIVE;
1050 
1051     vob->ttime               = NULL;
1052 
1053     vob->psu_offset          = 0.0f;
1054     vob->bitreservoir        = TC_TRUE;
1055     vob->lame_preset         = NULL;
1056 
1057     vob->ts_pid1             = 0x0;
1058     vob->ts_pid2             = 0x0;
1059 
1060     vob->dv_yuy2_mode        = 0;
1061     vob->hard_fps_flag       = 0;
1062     vob->mpeg_profile        = PROF_NONE;
1063 
1064     vob->attributes          = 0;
1065     vob->export_attributes   = TC_EXPORT_ATTRIBUTE_NONE;
1066 
1067     return vob;
1068 }
1069 
1070 /*************************************************************************/
1071 
1072 /*
1073  * parse_navigation_file:
1074  *      parse navigation data file and setup vob data fields accordingly.
1075  *      This function handle both aviindex and tcdemux -W generated files.
1076  *
1077  * Parameters:
1078  *                vob: Pointer to the global vob_t data structure.
1079  *      nav_seek_file: Path of navigation file.
1080  * Return Value:
1081  *      None
1082  */
parse_navigation_file(vob_t * vob,const char * nav_seek_file)1083 static void parse_navigation_file(vob_t *vob, const char *nav_seek_file)
1084 {
1085     if (nav_seek_file) {
1086         FILE *fp = NULL;
1087         struct fc_time *tmptime = NULL;
1088         char buf[TC_BUF_MIN];
1089         int line_count = 0;
1090         int flag = 0;
1091         int is_aviindex = 0;
1092 
1093         if (vob->vob_offset) {
1094             tc_warn("-L and --nav_seek are incompatible.");
1095         }
1096 
1097         fp = fopen(nav_seek_file, "r");
1098         if (NULL == fp) {
1099             tc_error("unable to open: %s", nav_seek_file);
1100         }
1101 
1102         tmptime = vob->ttime;
1103         line_count = 0;
1104 
1105         // check if this is an AVIIDX1 file
1106         if (fgets(buf, sizeof(buf), fp)) {
1107             if (strncasecmp(buf, "AVIIDX1", 7) == 0)
1108                 is_aviindex=1;
1109             fseek(fp, 0, SEEK_SET);
1110         } else {
1111             tc_error("An error happend while reading the nav_seek file");
1112         }
1113 
1114         if (!is_aviindex) {
1115             while (tmptime){
1116                 flag = 0;
1117                 for (; fgets(buf, sizeof(buf), fp); line_count++) {
1118                     int L, new_frame_a;
1119 
1120                     if (2 == sscanf(buf, "%*d %*d %*d %*d %d %d ", &L, &new_frame_a)) {
1121                         if (line_count == tmptime->stf) {
1122                             int len = tmptime->etf - tmptime->stf;
1123                             tmptime->stf = frame_a = new_frame_a;
1124                             tmptime->etf = frame_b = new_frame_a + len;
1125                             tmptime->vob_offset = L;
1126                             flag = 1;
1127                             line_count++;
1128                             break;
1129                         }
1130                     }
1131                 }
1132                 tmptime = tmptime->next;
1133             }
1134         } else { // is_aviindex==1
1135             fgets(buf, sizeof(buf), fp); // magic
1136             fgets(buf, sizeof(buf), fp); // comment
1137 
1138             while (tmptime) {
1139                 int new_frame_a, type, key;
1140                 long chunk, chunkptype, last_keyframe = 0;
1141                 long long pos, len;
1142                 char tag[4];
1143                 double ms = 0.0;
1144                 flag = 0;
1145 
1146                 for (; fgets(buf, sizeof(buf), fp); line_count++) {
1147                     // TAG TYPE CHUNK CHUNK/TYPE POS LEN KEY MS
1148                     if (sscanf(buf, "%s %d %ld %ld %lld %lld %d %lf",
1149                                tag, &type, &chunk, &chunkptype, &pos, &len, &key, &ms)) {
1150                         if (type != 1)
1151                             continue;
1152                         if (key)
1153                             last_keyframe = chunkptype;
1154                         if (chunkptype == tmptime->stf) {
1155                             int lenf = tmptime->etf - tmptime->stf;
1156                             new_frame_a = chunkptype - last_keyframe;
1157 
1158                             // If we are doing pass-through, we cannot skip frames, but only start
1159                             // passthrough on a keyframe boundary. At least, we respect the
1160                             // last frame the user whishes.
1161                             if (vob->pass_flag & TC_VIDEO) {
1162                                 new_frame_a = 0;
1163                                 lenf += (chunkptype - last_keyframe);
1164                             }
1165 
1166                             tmptime->stf = frame_a = new_frame_a;
1167                             tmptime->etf = frame_b = new_frame_a + lenf;
1168                             tmptime->vob_offset = last_keyframe;
1169                             flag = 1;
1170                             line_count++;
1171                             break;
1172                         }
1173                     }
1174                 }
1175                 tmptime = tmptime->next;
1176             }
1177         }
1178         fclose(fp);
1179 
1180         if (!flag) {
1181             //frame not found
1182             tc_warn("%s: frame %d out of range (%d frames found)",
1183                     nav_seek_file, frame_a, line_count);
1184             tc_error("invalid option parameter for -c / --nav_seek");
1185         }
1186     }
1187 }
1188 
1189 /*************************************************************************/
1190 
setup_input_sources(vob_t * vob)1191 static void setup_input_sources(vob_t *vob)
1192 {
1193     if (vob->video_in_file == NULL && vob->audio_in_file == NULL)
1194         tc_error("no input sources avalaible");
1195     if (vob->audio_in_file == NULL)
1196         vob->audio_in_file = vob->video_in_file;
1197 
1198     /*
1199      * let's try happily both sources independently.
1200      * At least one will succeed, if we're here.
1201      */
1202     vob->video_in_files = tc_glob_open(vob->video_in_file, 0);
1203     if (vob->video_in_files) {
1204         /* we always have at least one source */
1205         tc_next_video_in_file(vob);
1206     }
1207     if (!validate_source_path(vob->video_in_file)) {
1208         tc_error("invalid input video file: %s", vob->video_in_file);
1209     }
1210 
1211     vob->audio_in_files = tc_glob_open(vob->audio_in_file, 0);
1212     if (vob->audio_in_files) {
1213         /* we always have at least one source */
1214         tc_next_audio_in_file(vob);
1215     }
1216     if (!validate_source_path(vob->audio_in_file)) {
1217         tc_error("invalid input audio file: %s", vob->audio_in_file);
1218     }
1219 }
1220 
teardown_input_sources(vob_t * vob)1221 static void teardown_input_sources(vob_t *vob)
1222 {
1223     if (vob->video_in_files) {
1224         tc_glob_close(vob->video_in_files);
1225         vob->video_in_files = NULL;
1226     }
1227     if (vob->audio_in_files) {
1228         tc_glob_close(vob->audio_in_files);
1229         vob->audio_in_files = NULL;
1230     }
1231 }
1232 
1233 /*************************************************************************/
1234 
1235 /* support macros */
1236 
1237 #define CLIP_CHECK(MODE, NAME, OPTION) do { \
1238     /* force to even for YUV mode */ \
1239     if (vob->im_v_codec == CODEC_YUV || vob->im_v_codec == CODEC_YUV422) { \
1240         if (vob->MODE ## _left % 2 != 0) { \
1241             tc_warn("left/right %s must be even in YUV/YUV422 mode", NAME); \
1242             vob->MODE ## _left--; \
1243         } \
1244         if (vob->MODE ## _right % 2 != 0) { \
1245             tc_warn("left/right %s must be even in YUV/YUV422 mode", NAME); \
1246             vob->MODE ## _right--; \
1247         } \
1248         if (vob->im_v_codec == CODEC_YUV && vob->MODE ## _top % 2 != 0) { \
1249             tc_warn("top/bottom %s must be even in YUV mode", NAME); \
1250             vob->MODE ## _top--; \
1251         } \
1252         if (vob->im_v_codec == CODEC_YUV && vob->MODE ## _bottom % 2 != 0) { \
1253             tc_warn("top/bottom %s must be even in YUV mode", NAME); \
1254             vob->MODE ## _bottom--; \
1255         } \
1256     } \
1257     /* check against import parameter, this is pre processing! */ \
1258     if (vob->ex_v_height - vob->MODE ## _top - vob->MODE ## _bottom <= 0 \
1259      || vob->ex_v_height - vob->MODE ## _top - vob->MODE ## _bottom > TC_MAX_V_FRAME_HEIGHT) \
1260         tc_error("invalid top/bottom clip parameter for option %s", OPTION); \
1261     \
1262     if (vob->ex_v_width - vob->MODE ## _left - vob->MODE ## _right <= 0 \
1263      || vob->ex_v_width - vob->MODE ## _left - vob->MODE ## _right > TC_MAX_V_FRAME_WIDTH) \
1264         tc_error("invalid left/right clip parameter for option %s", OPTION); \
1265     \
1266     vob->ex_v_height -= (vob->MODE ## _top + vob->MODE ## _bottom); \
1267     vob->ex_v_width  -= (vob->MODE ## _left + vob->MODE ## _right); \
1268 } while (0)
1269 
1270 
1271 
1272 #define SHUTDOWN_MARK(STAGE) do { \
1273     if (verbose & TC_DEBUG) { \
1274         fprintf(stderr, " %s |", (STAGE)); \
1275         fflush(stderr); \
1276     } \
1277 } while (0)
1278 
1279 
1280 /*************************************************************************/
1281 
1282 /* common support data */
1283 
1284 typedef struct ratio_t {
1285     int t, b;
1286 } ratio_t;
1287 
1288 static const ratio_t asrs[] = {
1289     {   1,   1 }, {   1,   1 }, {   4,   3 }, {  16,   9 },
1290     { 221, 100 }, { 250, 100 }, { 125, 100 }
1291 };
1292 
1293 static const char *demuxer_desc[] = {
1294     "sync AV at PTS start - demuxer disabled",
1295     "sync AV at initial MPEG sequence",
1296     "initial MPEG sequence / enforce frame rate",
1297     "sync AV at initial PTS",
1298     "initial PTS / enforce frame rate",
1299 };
1300 
1301 static const char *deinterlace_desc[] = {
1302     "disabled", /* never used */
1303     "interpolate scanlines (fast)",
1304     "handled by encoder (if available)",
1305     "zoom to full frame (slow)",
1306     "drop field / half height (fast)",
1307     "interpolate scanlines / blend frames",
1308 
1309 };
1310 
1311  static const char *antialias_desc[] = {
1312     "disabled", /* never used */
1313     "de-interlace effects only",
1314     "resize effects only",
1315     "process full frame (slow)"
1316 };
1317 
1318 
1319 /**
1320  * main:  transcode main routine.  Performs initialization, parses command
1321  * line options, and calls the transcoding routines.
1322  *
1323  * Parameters:
1324  *     argc: Command line argument count.
1325  *     argv: Command line argument vector.
1326  * Return value:
1327  *     Zero on success, nonzero on error (exit code).
1328  */
1329 
main(int argc,char * argv[])1330 int main(int argc, char *argv[])
1331 {
1332     sigset_t sigs_to_block;
1333 
1334     const char *psubase = NULL;
1335 
1336     double fch, asr;
1337     int leap_bytes1, leap_bytes2;
1338     int max_frame_buffer = TC_FRAME_BUFFER;
1339 
1340     struct fc_time *tstart = NULL;
1341 
1342     TCFrameSpecs specs;
1343 
1344     //main thread id
1345     writepid = getpid();
1346 
1347     /* ------------------------------------------------------------
1348      *
1349      *  (I) set transcode defaults:
1350      *
1351      * ------------------------------------------------------------ */
1352 
1353     // create global vob structure
1354     vob = new_vob();
1355     if (!vob) {
1356         tc_error("data initialization failed");
1357     }
1358 
1359     // prepare for signal catching
1360     sigemptyset(&sigs_to_block);
1361     sigaddset(&sigs_to_block, SIGINT);
1362     sigaddset(&sigs_to_block, SIGTERM);
1363     // enabling this breaks the import_vob module.
1364     //sigaddset(&sigs_to_block, SIGPIPE);
1365     pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
1366 
1367     // start of the signal handler thread is delayed later
1368 
1369     // close all threads at exit
1370     atexit(stop_event_thread);
1371 
1372     /* ------------------------------------------------------------
1373      *
1374      * (II) parse command line
1375      *
1376      * ------------------------------------------------------------ */
1377 
1378     /*
1379      * A *FEW* special options that deserve separate treatment.
1380      * PLEASE keep VERY LOW the number of this special cases.
1381      */
1382     libtc_init(&argc, &argv);
1383 
1384     if (!parse_cmdline(argc, argv, vob))
1385         exit(EXIT_FAILURE);
1386 
1387     setup_input_sources(vob);
1388 
1389     if (tc_progress_meter < 0) {
1390         // if we have verbosity disabled, default to no progress meter.
1391         if (verbose) {
1392             tc_progress_meter = 1;
1393         } else {
1394             tc_progress_meter = 0;
1395         }
1396     }
1397 
1398     if (psu_mode) {
1399         if (vob->video_out_file == NULL)
1400             tc_error("please specify output file name for psu mode");
1401         if (!strchr(vob->video_out_file, '%') && !no_split) {
1402             char *pc = tc_malloc(PATH_MAX);
1403             char *suffix = strrchr(vob->video_out_file, '.');
1404             if (suffix) {
1405                 *suffix = '\0';
1406             } else {
1407                 suffix = "";
1408             }
1409             tc_snprintf(pc, PATH_MAX, "%s-psu%%02d%s",
1410                         vob->video_out_file, suffix);
1411             psubase = pc;
1412         } else {
1413             psubase = vob->video_out_file;
1414         }
1415     }
1416 
1417     // user doesn't want to start at all;-(
1418     if (tc_interrupted())
1419         goto summary;
1420 
1421     // display program version
1422     if (verbose)
1423         version();
1424 
1425     if (tc_niceness) {
1426         if (nice(tc_niceness) < 0) {
1427             tc_warn("setting nice to %d failed", tc_niceness);
1428         }
1429     }
1430 
1431     /* ------------------------------------------------------------
1432      *
1433      * (III) auto probe properties of input stream
1434      *
1435      * ------------------------------------------------------------ */
1436 
1437     if (auto_probe) {
1438         // interface to "tcprobe"
1439         int result = probe_source(vob->video_in_file, vob->audio_in_file, seek_range,
1440                                   preset_flag, vob);
1441         if (verbose) {
1442             tc_log_info(PACKAGE, "V: %-16s | %s (%s)", "auto-probing",
1443                         (vob->video_in_file != NULL) ?vob->video_in_file :"N/A",
1444                         result ? "OK" : "FAILED");
1445             tc_log_info(PACKAGE, "V: %-16s | %s in %s (module=%s)",
1446                         "import format",
1447                         tc_codec_to_comment(vob->v_codec_flag),
1448                         mformat2str(vob->v_format_flag),
1449                         no_vin_codec == 0 ? im_vid_mod : vob->vmod_probed);
1450             tc_log_info(PACKAGE, "A: %-16s | %s (%s)", "auto-probing",
1451                         (vob->audio_in_file != NULL) ?vob->audio_in_file :"N/A",
1452                         result ? "OK" : "FAILED");
1453             tc_log_info(PACKAGE, "A: %-16s | %s in %s (module=%s)",
1454                         "import format",
1455                         tc_codec_to_comment(vob->a_codec_flag),
1456                         mformat2str(vob->a_format_flag),
1457                         no_ain_codec==0 ? im_aud_mod : vob->amod_probed);
1458         }
1459     }
1460 
1461     if (vob->vmod_probed_xml && strstr(vob->vmod_probed_xml, "xml") != NULL
1462      && vob->video_in_file) {
1463         if (!probe_source_xml(vob, PROBE_XML_VIDEO))
1464             tc_error("failed to probe video XML source");
1465     }
1466     if (vob->amod_probed_xml && strstr(vob->amod_probed_xml, "xml") != NULL
1467      && vob->audio_in_file) {
1468         if (!probe_source_xml(vob, PROBE_XML_AUDIO))
1469             tc_error("failed to probe audio XML source");
1470     }
1471 
1472     /* ------------------------------------------------------------
1473      *
1474      * (IV) autosplit stream for cluster processing
1475      *
1476      * currently, only VOB streams are supported
1477      *
1478      * ------------------------------------------------------------*/
1479 
1480     // set up ttime from -c or default
1481     if (fc_ttime_string) {
1482         // FIXME: should be in -c handler, but we need to know vob->fps first
1483         free_fc_time(vob->ttime);
1484         if (parse_fc_time_string(fc_ttime_string, vob->fps, ",",
1485                                  (verbose>1 ? 1 : 0), &vob->ttime) == -1)
1486             tc_error("error parsing time specifications");
1487     } else {
1488         vob->ttime = new_fc_time();
1489         vob->ttime->fps = vob->fps;
1490         vob->ttime->stf = TC_FRAME_FIRST;
1491         vob->ttime->etf = TC_FRAME_LAST;
1492         vob->ttime->next = NULL;
1493     }
1494     frame_a = vob->ttime->stf;
1495     frame_b = vob->ttime->etf;
1496     vob->ttime->vob_offset = 0;
1497     tstart = vob->ttime;
1498     counter_on(); //activate
1499 
1500     // determine -S,-c,-L option parameter for distributed processing
1501     parse_navigation_file(vob, nav_seek_file);
1502 
1503     if (vob->vob_chunk_max) {
1504         int this_unit = -1;
1505 
1506         // overwrite tcprobe's unit preset:
1507         if (preset_flag & TC_PROBE_NO_SEEK)
1508             this_unit = vob->ps_unit;
1509 
1510         if (split_stream(vob, vob->vob_info_file, this_unit, &frame_a, &frame_b, 1) < 0)
1511             tc_error("cluster mode option -W error");
1512     }
1513 
1514     /* ------------------------------------------------------------
1515      *
1516      * some sanity checks for command line parameters
1517      *
1518      * ------------------------------------------------------------*/
1519 
1520     // -M
1521     if (vob->demuxer == -1) {
1522         vob->demuxer = 1;
1523     }
1524     if (verbose & TC_INFO) {
1525         tc_log_info(PACKAGE, "V: %-16s | (%i) %s", "AV demux/sync",
1526                     vob->demuxer, demuxer_desc[vob->demuxer]);
1527     }
1528 
1529     // -P
1530     if (vob->pass_flag & TC_VIDEO) {
1531         vob->im_v_codec = (vob->im_v_codec == CODEC_YUV) ?CODEC_RAW_YUV :CODEC_RAW;
1532         vob->ex_v_codec = CODEC_RAW;
1533 
1534         // suggestion:
1535         if (no_v_out_codec)
1536             ex_vid_mod = "raw";
1537         no_v_out_codec = 0;
1538 
1539         if (no_a_out_codec)
1540             ex_aud_mod = "raw";
1541         no_a_out_codec = 0;
1542 
1543         if (verbose & TC_INFO)
1544             tc_log_info(PACKAGE, "V: %-16s | yes", "pass-through");
1545     }
1546 
1547     // -x
1548     if (no_vin_codec && vob->video_in_file != NULL && vob->vmod_probed == NULL)
1549         tc_error("module autoprobe failed, no option -x found");
1550 
1551 
1552     //overwrite results of autoprobing if modules are provided
1553     if (no_vin_codec && vob->vmod_probed!=NULL) {
1554         im_vid_mod = (char *)vob->vmod_probed_xml;
1555         //need to load the correct module if the input file type is xml
1556     }
1557 
1558     if (no_ain_codec && vob->amod_probed!=NULL) {
1559         im_aud_mod = (char *)vob->amod_probed_xml;
1560         //need to load the correct module if the input file type is xml
1561     }
1562 
1563     // make zero frame size default for no video
1564     if (im_vid_mod != NULL && strcmp(im_vid_mod, "null") == 0) {
1565         vob->im_v_width = 0;
1566         vob->im_v_height = 0;
1567     }
1568 
1569     //initial aspect ratio
1570     asr = (double) vob->im_v_width/vob->im_v_height;
1571 
1572     // -g
1573 
1574     // import size
1575     // force to even for YUV mode
1576     if (vob->im_v_codec == CODEC_YUV || vob->im_v_codec == CODEC_YUV422) {
1577         if (vob->im_v_width % 2 != 0) {
1578             tc_warn("frame width must be even in YUV/YUV422 mode");
1579             vob->im_v_width--;
1580         }
1581         if (vob->im_v_codec == CODEC_YUV && vob->im_v_height % 2 != 0) {
1582             tc_warn("frame height must be even in YUV mode");
1583             vob->im_v_height--;
1584         }
1585     }
1586     if (verbose & TC_INFO) {
1587         if (vob->im_v_width && vob->im_v_height) {
1588             tc_log_info(PACKAGE, "V: %-16s | %03dx%03d  %4.2f:1  %s",
1589                         "import frame", vob->im_v_width, vob->im_v_height,
1590                         asr, tc_asr_code_describe(vob->im_asr));
1591         } else {
1592             tc_log_info(PACKAGE, "V: %-16s | disabled", "import frame");
1593         }
1594     }
1595 
1596     // init frame size with cmd line frame size
1597     vob->ex_v_height = vob->im_v_height;
1598     vob->ex_v_width  = vob->im_v_width;
1599 
1600     // import bytes per frame (RGB 24bits)
1601     vob->im_v_size   = vob->im_v_height * vob->im_v_width * BPP/8;
1602     // export bytes per frame (RGB 24bits)
1603     vob->ex_v_size   = vob->im_v_size;
1604 
1605     // calc clip settings for encoding to mpeg (vcd,svcd,xvcd,dvd)
1606     // --export_prof {vcd,vcd-pal,vcd-ntsc,svcd,svcd-pal,svcd-ntsc,dvd,dvd-pal,dvd-ntsc}
1607 
1608     if (vob->mpeg_profile != PROF_NONE) {
1609         ratio_t imasr = asrs[0];
1610         ratio_t exasr = asrs[0];
1611 
1612         int impal = 0;
1613         int pre_clip;
1614 
1615         // Make an educated guess if this is pal or ntsc
1616         switch (vob->mpeg_profile) {
1617           case VCD:
1618           case SVCD:
1619           case XVCD:
1620           case DVD:
1621             if (vob->im_v_height == 288 || vob->im_v_height == 576)
1622                 impal = 1;
1623             if ((int)vob->fps == 25 || vob->im_frc == 3)
1624                 impal = 1;
1625             break;
1626           case VCD_PAL:
1627           case SVCD_PAL:
1628           case XVCD_PAL:
1629           case DVD_PAL:
1630             impal = 1;
1631             break;
1632           default:
1633             break;
1634         }
1635 
1636         // choose height dependent on pal or NTSC.
1637         switch (vob->mpeg_profile) {
1638           case VCD:
1639           case VCD_PAL:
1640           case VCD_NTSC:
1641             if (!vob->zoom_height)
1642                 vob->zoom_height = impal ?288 :240;
1643             break;
1644 
1645           case SVCD:
1646           case SVCD_PAL:
1647           case SVCD_NTSC:
1648           case XVCD:
1649           case XVCD_PAL:
1650           case XVCD_NTSC:
1651           case DVD:
1652           case DVD_PAL:
1653           case DVD_NTSC:
1654             if (!vob->zoom_height)
1655                 vob->zoom_height = impal ?576 :480;
1656             break;
1657 
1658           default:
1659             break;
1660         }
1661 
1662         // choose width if not set by user.
1663         switch (vob->mpeg_profile) {
1664           case VCD:
1665           case VCD_PAL:
1666           case VCD_NTSC:
1667             if (!vob->zoom_width)
1668                 vob->zoom_width = 352;
1669             vob->ex_asr = 2;
1670             break;
1671           case SVCD:
1672           case SVCD_PAL:
1673           case SVCD_NTSC:
1674           case XVCD:
1675           case XVCD_PAL:
1676           case XVCD_NTSC:
1677             if (!vob->zoom_width)
1678                 vob->zoom_width = 480;
1679             vob->ex_asr = 2;
1680             break;
1681           case DVD:
1682           case DVD_PAL:
1683           case DVD_NTSC:
1684             if (!vob->zoom_width)
1685                 vob->zoom_width = 720;
1686             if (vob->ex_asr <= 0)
1687                 vob->ex_asr = 2; // assume 4:3
1688             break;
1689           default:
1690             break;
1691         }
1692 
1693         // an input file without any aspect ratio setting (an AVI maybe?)
1694         // so make a guess.
1695 
1696         if (vob->im_asr == 0) {
1697             int i, mini=0;
1698             const ratio_t *r = &asrs[1];
1699             double diffs[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
1700             double mindiff = 2.0;
1701 
1702             for (i = 0; i < 6; i++) {
1703                 diffs[i] = (double)(r->b*vob->im_v_width) / (double)(r->t*vob->im_v_height);
1704                 r++;
1705             }
1706 
1707             // look for the diff which is closest to 1.0
1708 
1709             for (i = 0; i < 6; i++) {
1710                 double a = fabs(1.0 - diffs[i]);
1711                 if (a < mindiff) {
1712                     mindiff = a;
1713                     mini = i+1;
1714                 }
1715             }
1716             vob->im_asr = mini;
1717         }
1718 
1719         imasr = asrs[vob->im_asr];
1720         exasr = asrs[vob->ex_asr];
1721 
1722         pre_clip = vob->im_v_height - (vob->im_v_height * imasr.t * exasr.b ) / (imasr.b * exasr.t );
1723 
1724         if (pre_im_clip == TC_FALSE) {
1725             if (pre_clip % 2 != 0) {
1726                 vob->pre_im_clip_top = pre_clip/2+1;
1727                 vob->pre_im_clip_bottom = pre_clip/2-1;
1728             } else {
1729                 vob->pre_im_clip_bottom = vob->pre_im_clip_top = pre_clip/2;
1730             }
1731             if (vob->pre_im_clip_top % 2 != 0 || vob->pre_im_clip_bottom % 2 != 0) {
1732                 vob->pre_im_clip_top--;
1733                 vob->pre_im_clip_bottom++;
1734             }
1735         }
1736 
1737         //FIXME hack, kludge, etc. EMS
1738         if ((vob->im_v_height != vob->zoom_height)
1739          || ((vob->im_v_width != vob->zoom_width) && (vob->ex_v_width != 704)))
1740             zoom = TC_TRUE;
1741         else
1742             zoom = TC_FALSE;
1743 
1744         if (pre_clip) pre_im_clip = TC_TRUE;
1745 
1746         // shall we really go this far?
1747         // If yes, there can be much more settings adjusted.
1748         if (ex_vid_mod == NULL || !strcmp(ex_vid_mod, "mpeg2enc")) {
1749 #ifdef HAVE_MJPEGTOOLS
1750             if (!ex_aud_mod)
1751                 ex_aud_mod = "mp2enc";
1752             no_v_out_codec = 0;
1753             ex_vid_mod = "mpeg2enc";
1754             //FIXME this should be in export_mpeg2enc.c
1755             if (!vob->ex_v_fcc) {
1756                 switch (vob->mpeg_profile) {
1757                   case VCD:
1758                   case VCD_PAL:
1759                   case VCD_NTSC:
1760                     vob->ex_v_fcc = "1";
1761                     break;
1762                   case SVCD:
1763                   case SVCD_PAL:
1764                   case SVCD_NTSC:
1765                   case XVCD:
1766                   case XVCD_PAL:
1767                   case XVCD_NTSC:
1768                     vob->ex_v_fcc = "4";
1769                     break;
1770                   case DVD:
1771                   case DVD_PAL:
1772                   case DVD_NTSC:
1773                     vob->ex_v_fcc = "8";
1774                     break;
1775                   default:
1776                     break;
1777                 }
1778             }
1779 #endif
1780         } else if(!strcmp(ex_vid_mod, "ffmpeg")) {
1781             if (!ex_aud_mod)
1782                 ex_aud_mod = "ffmpeg";
1783             switch (vob->mpeg_profile) {
1784               case VCD:
1785                 vob->ex_v_fcc = "vcd";
1786                 break;
1787               case VCD_PAL:
1788                 vob->ex_v_fcc = "vcd-pal";
1789                 break;
1790               case VCD_NTSC:
1791                 vob->ex_v_fcc = "vcd-ntsc";
1792                 break;
1793               case SVCD:
1794                 vob->ex_v_fcc = "svcd";
1795                 break;
1796               case SVCD_PAL:
1797                 vob->ex_v_fcc = "svcd-pal";
1798                 break;
1799               case SVCD_NTSC:
1800                 vob->ex_v_fcc = "svcd-ntsc";
1801                 break;
1802               case XVCD:
1803                 vob->ex_v_fcc = "xvcd";
1804                 break;
1805               case XVCD_PAL:
1806                 vob->ex_v_fcc = "xvcd-pal";
1807                 break;
1808               case XVCD_NTSC:
1809                 vob->ex_v_fcc = "xvcd-ntsc";
1810                 break;
1811               case DVD:
1812                 vob->ex_v_fcc = "dvd";
1813                 break;
1814               case DVD_PAL:
1815                 vob->ex_v_fcc = "dvd-pal";
1816                 break;
1817               case DVD_NTSC:
1818                 vob->ex_v_fcc = "dvd-ntsc";
1819                 break;
1820               case PROF_NONE:
1821                 break;
1822             }
1823         } // ffmpeg
1824 
1825         if (ex_aud_mod == NULL) {
1826 #ifdef HAVE_MJPEGTOOLS
1827             no_a_out_codec=0;
1828             ex_aud_mod = "mp2enc";
1829 #endif
1830         }
1831     } // mpeg_profile != PROF_NONE
1832 
1833 
1834     // --PRE_CLIP
1835     if (pre_im_clip) {
1836         CLIP_CHECK(pre_im_clip, "pre_clip", "--pre_clip");
1837 
1838         if (verbose & TC_INFO) {
1839             tc_log_info(PACKAGE, "V: %-16s | %03dx%03d (%d,%d,%d,%d)",
1840                        "pre clip frame", vob->ex_v_width, vob->ex_v_height,
1841                        vob->pre_im_clip_top, vob->pre_im_clip_left,
1842                        vob->pre_im_clip_bottom, vob->pre_im_clip_right);
1843         }
1844     }
1845 
1846     // -j
1847     if (im_clip) {
1848         CLIP_CHECK(im_clip, "clip", "-j");
1849 
1850         if (verbose & TC_INFO) {
1851             tc_log_info(PACKAGE, "V: %-16s | %03dx%03d", "clip frame (<-)",
1852                         vob->ex_v_width, vob->ex_v_height);
1853         }
1854     }
1855 
1856     // -I
1857     /* can this really happen? */
1858     if (vob->deinterlace < 0 || vob->deinterlace > 5) {
1859         tc_error("invalid parameter for option -I");
1860     }
1861 
1862     if ((verbose & TC_INFO) && vob->deinterlace) {
1863         tc_log_info(PACKAGE,
1864                     "V: %-16s | (mode=%i) %s",
1865                     "de-interlace", vob->deinterlace,
1866                     deinterlace_desc[vob->deinterlace]);
1867     }
1868 
1869     if (vob->deinterlace == 4)
1870         vob->ex_v_height /= 2;
1871 
1872     // Calculate the missing w or h based on the ASR
1873     if (zoom && (vob->zoom_width == 0 || vob->zoom_height == 0)) {
1874         enum missing_t { NONE, CALC_W, CALC_H, ALL } missing = ALL;
1875         ratio_t asr = asrs[0];
1876         float oldr;
1877 
1878         // check if we have at least on width or height
1879         if (vob->zoom_width == 0 && vob->zoom_height == 0)
1880             missing = ALL;
1881         else if (vob->zoom_width == 0 && vob->zoom_height > 0)
1882             missing = CALC_W;
1883         else if (vob->zoom_width > 0 && vob->zoom_height == 0)
1884             missing = CALC_H;
1885         else if (vob->zoom_width > 0 && vob->zoom_height > 0)
1886             missing = NONE;
1887 
1888         // try import
1889         if (vob->im_asr > 0 && vob->im_asr < 5)
1890             asr = asrs[vob->im_asr];
1891         // try the export aspectratio
1892         else if (vob->ex_asr > 0 && vob->ex_asr < 5)
1893             asr = asrs[vob->ex_asr];
1894 
1895         switch (missing) {
1896           case ALL:
1897             tc_error("Neither zoom width nor height set, can't guess anything");
1898           case CALC_W:
1899             vob->zoom_width = vob->zoom_height * asr.t; vob->zoom_width /= asr.b;
1900             break;
1901           case CALC_H:
1902             vob->zoom_height = vob->zoom_width * asr.b; vob->zoom_height /= asr.t;
1903             break;
1904           case NONE:
1905           default:
1906             /* can't happen */
1907             break;
1908         }
1909 
1910         // for error printout
1911         oldr = (float)vob->zoom_width/(float)vob->zoom_height;
1912 
1913         // align
1914         if (vob->zoom_height % 8 != 0)
1915             vob->zoom_height += 8-(vob->zoom_height%8);
1916         if (vob->zoom_width % 8 != 0)
1917             vob->zoom_width += 8-(vob->zoom_width%8);
1918         oldr = ((float)vob->zoom_width/(float)vob->zoom_height-oldr)*100.0;
1919         oldr = oldr<0?-oldr:oldr;
1920 
1921         tc_log_info(PACKAGE, "V: %-16s | %03dx%03d  %4.2f:1 error %.2f%%",
1922                     "auto resize", vob->zoom_width, vob->zoom_height,
1923                     (float)vob->zoom_width/(float)vob->zoom_height, oldr);
1924     }
1925 
1926     // -Z ...,fast
1927     if (fast_resize) {
1928         int ret = tc_compute_fast_resize_values(vob, TC_FALSE);
1929         if (ret == 0) {
1930             if (vob->hori_resize1 == 0 && vob->vert_resize1 == 0)
1931                 resize1 = TC_FALSE;
1932             else
1933                 resize1 = TC_TRUE;
1934             if (vob->hori_resize2 == 0 && vob->vert_resize2 == 0)
1935                 resize2 = TC_FALSE;
1936             else
1937                 resize2 = TC_TRUE;
1938 
1939             if (verbose & TC_INFO) {
1940                 tc_log_info(PACKAGE, "V: %-16s | Using -B %d,%d,8 -X %d,%d,8",
1941                             "fast resize",
1942                             vob->vert_resize1, vob->hori_resize1,
1943                             vob->vert_resize2, vob->hori_resize2);
1944             }
1945             zoom = TC_FALSE;
1946         } else {
1947             if(verbose & TC_INFO) {
1948                 tc_log_info(PACKAGE,
1949                             "V: %-16s | requested but can't be used (W or H mod 8 != 0)",
1950                             "fast resize");
1951             }
1952         }
1953     }
1954 
1955     // -X
1956     if (resize2) {
1957         if (vob->resize2_mult % 8 != 0)
1958             tc_error("resize multiplier for option -X is not a multiple of 8");
1959 
1960         // works only for frame dimension beeing an integral multiple of vob->resize2_mult:
1961         if (vob->vert_resize2
1962          && (vob->vert_resize2 * vob->resize2_mult + vob->ex_v_height) % vob->resize2_mult != 0)
1963             tc_error("invalid frame height for option -X, check also option -j");
1964 
1965         if (vob->hori_resize2
1966          && (vob->hori_resize2 * vob->resize2_mult + vob->ex_v_width) % vob->resize2_mult != 0)
1967             tc_error("invalid frame width for option -X, check also option -j");
1968 
1969         vob->ex_v_height += (vob->vert_resize2 * vob->resize2_mult);
1970         vob->ex_v_width += (vob->hori_resize2 * vob->resize2_mult);
1971 
1972         //check2:
1973 
1974         if (vob->ex_v_height > TC_MAX_V_FRAME_HEIGHT
1975          || vob->ex_v_width >TC_MAX_V_FRAME_WIDTH)
1976             tc_error("invalid resize parameter for option -X");
1977 
1978         if (vob->vert_resize2 <0 || vob->hori_resize2 < 0)
1979             tc_error("invalid resize parameter for option -X");
1980 
1981         // new aspect ratio:
1982         asr *= (double) vob->ex_v_width * (vob->ex_v_height - vob->vert_resize2*vob->resize2_mult)/
1983                 ((vob->ex_v_width - vob->hori_resize2*vob->resize2_mult) * vob->ex_v_height);
1984 
1985         vob->vert_resize2 *= (vob->resize2_mult/8);
1986         vob->hori_resize2 *= (vob->resize2_mult/8);
1987 
1988         if (verbose & TC_INFO && vob->ex_v_height > 0)
1989             tc_log_info(PACKAGE,
1990                         "V: %-16s | %03dx%03d  %4.2f:1 (-X)",
1991                         "new aspect ratio",
1992                         vob->ex_v_width, vob->ex_v_height, asr);
1993     }
1994 
1995     // -B
1996     if (resize1) {
1997         if (vob->resize1_mult % 8 != 0)
1998             tc_error("resize multiplier for option -B is not a multiple of 8");
1999 
2000         // works only for frame dimension beeing an integral multiple of vob->resize1_mult:
2001         if (vob->vert_resize1
2002          && (vob->ex_v_height - vob->vert_resize1*vob->resize1_mult) % vob->resize1_mult != 0)
2003             tc_error("invalid frame height for option -B, check also option -j");
2004 
2005         if (vob->hori_resize1
2006          && (vob->ex_v_width - vob->hori_resize1*vob->resize1_mult) % vob->resize1_mult != 0)
2007             tc_error("invalid frame width for option -B, check also option -j");
2008 
2009         vob->ex_v_height -= (vob->vert_resize1 * vob->resize1_mult);
2010         vob->ex_v_width -= (vob->hori_resize1 * vob->resize1_mult);
2011 
2012         //check:
2013         if (vob->vert_resize1 < 0 || vob->hori_resize1 < 0)
2014             tc_error("invalid resize parameter for option -B");
2015 
2016         //new aspect ratio:
2017         asr *= (double) vob->ex_v_width * (vob->ex_v_height + vob->vert_resize1*vob->resize1_mult)/
2018                        ((vob->ex_v_width + vob->hori_resize1*vob->resize1_mult) * vob->ex_v_height);
2019 
2020         vob->vert_resize1 *= (vob->resize1_mult/8);
2021         vob->hori_resize1 *= (vob->resize1_mult/8);
2022 
2023         if (verbose & TC_INFO && vob->ex_v_height > 0)
2024             tc_log_info(PACKAGE,
2025                         "V: %-16s | %03dx%03d  %4.2f:1 (-B)",
2026                         "new aspect ratio",
2027                         vob->ex_v_width, vob->ex_v_height, asr);
2028     }
2029 
2030     // -Z
2031     if (zoom) {
2032         // new aspect ratio:
2033         asr *= (double) vob->zoom_width*vob->ex_v_height/(vob->ex_v_width * vob->zoom_height);
2034 
2035         vob->ex_v_width  = vob->zoom_width;
2036         vob->ex_v_height = vob->zoom_height;
2037 
2038         if (verbose & TC_INFO && vob->ex_v_height > 0)
2039             tc_log_info(PACKAGE,
2040                         "V: %-16s | %03dx%03d  %4.2f:1 (%s)",
2041                         "zoom",
2042                         vob->ex_v_width, vob->ex_v_height, asr,
2043                         tcv_zoom_filter_to_string(vob->zoom_filter));
2044     }
2045 
2046     // -Y
2047     if (ex_clip) {
2048         CLIP_CHECK(ex_clip, "clip", "-Y");
2049 
2050         if (verbose & TC_INFO)
2051             tc_log_info(PACKAGE,
2052                         "V: %-16s | %03dx%03d", "clip frame (->)",
2053                         vob->ex_v_width, vob->ex_v_height);
2054     }
2055 
2056     // -r
2057     if (rescale) {
2058         vob->ex_v_height /= vob->reduce_h;
2059         vob->ex_v_width /= vob->reduce_w;
2060 
2061         //new aspect ratio:
2062         asr *= (double)vob->ex_v_width/vob->ex_v_height*(vob->reduce_h*vob->ex_v_height)/
2063                 (vob->reduce_w*vob->ex_v_width);
2064         if (verbose & TC_INFO)
2065             tc_log_info(PACKAGE,
2066                         "V: %-16s | %03dx%03d  %4.2f:1 (-r)",
2067                         "rescale frame",
2068                         vob->ex_v_width, vob->ex_v_height,asr);
2069 
2070         // sanity check for YUV
2071         if (vob->im_v_codec == CODEC_YUV || vob->im_v_codec == CODEC_YUV422) {
2072             if (vob->ex_v_width%2 != 0 || (vob->im_v_codec == CODEC_YUV && vob->ex_v_height % 2 != 0)) {
2073                 tc_error("rescaled width/height must be even for YUV mode, try -V rgb24");
2074             }
2075         }
2076     }
2077 
2078     // --keep_asr
2079     if (keepasr) {
2080         int clip, zoomto;
2081         double asr_out = (double)vob->ex_v_width/(double)vob->ex_v_height;
2082         double asr_in  = (double)vob->im_v_width/(double)vob->im_v_height;
2083         double delta   = 0.01;
2084         double asr_cor = 1.0;
2085 
2086 
2087         if (vob->im_asr) {
2088             switch (vob->im_asr) {
2089               case 1:
2090                 asr_cor = (1.0);
2091                 break;
2092               case 2:
2093                 asr_cor = (4.0/3.0);
2094                 break;
2095               case 3:
2096                 asr_cor = (16.0/9.0);
2097                 break;
2098               case 4:
2099                 asr_cor = (2.21);
2100                 break;
2101             }
2102         }
2103 
2104         if (!zoom)
2105             tc_error ("keep_asr only works with -Z");
2106 
2107         if (asr_in-delta < asr_out && asr_out < asr_in+delta)
2108             tc_error ("Aspect ratios are too similar, don't use --keep_asr ");
2109 
2110         if (asr_in > asr_out) {
2111             /* adjust height */
2112             int clipV = (vob->im_clip_top +vob->im_clip_bottom);
2113             int clipH = (vob->im_clip_left+vob->im_clip_right);
2114             int clip1 = 0;
2115             int clip2 = 0;
2116 
2117             zoomto = (int)((double)(vob->ex_v_width) /
2118                        ( ((double)(vob->im_v_width -clipH) / (vob->im_v_width/asr_cor/vob->im_v_height) )/
2119                         (double)(vob->im_v_height-clipV))+.5);
2120             clip = vob->ex_v_height - zoomto;
2121             if (zoomto % 2 != 0)
2122                 (clip>0?zoomto--:zoomto++); // XXX
2123             clip = vob->ex_v_height - zoomto;
2124             clip /= 2;
2125             clip1 = clip2 = clip;
2126 
2127             if (clip & 1) {
2128                 clip1--;
2129                 clip2++;
2130             }
2131             ex_clip = TC_TRUE;
2132             vob->ex_clip_top = -clip1;
2133             vob->ex_clip_bottom = -clip2;
2134 
2135             vob->zoom_height = zoomto;
2136         } else {
2137             /* adjust width */
2138             int clipV = (vob->im_clip_top +vob->im_clip_bottom);
2139             int clipH = (vob->im_clip_left+vob->im_clip_right);
2140             int clip1 = 0;
2141             int clip2 = 0;
2142             zoomto = (int)((double)vob->ex_v_height * (
2143                       ( ((double)(vob->im_v_width-clipH)) / (vob->im_v_width/asr_cor/vob->im_v_height) ) /
2144                         (double)(vob->im_v_height-clipV)) +.5);
2145 
2146             clip = vob->ex_v_width - zoomto;
2147 
2148             if (zoomto % 2 != 0)
2149                 (clip>0?zoomto--:zoomto++); // XXX
2150             clip = vob->ex_v_width - zoomto;
2151             clip /= 2;
2152             clip1 = clip2 = clip;
2153 
2154             if (clip & 1) {
2155                 clip1--;
2156                 clip2++;
2157             }
2158             ex_clip = TC_TRUE;
2159             vob->ex_clip_left = -clip1;
2160             vob->ex_clip_right = -clip2;
2161 
2162             vob->zoom_width = zoomto;
2163         }
2164 
2165        if (vob->ex_v_height - vob->ex_clip_top - vob->ex_clip_bottom <= 0)
2166             tc_error("invalid top/bottom clip parameter calculated from --keep_asr");
2167 
2168         if (vob->ex_v_width - vob->ex_clip_left - vob->ex_clip_right <= 0)
2169             tc_error("invalid left/right clip parameter calculated from --keep_asr");
2170 
2171         if (verbose & TC_INFO)
2172             tc_log_info(PACKAGE, "V: %-16s | yes (%d,%d,%d,%d)", "keep aspect",
2173                         vob->ex_clip_top, vob->ex_clip_left,
2174                         vob->ex_clip_bottom, vob->ex_clip_right);
2175     }
2176 
2177     // -z
2178 
2179     if (flip && verbose & TC_INFO)
2180         tc_log_info(PACKAGE, "V: %-16s | yes", "flip frame");
2181 
2182     // -l
2183     if (mirror && verbose & TC_INFO)
2184         tc_log_info(PACKAGE, "V: %-16s | yes", "mirror frame");
2185 
2186     // -k
2187     if (rgbswap && verbose & TC_INFO)
2188         tc_log_info(PACKAGE, "V: %-16s | yes", "rgb2bgr");
2189 
2190     // -K
2191     if (decolor && verbose & TC_INFO)
2192         tc_log_info(PACKAGE, "V: %-16s | yes", "b/w reduction");
2193 
2194     // -G
2195     if (dgamma && verbose & TC_INFO)
2196         tc_log_info(PACKAGE, "V: %-16s | %.3f", "gamma correction", vob->gamma);
2197 
2198     // number of bits/pixel
2199     //
2200     // Christoph Lampert writes in transcode-users/2002-July/003670.html
2201     //          B*1000            B*1000*asr
2202     //  bpp =  --------;   W^2 = ------------
2203     //          W*H*F             bpp * F
2204     // If this number is less than 0.15, you will
2205     // most likely see visual artefacts (e.g. in high motion scenes). If you
2206     // reach 0.2 or more, the visual quality normally is rather good.
2207     // For my tests, this corresponded roughly to a fixed quantizer of 4,
2208     // which is not brilliant, but okay.
2209 
2210     if (vob->divxbitrate > 0 && vob->divxmultipass != 3
2211       && verbose & TC_INFO) {
2212         double div = vob->ex_v_width * vob->ex_v_height * vob->fps;
2213         double bpp = vob->divxbitrate * 1000;
2214         const char *judge = "";
2215 
2216         if (div < 1.0)
2217             bpp = 0.0;
2218         else
2219             bpp /= div;
2220 
2221         if (bpp <= 0.0)
2222             judge = " (unknown)";
2223         else if (bpp > 0.0  && bpp <= 0.15)
2224             judge = " (low)";
2225 
2226         tc_log_info(PACKAGE, "V: %-16s | %.3f%s", "bits/pixel", bpp, judge);
2227     }
2228 
2229     // -C
2230     if (vob->antialias < 0 || vob->antialias > 3) {
2231         tc_error("invalid parameter for option -C");
2232     } else {
2233         if ((verbose & TC_INFO) && vob->antialias) {
2234             tc_log_info(PACKAGE,
2235                         "V: %-16s | (mode=%d|%.2f|%.2f) %s",
2236                         "anti-alias",
2237                         vob->antialias, vob->aa_weight, vob->aa_bias,
2238                         antialias_desc[vob->antialias]);
2239         }
2240     }
2241 
2242     // --POST_CLIP
2243 
2244     if (post_ex_clip) {
2245         CLIP_CHECK(post_ex_clip, "post_clip", "--post_clip");
2246 
2247         if (verbose & TC_INFO)
2248             tc_log_info(PACKAGE,
2249                         "V: %-16s | %03dx%03d",
2250                         "post clip frame",
2251                         vob->ex_v_width, vob->ex_v_height);
2252     }
2253 
2254 
2255     // -W
2256     if (vob->vob_percentage) {
2257         if (vob->vob_chunk < 0 || vob->vob_chunk < 0)
2258             tc_error("invalid parameter for option -W");
2259     } else {
2260         if (vob->vob_chunk < 0 || vob->vob_chunk > vob->vob_chunk_max + 1)
2261             tc_error("invalid parameter for option -W");
2262     }
2263 
2264     // -f
2265 
2266     if (verbose & TC_INFO)
2267         tc_log_info(PACKAGE, "V: %-16s | %.3f,%d",
2268                     "decoding fps,frc",
2269                     vob->fps, vob->im_frc);
2270 
2271     // -R
2272     if (vob->divxmultipass && verbose & TC_INFO) {
2273         switch (vob->divxmultipass) {
2274           case 1:
2275             tc_log_info(PACKAGE,
2276                         "V: %-16s | (mode=%d) %s %s",
2277                         "multi-pass",
2278                         vob->divxmultipass,
2279                         "writing data (pass 1) to",
2280                         vob->divxlogfile);
2281             break;
2282           case 2:
2283             tc_log_info(PACKAGE,
2284                         "V: %-16s | (mode=%d) %s %s",
2285                         "multi-pass",
2286                         vob->divxmultipass,
2287                         "reading data (pass2) from",
2288                         vob->divxlogfile);
2289             break;
2290           case 3:
2291             if (vob->divxbitrate > VMAXQUANTIZER)
2292                 vob->divxbitrate = VQUANTIZER;
2293             tc_log_info(PACKAGE,
2294                         "V: %-16s | (mode=%d) %s (quant=%d)",
2295                         "single-pass",
2296                         vob->divxmultipass,
2297                         "constant quantizer/quality",
2298                         vob->divxbitrate);
2299             break;
2300         }
2301     }
2302 
2303     // export frame size final check
2304     if (vob->ex_v_height < 0 || vob->ex_v_width < 0) {
2305         tc_warn("invalid export frame combination %dx%d", vob->ex_v_width, vob->ex_v_height);
2306         tc_error("invalid frame processing requested");
2307     }
2308 
2309     // -V
2310     if (vob->im_v_codec == CODEC_YUV) {
2311         vob->ex_v_size = (3*vob->ex_v_height * vob->ex_v_width)>>1;
2312         vob->im_v_size = (3*vob->im_v_height * vob->im_v_width)>>1;
2313         if (verbose & TC_INFO)
2314             tc_log_info(PACKAGE,
2315                         "V: %-16s | YUV420 (4:2:0) aka I420",
2316                         "video format");
2317     } else if (vob->im_v_codec == CODEC_YUV422) {
2318         vob->ex_v_size = (2*vob->ex_v_height * vob->ex_v_width);
2319         vob->im_v_size = (2*vob->im_v_height * vob->im_v_width);
2320         if (verbose & TC_INFO)
2321             tc_log_info(PACKAGE,
2322                         "V: %-16s | YUV422 (4:2:2)",
2323                         "video format");
2324     } else {
2325         vob->ex_v_size = vob->ex_v_height * vob->ex_v_width * BPP/8;
2326         if (verbose & TC_INFO)
2327             tc_log_info(PACKAGE,
2328                         "V: %-16s | RGB24",
2329                         "video format");
2330     }
2331 
2332     // -m
2333     // different audio/video output files not yet supported
2334     if (vob->audio_out_file == NULL)
2335         vob->audio_out_file = vob->video_out_file;
2336 
2337     // -n
2338     if (no_ain_codec == 1 && vob->has_audio == 0
2339      && vob->a_codec_flag == CODEC_AC3) {
2340         if (vob->amod_probed == NULL || strcmp(vob->amod_probed,"null") == 0) {
2341             if (verbose & TC_DEBUG)
2342                 tc_log_warn(PACKAGE,
2343                             "problems detecting audio format - using 'null' module");
2344             vob->a_codec_flag = 0;
2345         }
2346     }
2347 
2348     if (preset_flag & TC_PROBE_NO_TRACK) {
2349         //tracks specified by user
2350     } else {
2351         if (!vob->has_audio_track && vob->has_audio) {
2352             tc_warn("requested audio track %d not found - using 'null' module", vob->a_track);
2353             vob->a_codec_flag = 0;
2354         }
2355     }
2356 
2357     //audio import disabled
2358     if (vob->a_codec_flag == 0) {
2359         if (verbose & TC_INFO)
2360             tc_log_info(PACKAGE, "A: %-16s | disabled", "import");
2361         im_aud_mod = "null";
2362     } else {
2363         //audio format, if probed sucessfully
2364         if (verbose & TC_INFO) {
2365             if (vob->a_stream_bitrate)
2366                 tc_log_info(PACKAGE,
2367                             "A: %-16s | 0x%-5lx %-12s [%4d,%2d,%1d] %4d kbps",
2368                             "import format",
2369                             vob->a_codec_flag,
2370                             tc_codec_to_comment(vob->a_codec_flag),
2371                             vob->a_rate, vob->a_bits, vob->a_chan,
2372                             vob->a_stream_bitrate);
2373             else
2374                 tc_log_info(PACKAGE,
2375                             "A: %-16s | 0x%-5lx %-12s [%4d,%2d,%1d]",
2376                             "import format",
2377                             vob->a_codec_flag,
2378                             tc_codec_to_comment(vob->a_codec_flag),
2379                             vob->a_rate, vob->a_bits, vob->a_chan);
2380         }
2381     }
2382 
2383     if (vob->im_a_codec == CODEC_PCM && vob->a_chan > 2 && !(vob->pass_flag & TC_AUDIO)) {
2384         // Input is more than 2 channels (i.e. 5.1 AC3) but PCM internal
2385         // representation can't handle that, adjust the channel count to reflect
2386         // what modules will actually have presented to them.
2387         if (verbose & TC_INFO)
2388             tc_log_info(PACKAGE,
2389                         "A: %-16s | %d channels -> %d channels",
2390                         "downmix", vob->a_chan, 2);
2391         vob->a_chan = 2;
2392     }
2393 
2394     if (vob->ex_a_codec == 0 || vob->a_codec_flag == 0
2395      || ex_aud_mod == NULL || strcmp(ex_aud_mod, "null") == 0) {
2396         if (verbose & TC_INFO)
2397             tc_log_info(PACKAGE, "A: %-16s | disabled", "export");
2398         ex_aud_mod = "null";
2399     } else {
2400         // audio format
2401         if (ex_aud_mod && strlen(ex_aud_mod) != 0) {
2402             if (strcmp(ex_aud_mod, "mpeg") == 0)
2403                 vob->ex_a_codec = CODEC_MP2;
2404             if (strcmp(ex_aud_mod, "mp2enc") == 0)
2405                 vob->ex_a_codec = CODEC_MP2;
2406             if (strcmp(ex_aud_mod, "mp1e") == 0)
2407                 vob->ex_a_codec=CODEC_MP2;
2408         }
2409 
2410         // calc export bitrate
2411         switch (vob->ex_a_codec) {
2412           case 0x1: // PCM
2413             vob->mp3bitrate = ((vob->mp3frequency > 0) ?vob->mp3frequency :vob->a_rate) *
2414                                ((vob->dm_bits > 0) ?vob->dm_bits :vob->a_bits) *
2415                                 ((vob->dm_chan > 0) ?vob->dm_chan :vob->a_chan) / 1000;
2416             break;
2417           case 0x2000: // PCM
2418             if (vob->im_a_codec == CODEC_AC3) {
2419                 vob->mp3bitrate = vob->a_stream_bitrate;
2420             }
2421             break;
2422         }
2423 
2424         if (verbose & TC_INFO) {
2425             if (vob->pass_flag & TC_AUDIO)
2426                 tc_log_info(PACKAGE,
2427                             "A: %-16s | 0x%-5x %-12s [%4d,%2d,%1d] %4d kbps",
2428                             "export format",
2429                             vob->im_a_codec,
2430                             tc_codec_to_comment(vob->im_a_codec),
2431                             vob->a_rate, vob->a_bits, vob->a_chan,
2432                             vob->a_stream_bitrate);
2433             else
2434                 tc_log_info(PACKAGE,
2435                             "A: %-16s | 0x%-5x %-12s [%4d,%2d,%1d] %4d kbps",
2436                             "export format",
2437                             vob->ex_a_codec,
2438                             tc_codec_to_comment(vob->ex_a_codec),
2439                              ((vob->mp3frequency > 0) ?vob->mp3frequency :vob->a_rate),
2440                              ((vob->dm_bits > 0) ?vob->dm_bits :vob->a_bits),
2441                              ((vob->dm_chan > 0) ?vob->dm_chan :vob->a_chan),
2442                             vob->mp3bitrate);
2443             tc_log_info(PACKAGE, "V: %-16s | %s%s", "export format",
2444                         tc_codec_to_string(vob->ex_v_codec),
2445                         (vob->ex_v_codec == 0) ?" (module dependant)" :"");
2446         }
2447     }
2448 
2449     // Do not run out of audio-data
2450     // import_ac3 now correctly probes the channels of the ac3 stream
2451     // (previous versions always returned "2"). This breakes transcode
2452     // when doing -A --tibit
2453     if (vob->im_a_codec == CODEC_AC3)
2454         vob->a_chan = vob->a_chan > 2 ?2 :vob->a_chan;
2455 
2456     // -f and --export_fps/export_frc
2457     //
2458     // set import/export frc/fps
2459     if (vob->im_frc == 0)
2460         tc_frc_code_from_value(&vob->im_frc, vob->fps);
2461 
2462     // ex_fps given, but not ex_frc
2463     if (vob->ex_frc == 0 && (vob->ex_fps != 0.0))
2464         tc_frc_code_from_value(&vob->ex_frc, vob->ex_fps);
2465 
2466     if (vob->ex_frc == 0 && vob->im_frc != 0)
2467         vob->ex_frc = vob->im_frc;
2468 
2469     // ex_frc always overwrites ex_fps
2470     if (vob->ex_frc > 0)
2471         tc_frc_code_to_value(vob->ex_frc, &vob->ex_fps);
2472 
2473     if (vob->im_frc <= 0 && vob->ex_frc <= 0 && vob->ex_fps == 0)
2474         vob->ex_fps = vob->fps;
2475 
2476     if (vob->im_frc == -1)
2477         vob->im_frc = 0;
2478     if (vob->ex_frc == -1)
2479         vob->ex_frc = 0;
2480 
2481     // --export_fps
2482 
2483     if(verbose & TC_INFO)
2484         tc_log_info(PACKAGE,
2485                     "V: %-16s | %.3f,%d",
2486                     "encoding fps,frc",
2487                     vob->ex_fps, vob->ex_frc);
2488 
2489 
2490     // --a52_demux
2491 
2492     if ((vob->a52_mode & TC_A52_DEMUX) && (verbose & TC_INFO))
2493         tc_log_info(PACKAGE,
2494                     "A: %-16s | %s", "A52 demuxing",
2495                     "(yes) 3 front, 2 rear, 1 LFE (5.1)");
2496 
2497     //audio language, if probed sucessfully
2498     if(vob->lang_code > 0 && (verbose & TC_INFO))
2499         tc_log_info(PACKAGE,
2500                     "A: %-16s | %c%c",
2501                     "language",
2502                     vob->lang_code >> 8, vob->lang_code & 0xff);
2503 
2504     // recalculate audio bytes per frame since video frames per second
2505     // may have changed
2506 
2507     // samples per audio frame
2508     fch = vob->a_rate/vob->ex_fps;
2509 
2510     // bytes per audio frame
2511     vob->im_a_size = (int)(fch * (vob->a_bits/8) * vob->a_chan);
2512     vob->im_a_size =  (vob->im_a_size >> 2) << 2;
2513 
2514     // rest:
2515     fch *= (vob->a_bits/8) * vob->a_chan;
2516 
2517     leap_bytes1 = TC_LEAP_FRAME * (fch - vob->im_a_size);
2518     leap_bytes2 = - leap_bytes1 + TC_LEAP_FRAME * (vob->a_bits/8) * vob->a_chan;
2519     leap_bytes1 = (leap_bytes1 >> 2) << 2;
2520     leap_bytes2 = (leap_bytes2 >> 2) << 2;
2521 
2522     if(leap_bytes1<leap_bytes2) {
2523         vob->a_leap_bytes = leap_bytes1;
2524     } else {
2525         vob->a_leap_bytes = -leap_bytes2;
2526         vob->im_a_size += (vob->a_bits/8) * vob->a_chan;
2527     }
2528 
2529     // final size in bytes
2530     vob->ex_a_size = vob->im_a_size;
2531 
2532     if (verbose & TC_INFO)
2533         tc_log_info(PACKAGE,
2534                     "A: %-16s | %d (%.6f)",
2535                     "bytes per frame", vob->im_a_size, fch);
2536 
2537     if(no_audio_adjust) {
2538         vob->a_leap_bytes=0;
2539 
2540         if (verbose & TC_INFO)
2541             tc_log_info(PACKAGE, "A: %-16s | disabled", "adjustment");
2542 
2543     } else
2544         if (verbose & TC_INFO)
2545             tc_log_info(PACKAGE,
2546                         "A: %-16s | %d@%d", "adjustment",
2547                         vob->a_leap_bytes, vob->a_leap_frame);
2548 
2549     // -s
2550 
2551     if (vob->volume > 0 && vob->a_chan != 2) {
2552         //tc_error("option -s not yet implemented for mono streams");
2553     }
2554 
2555     if (vob->volume > 0 && (verbose & TC_INFO))
2556         tc_log_info(PACKAGE,
2557                     "A: %-16s | %5.3f",
2558                     "rescale stream", vob->volume);
2559 
2560     // -D
2561     if (vob->sync_ms >= (int) (1000.0/vob->ex_fps)
2562       || vob->sync_ms <= - (int) (1000.0/vob->ex_fps)) {
2563         vob->sync     = (int) (vob->sync_ms/1000.0*vob->ex_fps);
2564         vob->sync_ms -= vob->sync * (int) (1000.0/vob->ex_fps);
2565     }
2566 
2567     if ((vob->sync || vob->sync_ms) && (verbose & TC_INFO))
2568         tc_log_info(PACKAGE,
2569                     "A: %-16s | %d ms [ %d (A) | %d ms ]",
2570                     "AV shift",
2571                     vob->sync * (int) (1000.0/vob->ex_fps) + vob->sync_ms,
2572                     vob->sync, vob->sync_ms);
2573 
2574     // -d
2575     if (pcmswap)
2576         if (verbose & TC_INFO)
2577             tc_log_info(PACKAGE, "A: %-16s | yes", "swap bytes");
2578 
2579     // -E
2580 
2581     //set export parameter to input parameter, if no re-sampling is requested
2582     if (vob->dm_chan == 0)
2583         vob->dm_chan = vob->a_chan;
2584     if (vob->dm_bits == 0)
2585         vob->dm_bits = vob->a_bits;
2586 
2587     // -P
2588     if (vob->pass_flag & TC_AUDIO) {
2589         vob->im_a_codec = CODEC_RAW;
2590         vob->ex_a_codec = CODEC_RAW;
2591         //suggestion:
2592         if (no_a_out_codec)
2593             ex_aud_mod = "raw";
2594         no_a_out_codec = 0;
2595 
2596         if (verbose & TC_INFO)
2597             tc_log_info(PACKAGE, "A: %-16s | yes", "pass-through");
2598     }
2599 
2600     // -m
2601     // different audio/video output files need two export modules
2602     if (no_a_out_codec == 0 && vob->audio_out_file == NULL
2603      && strcmp(ex_vid_mod, ex_aud_mod) != 0)
2604         tc_error("different audio/export modules require use of option -m");
2605 
2606 
2607     // --accel
2608 #if defined(ARCH_X86) || defined(ARCH_X86_64)
2609     if (verbose & TC_INFO)
2610         tc_log_info(PACKAGE, "V: IA32/AMD64 accel | %s ",
2611                     ac_flagstotext(tc_accel & ac_cpuinfo()));
2612 #endif
2613 
2614     ac_init(tc_accel);
2615 
2616     // more checks with warnings
2617 
2618     if (verbose & TC_INFO) {
2619         // -o
2620         if (vob->video_out_file == NULL && vob->audio_out_file == NULL
2621          && core_mode == TC_MODE_DEFAULT) {
2622             vob->video_out_file = TC_DEFAULT_OUT_FILE;
2623             vob->audio_out_file = TC_DEFAULT_OUT_FILE;
2624             tc_warn("no option -o found, encoded frames send to \"%s\"",
2625                     vob->video_out_file);
2626         }
2627 
2628         // -y
2629         if (core_mode == TC_MODE_DEFAULT
2630          && vob->video_out_file != NULL && no_v_out_codec)
2631             tc_warn("no option -y found, option -o ignored, writing to \"/dev/null\"");
2632 
2633         if (core_mode == TC_MODE_AVI_SPLIT && no_v_out_codec)
2634             tc_warn("no option -y found, option -t ignored, writing to \"/dev/null\"");
2635 
2636         if (vob->im_v_codec == CODEC_YUV
2637          && (vob->im_clip_left % 2 != 0 || vob->im_clip_right % 2
2638          || vob->im_clip_top % 2 != 0 || vob->im_clip_bottom % 2 != 0))
2639             tc_warn ("Odd import clipping paramter(s) detected, may cause distortion");
2640 
2641         if (vob->im_v_codec == CODEC_YUV
2642          && (vob->ex_clip_left % 2 != 0 || vob->ex_clip_right % 2
2643          || vob->ex_clip_top % 2 != 0 || vob->ex_clip_bottom % 2 != 0))
2644             tc_warn ("Odd export clipping paramter(s) detected, may cause distortion");
2645     }
2646 
2647     // -u
2648     if (tc_buffer_delay_dec == -1) //adjust core parameter
2649         tc_buffer_delay_dec = (vob->pass_flag & TC_VIDEO || ex_vid_mod==NULL || strcmp(ex_vid_mod, "null") == 0)
2650                                 ?TC_DELAY_MIN :TC_DELAY_MAX;
2651 
2652     if (tc_buffer_delay_enc == -1) //adjust core parameter
2653         tc_buffer_delay_enc = (vob->pass_flag & TC_VIDEO || ex_vid_mod==NULL || strcmp(ex_vid_mod, "null") == 0)
2654                                 ?TC_DELAY_MIN :TC_DELAY_MAX;
2655 
2656     if (verbose & TC_DEBUG)
2657         tc_log_msg(PACKAGE, "encoder delay = decode=%d encode=%d usec",
2658                    tc_buffer_delay_dec, tc_buffer_delay_enc);
2659 
2660     if (core_mode == TC_MODE_AVI_SPLIT && !strlen(base) && !vob->video_out_file)
2661         tc_error("no option -o found, no base for -t given, so what?");
2662 
2663     /* -------------------------------------------------------------
2664      *
2665      * OK, so far, now start the support threads, setup buffers, ...
2666      *
2667      * ------------------------------------------------------------- */
2668 
2669     //this will speed up in pass-through mode
2670     if(vob->pass_flag && !(preset_flag & TC_PROBE_NO_BUFFER))
2671         max_frame_buffer = 50;
2672 
2673     if (vob->fps >= vob->ex_fps) {
2674         /* worst case -> lesser fps (more audio samples for second) */
2675         specs.frc = vob->im_frc;
2676     } else {
2677         specs.frc = vob->ex_frc;
2678     }
2679     specs.width = TC_MAX(vob->im_v_width, vob->ex_v_width);
2680     specs.height = TC_MAX(vob->im_v_height, vob->ex_v_height);
2681     specs.format = vob->im_v_codec;
2682 
2683     /* XXX: explain me up */
2684     specs.rate = TC_MAX(vob->a_rate, vob->mp3frequency);
2685     specs.channels = TC_MAX(vob->a_chan, vob->dm_chan);
2686     specs.bits = TC_MAX(vob->a_bits, vob->dm_bits);
2687 
2688     tc_framebuffer_set_specs(&specs);
2689 
2690     if (verbose & TC_INFO) {
2691         tc_log_info(PACKAGE, "V: video buffer     | %i @ %ix%i [0x%x]",
2692                     max_frame_buffer, specs.width, specs.height, specs.format);
2693         tc_log_info(PACKAGE, "A: audio buffer     | %i @ %ix%ix%i",
2694                     max_frame_buffer, specs.rate, specs.channels, specs.bits);
2695     }
2696 
2697 #ifdef STATBUFFER
2698     // allocate buffer
2699     if (verbose & TC_DEBUG)
2700         tc_log_msg(PACKAGE, "allocating %d framebuffers (static)",
2701                    max_frame_buffer);
2702 
2703     if (vframe_alloc(max_frame_buffer) < 0)
2704         tc_error("static framebuffer allocation failed");
2705     if (aframe_alloc(max_frame_buffer) < 0)
2706         tc_error("static framebuffer allocation failed");
2707 
2708 #else
2709     if(verbose & TC_DEBUG)
2710         tc_log_msg(PACKAGE, "%d framebuffers (dynamic) requested",
2711                    max_frame_buffer);
2712 #endif
2713 
2714     // load import/export modules and filters plugins
2715     if (transcode_init(vob, tc_get_ringbuffer(max_frame_threads, max_frame_threads)) < 0)
2716         tc_error("plug-in initialization failed");
2717 
2718     // start socket stuff
2719     if (socket_file)
2720         if (!tc_socket_init(socket_file))
2721             tc_error("failed to initialize socket handler");
2722 
2723     // now we start the signal handler thread
2724     if (pthread_create(&event_thread_id, NULL, event_thread, &sigs_to_block) != 0)
2725         tc_error("failed to start signal handler thread");
2726 
2727 
2728     // start frame processing threads
2729     tc_frame_threads_init(vob, max_frame_threads, max_frame_threads);
2730 
2731 
2732     /* ------------------------------------------------------------
2733      *
2734      * transcoder core modes
2735      *
2736      * ------------------------------------------------------------*/
2737 
2738     switch (core_mode) {
2739       case TC_MODE_DEFAULT:
2740         transcode_mode_default(vob);
2741         break;
2742 
2743       case TC_MODE_AVI_SPLIT:
2744         transcode_mode_avi_split(vob);
2745         break;
2746 
2747       case TC_MODE_PSU:
2748         transcode_mode_psu(vob, psubase);
2749         break;
2750 
2751       case TC_MODE_DIRECTORY:
2752         transcode_mode_directory(vob);
2753         break;
2754 
2755       case TC_MODE_DVD_CHAPTER:
2756         transcode_mode_dvd(vob);
2757         break;
2758 
2759       case TC_MODE_DEBUG:
2760         /* FIXME: get rid of this? */
2761         tc_log_msg(PACKAGE, "debug \"core\" mode");
2762         break;
2763 
2764       default:
2765         //should not get here:
2766         tc_error("internal error");
2767     }
2768 
2769     /* ------------------------------------------------------------
2770      * shutdown transcode, all cores modes end up here, core modes
2771      * must take care of proper import/export API shutdown.
2772      *
2773      * 1) stop and cancel frame processing threads
2774      * 2) unload all external modules
2775      * 3) cancel internal signal/server thread
2776      * ------------------------------------------------------------*/
2777 
2778     // turn counter off
2779     counter_off();
2780 
2781     SHUTDOWN_MARK("clean up");
2782 
2783     // stop and cancel frame processing threads
2784     tc_frame_threads_close();
2785     SHUTDOWN_MARK("frame threads");
2786 
2787     // unload all external modules
2788     transcode_fini(NULL);
2789     SHUTDOWN_MARK("unload modules");
2790 
2791     // cancel no longer used internal signal handler threads
2792     if (event_thread_id) {
2793         SHUTDOWN_MARK("cancel signal");
2794         stop_event_thread();
2795         event_thread_id = (pthread_t)0;
2796     }
2797 
2798     SHUTDOWN_MARK("internal threads");
2799 
2800     // shut down control socket, if active
2801     tc_socket_fini();
2802     SHUTDOWN_MARK("control socket");
2803 
2804     // all done
2805     if (verbose & TC_DEBUG)
2806         fprintf(stderr, " done\n");
2807 
2808  summary:
2809     // print a summary
2810     if ((verbose & TC_INFO) && vob->clip_count)
2811         tc_log_info(PACKAGE, "clipped %d audio samples",
2812                     vob->clip_count/2);
2813 
2814     if (verbose & TC_INFO) {
2815         long drop = - tc_get_frames_dropped();
2816 
2817         tc_log_info(PACKAGE, "encoded %ld frames (%ld dropped, %ld cloned),"
2818                             " clip length %6.2f s",
2819                     (long)tc_get_frames_encoded(), drop,
2820                     (long)tc_get_frames_cloned(),
2821                     tc_get_frames_encoded()/vob->ex_fps);
2822     }
2823 
2824 #ifdef STATBUFFER
2825     // free buffers
2826     vframe_free();
2827     aframe_free();
2828     if(verbose & TC_DEBUG)
2829         tc_log_msg(PACKAGE, "buffer released");
2830 #endif
2831 
2832     teardown_input_sources(vob);
2833 
2834     if (vob)
2835         tc_free(vob);
2836 
2837     //exit at last
2838     if (tc_interrupted())
2839         return 127;
2840     return 0;
2841 }
2842 
2843 // this Code below here _never_ gets called.
2844 // it is just there to trick the linker to not remove
2845 // unneeded object files from a .a file.
2846 
2847 #include "libtc/static_tclist.h"
2848 #include "libtc/static_optstr.h"
2849 #include "libtc/static_tctimer.h"
2850 #include "avilib/static_avilib.h"
2851 #include "avilib/static_wavlib.h"
2852 
2853 /*************************************************************************/
2854 
2855 /*
2856  * Local variables:
2857  *   c-file-style: "stroustrup"
2858  *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
2859  *   indent-tabs-mode: nil
2860  * End:
2861  *
2862  * vim: expandtab shiftwidth=4:
2863  */
2864