1 /*
2  * probe.c - probe input file for parameters
3  * Written by Andrew Church <achurch@achurch.org>
4  *
5  * This file is part of transcode, a video stream processing tool.
6  * transcode is free software, distributable under the terms of the GNU
7  * General Public License (version 2 or later).  See the file COPYING
8  * for details.
9  */
10 
11 #include "transcode.h"
12 #include "probe.h"
13 #include "libtc/libtc.h"
14 #include "libtc/tccodecs.h"
15 #include "libtc/ratiocodes.h"
16 #include "import/magic.h"
17 
18 #include <sys/wait.h>  // for waitpid()
19 
20 /*************************************************************************/
21 
22 /* Handy macro to check whether the probe flags allow setting of a
23  * particular field (pass the flag name without TC_PROBE_NO_): */
24 #define MAY_SET(flagname)  (!(flags & TC_PROBE_NO_##flagname))
25 
26 /* Internal routine declarations: */
27 
28 static int do_probe(const char *file, const char *nav_seek_file, int title,
29                     int range, int mplayer_flag, int verbose_flag,
30                     ProbeInfo *info_ret);
31 static void select_modules(int flags, vob_t *vob);
32 
33 /*************************************************************************/
34 /*************************************************************************/
35 
36 /* External interfaces */
37 
38 /*************************************************************************/
39 
40 /**
41  * probe_stream_data:  Probe a single source file and store the stream
42  * informations in data structure.
43  *
44  * Parameters:
45  *       file: File name to probe.
46  *      range: Amount of input file to probe, in MB.
47  *       info: Structure to be filled in with probed data.
48  * Return value:
49  *     Nonzero on success, zero on error.
50  * Preconditions:
51  *     info != NULL, range > 0
52  */
probe_stream_data(const char * file,int range,ProbeInfo * info)53 int probe_stream_data(const char *file, int range, ProbeInfo *info)
54 {
55     if (!info || range <= 0) {
56         tc_log_error(PACKAGE, "wrong probing parameters");
57         return 0;
58     }
59 
60     if (!file) {
61         tc_log_warn(PACKAGE, "missing source to probe");
62         memset(info, 0, sizeof(ProbeInfo));
63     } else {
64         if (!do_probe(file, NULL, 0, range, 0,
65                       (verbose >= TC_DEBUG) ? verbose : 0, info)
66         ) {
67             if (verbose & TC_DEBUG) {
68                 tc_log_warn(PACKAGE, "(%s) failed to probe stream '%s'",
69                             __FILE__, file);
70             }
71             return 0;
72         }
73     }
74     return 1;
75 }
76 
77 
78 /**
79  * probe_source:  Probe the given input file(s) and store the results in
80  * the global data structure.
81  *
82  * Parameters:
83  *     vid_file: Video file name, or NULL if none.
84  *     aud_file: Audio file name, or NULL if none.
85  *        range: Amount of input files to probe, in MB.
86  *        flags: Flags indicating which global parameters should be left
87  *               alone (TC_PROBE_NO_xxx flags).
88  *          vob: Pointer to global data structure.
89  * Return value:
90  *     Nonzero on success, zero on error.
91  * Preconditions:
92  *     vob != NULL
93  */
94 
probe_source(const char * vid_file,const char * aud_file,int range,int flags,vob_t * vob)95 int probe_source(const char *vid_file, const char *aud_file, int range,
96                  int flags, vob_t *vob)
97 {
98     ProbeInfo vinfo, ainfo;  // video and audio info structures
99 
100     /* Probe the video file, if present */
101     if (vid_file) {
102         if (!do_probe(vid_file, vob->nav_seek_file, vob->dvd_title, range,
103                       (flags & TC_PROBE_NO_BUILTIN),
104                       (verbose >= TC_DEBUG) ? verbose : 0, &vinfo)
105         ) {
106             if (verbose & TC_DEBUG) {
107                 tc_log_warn(PACKAGE, "(%s) failed to probe video source",
108                             __FILE__);
109             }
110             return 0;
111         }
112     } else {
113         vob->has_video = 0;
114     }
115 
116     /* Probe the audio file, if present */
117     if (aud_file) {
118         if (!do_probe(aud_file, vob->nav_seek_file, vob->dvd_title, range,
119                       (flags & TC_PROBE_NO_BUILTIN),
120                       (verbose >= TC_DEBUG) ? verbose : 0, &ainfo)
121         ) {
122             if (verbose & TC_DEBUG) {
123                 tc_log_warn(PACKAGE, "(%s) failed to probe audio source",
124                             __FILE__);
125             }
126             return 0;
127         }
128     }  /* else it might be contained in the video file */
129 
130     /* Set global parameters based on probed data */
131     probe_to_vob(vid_file ? &vinfo : NULL, aud_file ? &ainfo : NULL,
132                  flags, vob);
133     if (verbose & TC_DEBUG) {
134         tc_log_info(PACKAGE, "(%s) V magic=0x%lx, A magic=0x%lx,"
135                     " V codec=0x%lx, A codec=0x%lx", __FILE__,
136                     vob->v_format_flag, vob->a_format_flag,
137                     vob->v_codec_flag, vob->a_codec_flag);
138         tc_log_info(PACKAGE, "(%s) V magic=%s, A magic=%s, V codec=%s,"
139                     " A codec=%s", __FILE__,
140                     mformat2str(vob->v_format_flag),
141                     mformat2str(vob->a_format_flag),
142                     tc_codec_to_comment(vob->v_codec_flag),
143                     tc_codec_to_comment(vob->a_codec_flag));
144     }
145 
146     /* All done, return success */
147     return 1;
148 }
149 
150 /*************************************************************************/
151 
152 /**
153  * probe_source_xml:  Probe video or audio parameters from an XML file as
154  * specified by the vob_t data structure.
155  *
156  * Parameters:
157  *       vob: Global vob_t data structure.
158  *     which: PROBE_XML_VIDEO or PROBE_XML_AUDIO.
159  * Return value:
160  *     Nonzero on success, zero on error.
161  * Side effects:
162  *     Prints an error message on error.
163  */
164 
165 /* FIXME: is this the right place for these? */
166 
probe_source_xml(vob_t * vob,int which)167 int probe_source_xml(vob_t *vob, int which)
168 {
169     int retval = 1;
170 #ifdef HAVE_LIBXML2
171     int tochild[2], fromchild[2];  /* pipes */
172     pid_t pid;
173     int resize;
174 
175     if (pipe(tochild) == -1) {
176         tc_log_perror(PACKAGE, "probe_source_xml(): pipe(tochild) failed");
177         return 0;
178     }
179     if (pipe(fromchild) == -1) {
180         tc_log_perror(PACKAGE, "probe_source_xml(): pipe(fromchild) failed");
181         close(tochild[0]);
182         close(tochild[1]);
183         return 0;
184     }
185     pid = fork();
186     if (pid == -1) {
187         tc_log_perror(PACKAGE, "probe_source_xml(): fork failed");
188         return 0;
189     } else if (pid > 0) {
190         /* Child process */
191         const char *new_argv[6];
192         close(tochild[1]);
193         close(fromchild[0]);
194         if (tochild[0] != 0) {
195             if (dup2(tochild[0], 0) == -1) {
196                 tc_log_perror(PACKAGE, "probe_source_xml(): dup2(0) failed");
197                 exit(-1);
198             }
199             close(tochild[0]);
200         }
201         if (fromchild[1] != 1) {  // theoretically always true, but JIC
202             if (dup2(fromchild[1], 1) == -1) {
203                 tc_log_perror(PACKAGE, "probe_source_xml(): dup2(1) failed");
204                 exit(-1);
205             }
206             close(fromchild[1]);
207         }
208         new_argv[0] = "tcxmlcheck";
209         new_argv[1] = "-i";
210         new_argv[2] = vob->video_in_file;
211         new_argv[3] = "-B";
212         new_argv[4] = (which==PROBE_XML_VIDEO ? "-V" : "-A");
213         new_argv[5] = NULL;
214         execvp("tcxmlcheck", (char **)new_argv);
215         tc_log_perror(PACKAGE, "probe_source_xml(): exec(tcxmlcheck) failed");
216         exit(-1);
217     }
218     /* Parent process */
219     retval = 0;
220     close(tochild[0]);
221     close(fromchild[1]);
222     if (write(tochild[1], vob, sizeof(vob_t)) != sizeof(vob_t)) {
223         tc_log_error(PACKAGE, "Error writing data to tcxmlcheck: %s",
224                      strerror(errno));
225         close(tochild[1]);
226         close(fromchild[0]);
227         /* Can't just return--need to reap the child */
228         goto reapchild;
229     }
230     close(tochild[1]);
231     if (read(fromchild[0], vob, sizeof(vob_t)) != sizeof(vob_t)) {
232         tc_log_error(PACKAGE, "Error reading data from tcxmlcheck");
233         close(fromchild[0]);
234         goto reapchild;
235     }
236     if (read(fromchild[0], &resize, sizeof(int)) != sizeof(int)) {
237 	tc_log_error(PACKAGE, "Error reading data from tcxmlcheck 2");
238         close(fromchild[0]);
239         goto reapchild;
240     }
241     close(fromchild[0]);
242     if (which == PROBE_XML_VIDEO && resize == 2) {
243         // XML forced resize, clear command line parameters
244         resize1 = TC_FALSE;
245         resize2 = TC_FALSE;
246         zoom = TC_FALSE;
247         vob->resize1_mult = 32;
248         vob->vert_resize1 = 0;
249         vob->hori_resize1 = 0;
250         vob->resize2_mult = 32;
251         vob->vert_resize2 = 0;
252         vob->hori_resize2 = 0;
253         vob->zoom_width   = 0;
254         vob->zoom_height  = 0;
255         vob->zoom_filter  = TCV_ZOOM_LANCZOS3;
256     }
257     retval = 1;
258 
259   reapchild:  // clean up after the child process
260     waitpid(pid, NULL, 0);
261 #endif  // HAVE_LIBXML2
262 
263     return retval;
264 }
265 
266 /*************************************************************************/
267 
268 /**
269  * mformat2str:  Return a descriptive
270  * string for the given video format flag.
271  *
272  * Parameters:
273  *     flag: Flag to return string for.
274  * Return value:
275  *     String describing `flag'.
276  */
277 
278 
mformat2str(int flag)279 const char *mformat2str(int flag)
280 {
281     switch (flag) {
282         case TC_MAGIC_PAL:       return "PAL";
283         case TC_MAGIC_NTSC:      return "NTSC";
284         case TC_MAGIC_TS:        return "MPEG transport stream";
285         case TC_MAGIC_YUV4MPEG:  return "YUV4MPEG";
286         case TC_MAGIC_NUV:       return "NuppelVideo";
287         case TC_MAGIC_DVD_PAL:   return "DVD PAL";
288         case TC_MAGIC_DVD_NTSC:  return "DVD NTSC";
289         case TC_MAGIC_AVI:       return "RIFF data, AVI";
290         case TC_MAGIC_MOV:       return "QuickTime";
291         case TC_MAGIC_XML:       return "XML file";
292         case TC_MAGIC_TIFF1:     return "TIFF image";
293         case TC_MAGIC_TIFF2:     return "TIFF image";
294         case TC_MAGIC_JPEG:      return "JPEG image";
295         case TC_MAGIC_BMP:       return "BMP image";
296         case TC_MAGIC_PNG:       return "PNG image";
297         case TC_MAGIC_GIF:       return "GIF image";
298         case TC_MAGIC_PPM:       return "PPM image";
299         case TC_MAGIC_PGM:       return "PGM image";
300         case TC_MAGIC_CDXA:      return "RIFF data, CDXA";
301         case TC_MAGIC_AC3:       return "AC3";
302         case TC_MAGIC_MP3:       return "MP3";
303         case TC_MAGIC_MP2:       return "MP2";
304         case TC_MAGIC_OGG:       return "OGG stream";
305         case TC_MAGIC_WAV:       return "RIFF data, WAVE";
306         case TC_MAGIC_V4L_VIDEO: return "V4L,video";
307         case TC_MAGIC_V4L_AUDIO: return "V4L,audio";
308         case TC_MAGIC_PVN:       return "PVN video";
309     }
310     return "";
311 }
312 
313 /*************************************************************************/
314 /*************************************************************************/
315 
316 /* Internal routines */
317 
318 /*************************************************************************/
319 
320 /**
321  * do_probe:  Perform the actual probing of the source file.
322  *
323  * Parameters:
324  *              file: Filename to probe.
325  *     nav_seek_file: Navigation file for `file', or NULL if none.
326  *             title: Title to probe for DVD probing.
327  *             range: Amount of file to probe, in MB.
328  *      mplayer_flag: If nonzero, use mplayer to probe file.
329  *      verbose_flag: Verbosity flag to pass to tcprobe.
330  *          info_ret: Structure to be filled in with probed data.
331  * Return value:
332  *     Nonzero on success, zero on failure.
333  * Preconditions:
334  *     file != NULL
335  */
336 
do_probe(const char * file,const char * nav_seek_file,int title,int range,int mplayer_flag,int verbose_flag,ProbeInfo * info_ret)337 static int do_probe(const char *file, const char *nav_seek_file, int title,
338                     int range, int mplayer_flag, int verbose_flag,
339                     ProbeInfo *info_ret)
340 {
341     char cmdbuf[PATH_MAX+1000];
342     FILE *pipe;
343 
344     if (mplayer_flag) {
345 	if (tc_snprintf(cmdbuf, sizeof(cmdbuf),
346 			"tcprobe -B -M -i \"%s\" -d %d",
347 			file, verbose_flag) < 0)
348 	    return 0;
349     } else {
350 	if (tc_snprintf(cmdbuf, sizeof(cmdbuf),
351 			"tcprobe -B -i \"%s\" -T %d -H %d -d %d",
352 			file, title, range, verbose_flag) < 0)
353 	    return 0;
354         if (nav_seek_file
355          && tc_snprintf(cmdbuf+strlen(cmdbuf), sizeof(cmdbuf)-strlen(cmdbuf),
356                         " -f \"%s\"", nav_seek_file) < 0)
357             return 0;
358     }
359     pipe = popen(cmdbuf, "r");
360     if (!pipe)
361 	return 0;
362     if (fread(&tc_probe_pid, sizeof(pid_t), 1, pipe) != 1) {
363         pclose(pipe);
364 	return 0;
365     }
366     if (fread(info_ret, sizeof(*info_ret), 1, pipe) != 1) {
367         pclose(pipe);
368 	return 0;
369     }
370     pclose(pipe);
371     return 1;
372 }
373 
374 /*************************************************************************/
375 
376 /**
377  * probe_to_vob:  Use the results of probing the input files to set global
378  * parameters.
379  *
380  * Parameters:
381  *     vinfo: Pointer to probe results for video file, or NULL if no video
382  *            file.
383  *     ainfo: Pointer to probe results for audio file, or NULL if no audio
384  *            file.
385  *     flags: TC_PROBE_NO_xxx flags.
386  *       vob: Pointer to global data structure.
387  * Return value:
388  *     None.
389  * Preconditions:
390  *     vob != NULL
391  */
392 
probe_to_vob(ProbeInfo * vinfo,ProbeInfo * ainfo,int flags,vob_t * vob)393 void probe_to_vob(ProbeInfo *vinfo, ProbeInfo *ainfo, int flags, vob_t *vob)
394 {
395     int track;  // user-selected audio track, sanity-checked
396 
397     track = vob->a_track;
398     if (track < 0 || track >= TC_MAX_AUD_TRACKS)
399         track = 0;
400 
401     if (vinfo) {
402         int D_arg, D_arg_ms;  // for setting A/V sync
403 
404         /* Set frame size */
405         if (MAY_SET(FRAMESIZE)) {
406             if (vinfo->width > 0)
407                 vob->im_v_width = vinfo->width;
408             if (vinfo->height > 0)
409                 vob->im_v_height = vinfo->height;
410         }
411 
412         /* Set frame rate */
413         if (MAY_SET(FPS)) {
414             if (vinfo->frc > 0) {
415                 vob->im_frc = vinfo->frc;
416                 tc_frc_code_to_value(vob->im_frc, &vob->fps);
417             } else if (vinfo->fps > 0)
418                 vob->fps = vinfo->fps;
419         }
420 
421         /* Set aspect ratio */
422         if (MAY_SET(IMASR)) {
423             if (vinfo->asr > 0)
424                 vob->im_asr = vinfo->asr;
425         }
426 
427         /* Set additional attributes */
428         if (vinfo->attributes)
429             vob->attributes = vinfo->attributes;
430 
431         /* Clear demux sync flag if appropriate */
432         if (MAY_SET(DEMUX) && (vob->attributes & TC_INFO_NO_DEMUX)) {
433             vob->demuxer = 0;
434         }
435 
436         /* Calculate A/V sync correction */
437         if (vinfo->pts_start > 0 && vinfo->track[track].pts_start > 0) {
438             double pts_diff = vinfo->pts_start - vinfo->track[track].pts_start;
439             D_arg = (int)(vob->fps * pts_diff);
440             D_arg_ms = (int)((pts_diff - D_arg/vob->fps) * 1000);
441         } else {
442             D_arg = 0;
443             D_arg_ms = 0;
444         }
445         /* This voodoo to determine whether to set the A/V sync parameters
446          * is from the original probe.c, with the following comments:
447          *    - case 1: demuxer disabled needs PTS sync mode
448          *    - case 2: check if PTS of requested audio track requires
449          *              video frame dropping
450          *              vob->demuxer>0 and audio_pts > video_pts
451          *    - case 3: fully PTS based sync modes requested
452          */
453         if ((MAY_SET(DEMUX) && (vob->attributes & TC_INFO_NO_DEMUX))
454          || (MAY_SET(DEMUX) && (vinfo->pts_start < vinfo->track[track].pts_start))
455          || (vob->demuxer == 3 || vob->demuxer == 4)
456         ) {
457             if (MAY_SET(AVSHIFT))
458                 vob->sync = D_arg;
459             if (MAY_SET(AV_FINE))
460                 vob->sync_ms = D_arg_ms;
461         }
462 
463         /* Set starting presentation unit */
464         if (MAY_SET(SEEK)) {
465             if (vinfo->unit_cnt > 0)
466                 vob->ps_unit = vinfo->unit_cnt;
467         }
468 
469         /* Set format/codec flags and miscellaneous fields */
470         if (vinfo->magic)
471             vob->v_format_flag = vinfo->magic;
472         if (vinfo->codec)
473             vob->v_codec_flag = vinfo->codec;
474         vob->pts_start = vinfo->pts_start;
475 
476         /* If the width or height are 0, assume no video was detected
477          * (FIXME: what about -g?) */
478         if (vinfo->width == 0 || vinfo->height == 0)
479             vob->has_video = 0;
480 
481         /* If no separate audio file was found, use the video file for
482          * audio processing */
483         if (!ainfo)
484             ainfo = vinfo;
485 
486     }  // if (vinfo)
487 
488     if (ainfo) {
489 
490         /* Set audio format parameters */
491         if (MAY_SET(RATE)) {
492             if (ainfo->track[track].samplerate > 0)
493                 vob->a_rate = ainfo->track[track].samplerate;
494         }
495         if (MAY_SET(BITS)) {
496             if (ainfo->track[track].bits > 0)
497                 vob->a_bits = ainfo->track[track].bits;
498         }
499         if (MAY_SET(CHAN)) {
500             if (ainfo->track[track].chan > 0)
501                 vob->a_chan = ainfo->track[track].chan;
502         }
503 
504         /* Set audio codec, if not set by user */
505         if (MAY_SET(ACODEC)) {
506             if (ainfo->track[track].format > 0)
507                 vob->a_codec_flag = ainfo->track[track].format;
508         }
509 
510         /* Set format flag and miscellaneous fields */
511         if (ainfo->magic)
512             vob->a_format_flag = ainfo->magic;
513         if (ainfo->track[track].bitrate > 0)
514             vob->a_stream_bitrate = ainfo->track[track].bitrate;
515         if (ainfo->track[track].padrate > 0)
516             vob->a_padrate = ainfo->track[track].padrate;
517         if (ainfo->track[track].lang > 0)
518             vob->lang_code = ainfo->track[track].lang;
519 
520         /* See if audio was detected */
521         if (ainfo->num_tracks == 0)
522             vob->has_audio = 0;
523         if (ainfo->track[track].format == CODEC_NULL)
524             vob->has_audio_track = 0;
525 
526         /* Set video format/codec fields as well if no video present */
527         if (!vinfo) {
528             if (ainfo->magic)
529                 vob->v_format_flag = ainfo->magic;
530             if (ainfo->codec)
531                 vob->v_codec_flag = ainfo->codec;
532         }
533 
534     }  // if (ainfo)
535 
536     /* Make note of whether the input is an XML file */
537     if (vinfo && vinfo->magic != vinfo->magic_xml)
538         vob->vmod_probed_xml = "xml";
539     else
540         vob->vmod_probed_xml = NULL;
541     if (ainfo && ainfo->magic != ainfo->magic_xml)
542         vob->amod_probed_xml = "xml";
543     else
544         vob->amod_probed_xml = NULL;
545 
546     if (MAY_SET(MODULES)) {
547         /* Select appropriate import modules */
548         select_modules(flags, vob);
549     }
550 }
551 
552 /*************************************************************************/
553 
554 /**
555  * select_modules:  Use the results of probing the input files to set
556  * global parameters.
557  *
558  * Parameters:
559  *     flags: TC_PROBE_NO_xxx flags.
560  *       vob: Pointer to global data structure.
561  * Return value:
562  *     None.
563  * Preconditions:
564  *     vob != NULL
565  */
566 
select_modules(int flags,vob_t * vob)567 static void select_modules(int flags, vob_t *vob)
568 {
569     char *default_amod;
570 
571 
572     vob->vmod_probed = NULL;
573     vob->amod_probed = NULL;
574 
575     /* If no video or audio, use null module */
576     if (!vob->has_video) {
577         vob->vmod_probed = "null";
578         vob->im_v_width = 0;
579         vob->im_v_height = 0;
580     }
581     if (!vob->has_audio) {
582         vob->amod_probed = "null";
583         vob->a_rate = 0;
584         vob->a_chan = 0;
585     }
586 
587     /* Choose a default audio module based on the audio codec */
588     switch (vob->a_codec_flag) {
589         case CODEC_MP2:    default_amod = "mp3";  break;
590         case CODEC_MP3:    default_amod = "mp3";  break;
591         case CODEC_AC3:    default_amod = "ac3";  break;
592         case CODEC_PCM:    default_amod = "raw";  break;
593         case CODEC_VORBIS: default_amod = "ogg";  break;
594         case CODEC_VAG:    default_amod = "vag";  break;
595         default:           default_amod = "null"; break;
596     }
597 
598     /* Choose modules based on file format */
599 
600     switch (vob->v_format_flag) {
601 
602       case TC_MAGIC_MPLAYER:
603         vob->vmod_probed = "mplayer";
604         vob->amod_probed = "mplayer";
605         break;
606 
607       case TC_MAGIC_V4L_VIDEO:
608         vob->vmod_probed = "v4l";
609         if (MAY_SET(FRAMESIZE)) {
610             vob->im_v_width  = PAL_W/2;
611             vob->im_v_height = PAL_H/2;
612             if (vob->im_v_codec != CODEC_RGB)
613                 vob->im_v_width &= -16;
614         }
615         break;
616 
617       case TC_MAGIC_V4L2_VIDEO:
618         vob->vmod_probed = "v4l2";
619         vob->amod_probed = "v4l2";
620         if (MAY_SET(FRAMESIZE)) {
621             vob->im_v_width  = PAL_W/2;
622             vob->im_v_height = PAL_H/2;
623             if (vob->im_v_codec != CODEC_RGB)
624                 vob->im_v_width &= -16;
625         }
626         break;
627 
628       case TC_MAGIC_BKTR_VIDEO:
629         vob->vmod_probed = "bktr";
630         if (MAY_SET(FRAMESIZE) && !(vob->im_v_width>0 && vob->im_v_height>0)) {
631             vob->im_v_width  = PAL_W/2;
632             vob->im_v_height = PAL_H/2;
633             if (vob->im_v_codec != CODEC_RGB)
634                 vob->im_v_width &= -16;
635         }
636         break;
637 
638       case TC_MAGIC_YUV4MPEG:
639         vob->vmod_probed = "yuv4mpeg";
640         break;
641 
642       case TC_MAGIC_BSDAV:
643         vob->vmod_probed = "bsdav";
644         break;
645 
646       case TC_MAGIC_NUV:
647         vob->vmod_probed = "nuv";
648         vob->amod_probed = "nuv";
649         break;
650 
651       case TC_MAGIC_OGG:
652         vob->vmod_probed = "ogg";
653         vob->amod_probed = "ogg";
654 
655       case TC_MAGIC_DVD_NTSC:
656         if (MAY_SET(DEMUX)) {
657             if (vob->demuxer < 0)
658                 vob->demuxer = 1;
659             /* Activate special handling for 24fps video */
660             if (vob->fps < PAL_FPS && (vob->demuxer==1 || vob->demuxer==3))
661                 vob->demuxer++;
662         }
663         /* Fall through to common DVD handling */
664       case TC_MAGIC_DVD_PAL:
665         vob->vmod_probed = "dvd";
666         vob->amod_probed = "dvd";
667         break;
668 
669       case TC_MAGIC_AVI:
670         if (vob->pass_flag & TC_VIDEO)
671             vob->vmod_probed = "avi";
672         break;
673 
674       case TC_MAGIC_MOV:
675         vob->vmod_probed = "mov";
676         break;
677 
678       case TC_MAGIC_TS:
679         vob->vmod_probed = "ts";
680 
681       case TC_MAGIC_TIFF1:
682       case TC_MAGIC_TIFF2:
683       case TC_MAGIC_JPEG:
684       case TC_MAGIC_PPM:
685       case TC_MAGIC_PGM:
686       case TC_MAGIC_BMP:
687       case TC_MAGIC_PNG:
688       case TC_MAGIC_GIF:
689       case TC_MAGIC_SGI:
690         vob->vmod_probed = "im";
691         break;
692 
693       case TC_MAGIC_DV_NTSC:
694       case TC_MAGIC_DV_PAL:
695         if (vob->pass_flag & TC_VIDEO)
696             vob->vmod_probed = "dv";
697         break;
698 
699       case TC_MAGIC_CDXA:
700         vob->vmod_probed = "vob";
701         vob->amod_probed = "vob";
702         break;
703 
704       case TC_MAGIC_MP3:
705         vob->amod_probed = "mp3";
706         break;
707 
708       case TC_MAGIC_AC3:
709         vob->amod_probed = "ac3";
710         break;
711 
712       case TC_MAGIC_PV3:
713         vob->vmod_probed = "pv3";
714         vob->amod_probed = "pv3";  // really just BE raw after demuxing
715         break;
716 
717       case TC_MAGIC_PVN:
718         vob->vmod_probed = "pvn";
719         break;
720 
721       case TC_MAGIC_X11:
722         vob->vmod_probed = "x11";
723         break;
724 
725     }  // switch (vob->v_format_flag)
726 
727     switch (vob->a_format_flag) {
728         case TC_MAGIC_V4L_AUDIO:   vob->amod_probed = "v4l";   break;
729         case TC_MAGIC_V4L2_AUDIO:  vob->amod_probed = "v4l2";  break;
730         case TC_MAGIC_SUNAU_AUDIO: vob->amod_probed = "sunau"; break;
731         case TC_MAGIC_BSDAV:       vob->amod_probed = "bsdav"; break;
732         case TC_MAGIC_WAV:         vob->amod_probed = "raw";   break;
733         case TC_MAGIC_MOV:         vob->amod_probed = "mov";   break;
734         case TC_MAGIC_TS:          vob->amod_probed = "ts";    break;
735         case TC_MAGIC_MP3:         vob->amod_probed = "mp3";   break;
736         case TC_MAGIC_AC3:         vob->amod_probed = "ac3";   break;
737         case TC_MAGIC_OSS_AUDIO:
738           if (!vob->amod_probed)
739               vob->amod_probed = "oss";
740           break;
741         case TC_MAGIC_AVI:
742           if (vob->pass_flag & TC_AUDIO)
743               vob->amod_probed = "avi";
744           break;
745     }  // switch (vob->a_format_flag)
746 
747     /* Choose modules based on codec */
748     switch (vob->v_codec_flag) {
749 
750       case TC_CODEC_DV:
751         if (!vob->vmod_probed)
752             vob->vmod_probed = "dv";
753         if (!vob->amod_probed) {
754             if (vob->v_format_flag == TC_MAGIC_AVI)
755                 vob->amod_probed = default_amod;
756             else
757                 vob->amod_probed = "dv";
758         }
759         break;
760 
761       case TC_CODEC_MPEG:
762       case TC_CODEC_M2V:
763       case TC_CODEC_MPEG1:
764         if (!vob->vmod_probed)
765             vob->vmod_probed = "mpeg2";
766         if (!vob->amod_probed)
767             vob->amod_probed = default_amod;
768         break;
769 
770       case TC_CODEC_MPEG2:
771         if (!vob->vmod_probed) {
772             vob->vmod_probed = "vob";
773             if (MAY_SET(DEMUX)) {
774                 if (vob->demuxer < 0)
775                     vob->demuxer = 1;
776                 /* Activate special handling for 24fps video */
777                 if (vob->fps < PAL_FPS && (vob->demuxer==1 || vob->demuxer==3))
778                     vob->demuxer++;
779             }
780         }
781         if (!vob->amod_probed)
782             vob->amod_probed = vob->has_audio ? "vob" : "null";
783         break;
784 
785       case TC_CODEC_MJPEG:
786       case TC_CODEC_MPG1:
787       case TC_CODEC_MP42:
788       case TC_CODEC_MP43:
789       case TC_CODEC_RV10:
790       case TC_CODEC_ASV1:
791       case TC_CODEC_ASV2:
792       case TC_CODEC_FFV1:
793       case TC_CODEC_H264:
794         if (!vob->vmod_probed)
795             vob->vmod_probed = "ffmpeg";
796         if (!vob->amod_probed)
797             vob->amod_probed = default_amod;
798         break;
799 
800       case TC_CODEC_LZO1:
801       case TC_CODEC_LZO2:
802         /* Overwrite video import module selected from format */
803         vob->vmod_probed = "lzo";
804         if (!vob->amod_probed)
805             vob->amod_probed = default_amod;
806         break;
807 
808       case TC_CODEC_THEORA:
809         if (vob->v_format_flag != TC_MAGIC_OGG && !vob->vmod_probed)
810             vob->vmod_probed = "mplayer";
811         if (!vob->amod_probed)
812             vob->amod_probed = default_amod;
813         break;
814 
815       case TC_CODEC_DIVX3:
816       case TC_CODEC_DIVX4:
817       case TC_CODEC_DIVX5:
818       case TC_CODEC_XVID:
819         if (vob->v_format_flag != TC_MAGIC_OGG && !vob->vmod_probed)
820             vob->vmod_probed = "ffmpeg";
821         if (!vob->amod_probed)
822             vob->amod_probed = default_amod;
823         break;
824 
825       case TC_CODEC_YUV420P:
826       case TC_CODEC_YUV422P:
827       case TC_CODEC_RGB:
828         if (!vob->vmod_probed)
829             vob->vmod_probed = "raw";
830         if (!vob->amod_probed)
831             vob->amod_probed = default_amod;
832         break;
833 
834     }  // switch (vob->v_codec_flag)
835 
836     /* If still not known, default to the null module */
837     if (!vob->vmod_probed)
838         vob->vmod_probed = "null";
839     if (!vob->amod_probed)
840         vob->amod_probed = "null";
841 
842     /* Set XML import modules */
843     if (!vob->vmod_probed_xml)
844         vob->vmod_probed_xml = vob->vmod_probed;
845     if (!vob->amod_probed_xml)
846         vob->amod_probed_xml = vob->amod_probed;
847 }
848 
849 /*************************************************************************/
850 
851 /*
852  * Local variables:
853  *   c-file-style: "stroustrup"
854  *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
855  *   indent-tabs-mode: nil
856  * End:
857  *
858  * vim: expandtab shiftwidth=4:
859  */
860