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