/* * probe.c - probe input file for parameters * Written by Andrew Church * * This file is part of transcode, a video stream processing tool. * transcode is free software, distributable under the terms of the GNU * General Public License (version 2 or later). See the file COPYING * for details. */ #include "transcode.h" #include "probe.h" #include "libtc/libtc.h" #include "libtc/tccodecs.h" #include "libtc/ratiocodes.h" #include "import/magic.h" #include // for waitpid() /*************************************************************************/ /* Handy macro to check whether the probe flags allow setting of a * particular field (pass the flag name without TC_PROBE_NO_): */ #define MAY_SET(flagname) (!(flags & TC_PROBE_NO_##flagname)) /* Internal routine declarations: */ static int do_probe(const char *file, const char *nav_seek_file, int title, int range, int mplayer_flag, int verbose_flag, ProbeInfo *info_ret); static void select_modules(int flags, vob_t *vob); /*************************************************************************/ /*************************************************************************/ /* External interfaces */ /*************************************************************************/ /** * probe_stream_data: Probe a single source file and store the stream * informations in data structure. * * Parameters: * file: File name to probe. * range: Amount of input file to probe, in MB. * info: Structure to be filled in with probed data. * Return value: * Nonzero on success, zero on error. * Preconditions: * info != NULL, range > 0 */ int probe_stream_data(const char *file, int range, ProbeInfo *info) { if (!info || range <= 0) { tc_log_error(PACKAGE, "wrong probing parameters"); return 0; } if (!file) { tc_log_warn(PACKAGE, "missing source to probe"); memset(info, 0, sizeof(ProbeInfo)); } else { if (!do_probe(file, NULL, 0, range, 0, (verbose >= TC_DEBUG) ? verbose : 0, info) ) { if (verbose & TC_DEBUG) { tc_log_warn(PACKAGE, "(%s) failed to probe stream '%s'", __FILE__, file); } return 0; } } return 1; } /** * probe_source: Probe the given input file(s) and store the results in * the global data structure. * * Parameters: * vid_file: Video file name, or NULL if none. * aud_file: Audio file name, or NULL if none. * range: Amount of input files to probe, in MB. * flags: Flags indicating which global parameters should be left * alone (TC_PROBE_NO_xxx flags). * vob: Pointer to global data structure. * Return value: * Nonzero on success, zero on error. * Preconditions: * vob != NULL */ int probe_source(const char *vid_file, const char *aud_file, int range, int flags, vob_t *vob) { ProbeInfo vinfo, ainfo; // video and audio info structures /* Probe the video file, if present */ if (vid_file) { if (!do_probe(vid_file, vob->nav_seek_file, vob->dvd_title, range, (flags & TC_PROBE_NO_BUILTIN), (verbose >= TC_DEBUG) ? verbose : 0, &vinfo) ) { if (verbose & TC_DEBUG) { tc_log_warn(PACKAGE, "(%s) failed to probe video source", __FILE__); } return 0; } } else { vob->has_video = 0; } /* Probe the audio file, if present */ if (aud_file) { if (!do_probe(aud_file, vob->nav_seek_file, vob->dvd_title, range, (flags & TC_PROBE_NO_BUILTIN), (verbose >= TC_DEBUG) ? verbose : 0, &ainfo) ) { if (verbose & TC_DEBUG) { tc_log_warn(PACKAGE, "(%s) failed to probe audio source", __FILE__); } return 0; } } /* else it might be contained in the video file */ /* Set global parameters based on probed data */ probe_to_vob(vid_file ? &vinfo : NULL, aud_file ? &ainfo : NULL, flags, vob); if (verbose & TC_DEBUG) { tc_log_info(PACKAGE, "(%s) V magic=0x%lx, A magic=0x%lx," " V codec=0x%lx, A codec=0x%lx", __FILE__, vob->v_format_flag, vob->a_format_flag, vob->v_codec_flag, vob->a_codec_flag); tc_log_info(PACKAGE, "(%s) V magic=%s, A magic=%s, V codec=%s," " A codec=%s", __FILE__, mformat2str(vob->v_format_flag), mformat2str(vob->a_format_flag), tc_codec_to_comment(vob->v_codec_flag), tc_codec_to_comment(vob->a_codec_flag)); } /* All done, return success */ return 1; } /*************************************************************************/ /** * probe_source_xml: Probe video or audio parameters from an XML file as * specified by the vob_t data structure. * * Parameters: * vob: Global vob_t data structure. * which: PROBE_XML_VIDEO or PROBE_XML_AUDIO. * Return value: * Nonzero on success, zero on error. * Side effects: * Prints an error message on error. */ /* FIXME: is this the right place for these? */ int probe_source_xml(vob_t *vob, int which) { int retval = 1; #ifdef HAVE_LIBXML2 int tochild[2], fromchild[2]; /* pipes */ pid_t pid; int resize; if (pipe(tochild) == -1) { tc_log_perror(PACKAGE, "probe_source_xml(): pipe(tochild) failed"); return 0; } if (pipe(fromchild) == -1) { tc_log_perror(PACKAGE, "probe_source_xml(): pipe(fromchild) failed"); close(tochild[0]); close(tochild[1]); return 0; } pid = fork(); if (pid == -1) { tc_log_perror(PACKAGE, "probe_source_xml(): fork failed"); return 0; } else if (pid > 0) { /* Child process */ const char *new_argv[6]; close(tochild[1]); close(fromchild[0]); if (tochild[0] != 0) { if (dup2(tochild[0], 0) == -1) { tc_log_perror(PACKAGE, "probe_source_xml(): dup2(0) failed"); exit(-1); } close(tochild[0]); } if (fromchild[1] != 1) { // theoretically always true, but JIC if (dup2(fromchild[1], 1) == -1) { tc_log_perror(PACKAGE, "probe_source_xml(): dup2(1) failed"); exit(-1); } close(fromchild[1]); } new_argv[0] = "tcxmlcheck"; new_argv[1] = "-i"; new_argv[2] = vob->video_in_file; new_argv[3] = "-B"; new_argv[4] = (which==PROBE_XML_VIDEO ? "-V" : "-A"); new_argv[5] = NULL; execvp("tcxmlcheck", (char **)new_argv); tc_log_perror(PACKAGE, "probe_source_xml(): exec(tcxmlcheck) failed"); exit(-1); } /* Parent process */ retval = 0; close(tochild[0]); close(fromchild[1]); if (write(tochild[1], vob, sizeof(vob_t)) != sizeof(vob_t)) { tc_log_error(PACKAGE, "Error writing data to tcxmlcheck: %s", strerror(errno)); close(tochild[1]); close(fromchild[0]); /* Can't just return--need to reap the child */ goto reapchild; } close(tochild[1]); if (read(fromchild[0], vob, sizeof(vob_t)) != sizeof(vob_t)) { tc_log_error(PACKAGE, "Error reading data from tcxmlcheck"); close(fromchild[0]); goto reapchild; } if (read(fromchild[0], &resize, sizeof(int)) != sizeof(int)) { tc_log_error(PACKAGE, "Error reading data from tcxmlcheck 2"); close(fromchild[0]); goto reapchild; } close(fromchild[0]); if (which == PROBE_XML_VIDEO && resize == 2) { // XML forced resize, clear command line parameters resize1 = TC_FALSE; resize2 = TC_FALSE; zoom = TC_FALSE; vob->resize1_mult = 32; vob->vert_resize1 = 0; vob->hori_resize1 = 0; vob->resize2_mult = 32; vob->vert_resize2 = 0; vob->hori_resize2 = 0; vob->zoom_width = 0; vob->zoom_height = 0; vob->zoom_filter = TCV_ZOOM_LANCZOS3; } retval = 1; reapchild: // clean up after the child process waitpid(pid, NULL, 0); #endif // HAVE_LIBXML2 return retval; } /*************************************************************************/ /** * mformat2str: Return a descriptive * string for the given video format flag. * * Parameters: * flag: Flag to return string for. * Return value: * String describing `flag'. */ const char *mformat2str(int flag) { switch (flag) { case TC_MAGIC_PAL: return "PAL"; case TC_MAGIC_NTSC: return "NTSC"; case TC_MAGIC_TS: return "MPEG transport stream"; case TC_MAGIC_YUV4MPEG: return "YUV4MPEG"; case TC_MAGIC_NUV: return "NuppelVideo"; case TC_MAGIC_DVD_PAL: return "DVD PAL"; case TC_MAGIC_DVD_NTSC: return "DVD NTSC"; case TC_MAGIC_AVI: return "RIFF data, AVI"; case TC_MAGIC_MOV: return "QuickTime"; case TC_MAGIC_XML: return "XML file"; case TC_MAGIC_TIFF1: return "TIFF image"; case TC_MAGIC_TIFF2: return "TIFF image"; case TC_MAGIC_JPEG: return "JPEG image"; case TC_MAGIC_BMP: return "BMP image"; case TC_MAGIC_PNG: return "PNG image"; case TC_MAGIC_GIF: return "GIF image"; case TC_MAGIC_PPM: return "PPM image"; case TC_MAGIC_PGM: return "PGM image"; case TC_MAGIC_CDXA: return "RIFF data, CDXA"; case TC_MAGIC_AC3: return "AC3"; case TC_MAGIC_MP3: return "MP3"; case TC_MAGIC_MP2: return "MP2"; case TC_MAGIC_OGG: return "OGG stream"; case TC_MAGIC_WAV: return "RIFF data, WAVE"; case TC_MAGIC_V4L_VIDEO: return "V4L,video"; case TC_MAGIC_V4L_AUDIO: return "V4L,audio"; case TC_MAGIC_PVN: return "PVN video"; } return ""; } /*************************************************************************/ /*************************************************************************/ /* Internal routines */ /*************************************************************************/ /** * do_probe: Perform the actual probing of the source file. * * Parameters: * file: Filename to probe. * nav_seek_file: Navigation file for `file', or NULL if none. * title: Title to probe for DVD probing. * range: Amount of file to probe, in MB. * mplayer_flag: If nonzero, use mplayer to probe file. * verbose_flag: Verbosity flag to pass to tcprobe. * info_ret: Structure to be filled in with probed data. * Return value: * Nonzero on success, zero on failure. * Preconditions: * file != NULL */ static int do_probe(const char *file, const char *nav_seek_file, int title, int range, int mplayer_flag, int verbose_flag, ProbeInfo *info_ret) { char cmdbuf[PATH_MAX+1000]; FILE *pipe; if (mplayer_flag) { if (tc_snprintf(cmdbuf, sizeof(cmdbuf), "tcprobe -B -M -i \"%s\" -d %d", file, verbose_flag) < 0) return 0; } else { if (tc_snprintf(cmdbuf, sizeof(cmdbuf), "tcprobe -B -i \"%s\" -T %d -H %d -d %d", file, title, range, verbose_flag) < 0) return 0; if (nav_seek_file && tc_snprintf(cmdbuf+strlen(cmdbuf), sizeof(cmdbuf)-strlen(cmdbuf), " -f \"%s\"", nav_seek_file) < 0) return 0; } pipe = popen(cmdbuf, "r"); if (!pipe) return 0; if (fread(&tc_probe_pid, sizeof(pid_t), 1, pipe) != 1) { pclose(pipe); return 0; } if (fread(info_ret, sizeof(*info_ret), 1, pipe) != 1) { pclose(pipe); return 0; } pclose(pipe); return 1; } /*************************************************************************/ /** * probe_to_vob: Use the results of probing the input files to set global * parameters. * * Parameters: * vinfo: Pointer to probe results for video file, or NULL if no video * file. * ainfo: Pointer to probe results for audio file, or NULL if no audio * file. * flags: TC_PROBE_NO_xxx flags. * vob: Pointer to global data structure. * Return value: * None. * Preconditions: * vob != NULL */ void probe_to_vob(ProbeInfo *vinfo, ProbeInfo *ainfo, int flags, vob_t *vob) { int track; // user-selected audio track, sanity-checked track = vob->a_track; if (track < 0 || track >= TC_MAX_AUD_TRACKS) track = 0; if (vinfo) { int D_arg, D_arg_ms; // for setting A/V sync /* Set frame size */ if (MAY_SET(FRAMESIZE)) { if (vinfo->width > 0) vob->im_v_width = vinfo->width; if (vinfo->height > 0) vob->im_v_height = vinfo->height; } /* Set frame rate */ if (MAY_SET(FPS)) { if (vinfo->frc > 0) { vob->im_frc = vinfo->frc; tc_frc_code_to_value(vob->im_frc, &vob->fps); } else if (vinfo->fps > 0) vob->fps = vinfo->fps; } /* Set aspect ratio */ if (MAY_SET(IMASR)) { if (vinfo->asr > 0) vob->im_asr = vinfo->asr; } /* Set additional attributes */ if (vinfo->attributes) vob->attributes = vinfo->attributes; /* Clear demux sync flag if appropriate */ if (MAY_SET(DEMUX) && (vob->attributes & TC_INFO_NO_DEMUX)) { vob->demuxer = 0; } /* Calculate A/V sync correction */ if (vinfo->pts_start > 0 && vinfo->track[track].pts_start > 0) { double pts_diff = vinfo->pts_start - vinfo->track[track].pts_start; D_arg = (int)(vob->fps * pts_diff); D_arg_ms = (int)((pts_diff - D_arg/vob->fps) * 1000); } else { D_arg = 0; D_arg_ms = 0; } /* This voodoo to determine whether to set the A/V sync parameters * is from the original probe.c, with the following comments: * - case 1: demuxer disabled needs PTS sync mode * - case 2: check if PTS of requested audio track requires * video frame dropping * vob->demuxer>0 and audio_pts > video_pts * - case 3: fully PTS based sync modes requested */ if ((MAY_SET(DEMUX) && (vob->attributes & TC_INFO_NO_DEMUX)) || (MAY_SET(DEMUX) && (vinfo->pts_start < vinfo->track[track].pts_start)) || (vob->demuxer == 3 || vob->demuxer == 4) ) { if (MAY_SET(AVSHIFT)) vob->sync = D_arg; if (MAY_SET(AV_FINE)) vob->sync_ms = D_arg_ms; } /* Set starting presentation unit */ if (MAY_SET(SEEK)) { if (vinfo->unit_cnt > 0) vob->ps_unit = vinfo->unit_cnt; } /* Set format/codec flags and miscellaneous fields */ if (vinfo->magic) vob->v_format_flag = vinfo->magic; if (vinfo->codec) vob->v_codec_flag = vinfo->codec; vob->pts_start = vinfo->pts_start; /* If the width or height are 0, assume no video was detected * (FIXME: what about -g?) */ if (vinfo->width == 0 || vinfo->height == 0) vob->has_video = 0; /* If no separate audio file was found, use the video file for * audio processing */ if (!ainfo) ainfo = vinfo; } // if (vinfo) if (ainfo) { /* Set audio format parameters */ if (MAY_SET(RATE)) { if (ainfo->track[track].samplerate > 0) vob->a_rate = ainfo->track[track].samplerate; } if (MAY_SET(BITS)) { if (ainfo->track[track].bits > 0) vob->a_bits = ainfo->track[track].bits; } if (MAY_SET(CHAN)) { if (ainfo->track[track].chan > 0) vob->a_chan = ainfo->track[track].chan; } /* Set audio codec, if not set by user */ if (MAY_SET(ACODEC)) { if (ainfo->track[track].format > 0) vob->a_codec_flag = ainfo->track[track].format; } /* Set format flag and miscellaneous fields */ if (ainfo->magic) vob->a_format_flag = ainfo->magic; if (ainfo->track[track].bitrate > 0) vob->a_stream_bitrate = ainfo->track[track].bitrate; if (ainfo->track[track].padrate > 0) vob->a_padrate = ainfo->track[track].padrate; if (ainfo->track[track].lang > 0) vob->lang_code = ainfo->track[track].lang; /* See if audio was detected */ if (ainfo->num_tracks == 0) vob->has_audio = 0; if (ainfo->track[track].format == CODEC_NULL) vob->has_audio_track = 0; /* Set video format/codec fields as well if no video present */ if (!vinfo) { if (ainfo->magic) vob->v_format_flag = ainfo->magic; if (ainfo->codec) vob->v_codec_flag = ainfo->codec; } } // if (ainfo) /* Make note of whether the input is an XML file */ if (vinfo && vinfo->magic != vinfo->magic_xml) vob->vmod_probed_xml = "xml"; else vob->vmod_probed_xml = NULL; if (ainfo && ainfo->magic != ainfo->magic_xml) vob->amod_probed_xml = "xml"; else vob->amod_probed_xml = NULL; if (MAY_SET(MODULES)) { /* Select appropriate import modules */ select_modules(flags, vob); } } /*************************************************************************/ /** * select_modules: Use the results of probing the input files to set * global parameters. * * Parameters: * flags: TC_PROBE_NO_xxx flags. * vob: Pointer to global data structure. * Return value: * None. * Preconditions: * vob != NULL */ static void select_modules(int flags, vob_t *vob) { char *default_amod; vob->vmod_probed = NULL; vob->amod_probed = NULL; /* If no video or audio, use null module */ if (!vob->has_video) { vob->vmod_probed = "null"; vob->im_v_width = 0; vob->im_v_height = 0; } if (!vob->has_audio) { vob->amod_probed = "null"; vob->a_rate = 0; vob->a_chan = 0; } /* Choose a default audio module based on the audio codec */ switch (vob->a_codec_flag) { case CODEC_MP2: default_amod = "mp3"; break; case CODEC_MP3: default_amod = "mp3"; break; case CODEC_AC3: default_amod = "ac3"; break; case CODEC_PCM: default_amod = "raw"; break; case CODEC_VORBIS: default_amod = "ogg"; break; case CODEC_VAG: default_amod = "vag"; break; default: default_amod = "null"; break; } /* Choose modules based on file format */ switch (vob->v_format_flag) { case TC_MAGIC_MPLAYER: vob->vmod_probed = "mplayer"; vob->amod_probed = "mplayer"; break; case TC_MAGIC_V4L_VIDEO: vob->vmod_probed = "v4l"; if (MAY_SET(FRAMESIZE)) { vob->im_v_width = PAL_W/2; vob->im_v_height = PAL_H/2; if (vob->im_v_codec != CODEC_RGB) vob->im_v_width &= -16; } break; case TC_MAGIC_V4L2_VIDEO: vob->vmod_probed = "v4l2"; vob->amod_probed = "v4l2"; if (MAY_SET(FRAMESIZE)) { vob->im_v_width = PAL_W/2; vob->im_v_height = PAL_H/2; if (vob->im_v_codec != CODEC_RGB) vob->im_v_width &= -16; } break; case TC_MAGIC_BKTR_VIDEO: vob->vmod_probed = "bktr"; if (MAY_SET(FRAMESIZE) && !(vob->im_v_width>0 && vob->im_v_height>0)) { vob->im_v_width = PAL_W/2; vob->im_v_height = PAL_H/2; if (vob->im_v_codec != CODEC_RGB) vob->im_v_width &= -16; } break; case TC_MAGIC_YUV4MPEG: vob->vmod_probed = "yuv4mpeg"; break; case TC_MAGIC_BSDAV: vob->vmod_probed = "bsdav"; break; case TC_MAGIC_NUV: vob->vmod_probed = "nuv"; vob->amod_probed = "nuv"; break; case TC_MAGIC_OGG: vob->vmod_probed = "ogg"; vob->amod_probed = "ogg"; case TC_MAGIC_DVD_NTSC: if (MAY_SET(DEMUX)) { if (vob->demuxer < 0) vob->demuxer = 1; /* Activate special handling for 24fps video */ if (vob->fps < PAL_FPS && (vob->demuxer==1 || vob->demuxer==3)) vob->demuxer++; } /* Fall through to common DVD handling */ case TC_MAGIC_DVD_PAL: vob->vmod_probed = "dvd"; vob->amod_probed = "dvd"; break; case TC_MAGIC_AVI: if (vob->pass_flag & TC_VIDEO) vob->vmod_probed = "avi"; break; case TC_MAGIC_MOV: vob->vmod_probed = "mov"; break; case TC_MAGIC_TS: vob->vmod_probed = "ts"; case TC_MAGIC_TIFF1: case TC_MAGIC_TIFF2: case TC_MAGIC_JPEG: case TC_MAGIC_PPM: case TC_MAGIC_PGM: case TC_MAGIC_BMP: case TC_MAGIC_PNG: case TC_MAGIC_GIF: case TC_MAGIC_SGI: vob->vmod_probed = "im"; break; case TC_MAGIC_DV_NTSC: case TC_MAGIC_DV_PAL: if (vob->pass_flag & TC_VIDEO) vob->vmod_probed = "dv"; break; case TC_MAGIC_CDXA: vob->vmod_probed = "vob"; vob->amod_probed = "vob"; break; case TC_MAGIC_MP3: vob->amod_probed = "mp3"; break; case TC_MAGIC_AC3: vob->amod_probed = "ac3"; break; case TC_MAGIC_PV3: vob->vmod_probed = "pv3"; vob->amod_probed = "pv3"; // really just BE raw after demuxing break; case TC_MAGIC_PVN: vob->vmod_probed = "pvn"; break; case TC_MAGIC_X11: vob->vmod_probed = "x11"; break; } // switch (vob->v_format_flag) switch (vob->a_format_flag) { case TC_MAGIC_V4L_AUDIO: vob->amod_probed = "v4l"; break; case TC_MAGIC_V4L2_AUDIO: vob->amod_probed = "v4l2"; break; case TC_MAGIC_SUNAU_AUDIO: vob->amod_probed = "sunau"; break; case TC_MAGIC_BSDAV: vob->amod_probed = "bsdav"; break; case TC_MAGIC_WAV: vob->amod_probed = "raw"; break; case TC_MAGIC_MOV: vob->amod_probed = "mov"; break; case TC_MAGIC_TS: vob->amod_probed = "ts"; break; case TC_MAGIC_MP3: vob->amod_probed = "mp3"; break; case TC_MAGIC_AC3: vob->amod_probed = "ac3"; break; case TC_MAGIC_OSS_AUDIO: if (!vob->amod_probed) vob->amod_probed = "oss"; break; case TC_MAGIC_AVI: if (vob->pass_flag & TC_AUDIO) vob->amod_probed = "avi"; break; } // switch (vob->a_format_flag) /* Choose modules based on codec */ switch (vob->v_codec_flag) { case TC_CODEC_DV: if (!vob->vmod_probed) vob->vmod_probed = "dv"; if (!vob->amod_probed) { if (vob->v_format_flag == TC_MAGIC_AVI) vob->amod_probed = default_amod; else vob->amod_probed = "dv"; } break; case TC_CODEC_MPEG: case TC_CODEC_M2V: case TC_CODEC_MPEG1: if (!vob->vmod_probed) vob->vmod_probed = "mpeg2"; if (!vob->amod_probed) vob->amod_probed = default_amod; break; case TC_CODEC_MPEG2: if (!vob->vmod_probed) { vob->vmod_probed = "vob"; if (MAY_SET(DEMUX)) { if (vob->demuxer < 0) vob->demuxer = 1; /* Activate special handling for 24fps video */ if (vob->fps < PAL_FPS && (vob->demuxer==1 || vob->demuxer==3)) vob->demuxer++; } } if (!vob->amod_probed) vob->amod_probed = vob->has_audio ? "vob" : "null"; break; case TC_CODEC_MJPEG: case TC_CODEC_MPG1: case TC_CODEC_MP42: case TC_CODEC_MP43: case TC_CODEC_RV10: case TC_CODEC_ASV1: case TC_CODEC_ASV2: case TC_CODEC_FFV1: case TC_CODEC_H264: if (!vob->vmod_probed) vob->vmod_probed = "ffmpeg"; if (!vob->amod_probed) vob->amod_probed = default_amod; break; case TC_CODEC_LZO1: case TC_CODEC_LZO2: /* Overwrite video import module selected from format */ vob->vmod_probed = "lzo"; if (!vob->amod_probed) vob->amod_probed = default_amod; break; case TC_CODEC_THEORA: if (vob->v_format_flag != TC_MAGIC_OGG && !vob->vmod_probed) vob->vmod_probed = "mplayer"; if (!vob->amod_probed) vob->amod_probed = default_amod; break; case TC_CODEC_DIVX3: case TC_CODEC_DIVX4: case TC_CODEC_DIVX5: case TC_CODEC_XVID: if (vob->v_format_flag != TC_MAGIC_OGG && !vob->vmod_probed) vob->vmod_probed = "ffmpeg"; if (!vob->amod_probed) vob->amod_probed = default_amod; break; case TC_CODEC_YUV420P: case TC_CODEC_YUV422P: case TC_CODEC_RGB: if (!vob->vmod_probed) vob->vmod_probed = "raw"; if (!vob->amod_probed) vob->amod_probed = default_amod; break; } // switch (vob->v_codec_flag) /* If still not known, default to the null module */ if (!vob->vmod_probed) vob->vmod_probed = "null"; if (!vob->amod_probed) vob->amod_probed = "null"; /* Set XML import modules */ if (!vob->vmod_probed_xml) vob->vmod_probed_xml = vob->vmod_probed; if (!vob->amod_probed_xml) vob->amod_probed_xml = vob->amod_probed; } /*************************************************************************/ /* * Local variables: * c-file-style: "stroustrup" * c-file-offsets: ((case-label . *) (statement-case-intro . *)) * indent-tabs-mode: nil * End: * * vim: expandtab shiftwidth=4: */