summaryrefslogtreecommitdiffstats
path: root/debian/transcode/transcode-1.1.7/import/tcprobe.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/transcode/transcode-1.1.7/import/tcprobe.c')
-rw-r--r--debian/transcode/transcode-1.1.7/import/tcprobe.c1096
1 files changed, 1096 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/import/tcprobe.c b/debian/transcode/transcode-1.1.7/import/tcprobe.c
new file mode 100644
index 00000000..9334efec
--- /dev/null
+++ b/debian/transcode/transcode-1.1.7/import/tcprobe.c
@@ -0,0 +1,1096 @@
+/*
+ * tcprobe.c
+ *
+ * Copyright (C) Thomas Oestreich - June 2001
+ * updated by
+ * Francesco Romani - April 206
+ *
+ * This file is part of transcode, a video stream processing tool
+ *
+ * transcode is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * transcode is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Make; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "transcode.h"
+#include "tcinfo.h"
+#include "libtc/libtc.h"
+#include "libtc/iodir.h"
+#include "libtc/xio.h"
+#include "libtc/ratiocodes.h"
+#include "ioaux.h"
+#include "tc.h"
+#include "demuxer.h"
+#include "dvd_reader.h"
+#include "x11source.h"
+
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+
+#define EXE "tcprobe"
+
+int verbose = TC_INFO;
+
+int bitrate = ABITRATE;
+int binary_dump = 0;
+
+void import_exit(int code)
+{
+ if (verbose >= TC_DEBUG) {
+ tc_log_msg(EXE, "(pid=%d) exit (code %d)", (int) getpid(), code);
+ }
+ exit(code);
+}
+
+/*************************************************************************/
+
+/*
+ * enc_bitrate: Print bitrate information about the source data.
+ *
+ * Parameters:
+ * frames: Number of frames in the source.
+ * fps: Frames per second of the source.
+ * abitrate: Audio bitrate (bits per second).
+ * discsize: User-specified disc size in bytes, or 0 for none.
+ * Return value:
+ * None.
+ * Notes:
+ * This function is copied from tcscan.c. Ideally, tcprobe should
+ * only print basic source information, and this extended information
+ * should be handled by tcscan (or alternatively, tcscan should be
+ * merged into tcprobe).
+ */
+
+static void enc_bitrate(long frames, double fps, int abitrate, double discsize)
+{
+ static const int defsize[] = { 650, 700, 1300, 1400 };
+ double audiosize, videosize, vbitrate;
+ long time;
+
+ if (frames <= 0 || fps <= 0.0) {
+ return;
+ }
+ time = frames / fps;
+ audiosize = (double)abitrate/8 * time;
+
+ /* Print basic source information */
+ printf("V: %ld frames, %ld sec @ %.3f fps\n",
+ frames, time, fps);
+ printf("A: %.2f MB @ %d kbps\n",
+ audiosize/(1024*1024), abitrate/1000);
+
+ /* Print recommended bitrates for user-specified or default disc sizes */
+ if (discsize) {
+ videosize = discsize - audiosize;
+ vbitrate = videosize / time;
+ printf("USER CDSIZE: %4d MB | V: %6.1f MB @ %.1f kbps\n",
+ (int)floor(discsize/(1024*1024)), videosize/(1024*1024),
+ vbitrate);
+ } else {
+ int i;
+ for (i = 0; i < sizeof(defsize) / sizeof(*defsize); i++) {
+ videosize = defsize[i] - audiosize;
+ vbitrate = videosize / time;
+ printf("USER CDSIZE: %4d MB | V: %6.1f MB @ %.1f kbps\n",
+ defsize[i], videosize/(1024*1024),
+ vbitrate);
+ }
+ }
+}
+
+/*************************************************************************/
+
+/*
+ * we don't want to scan the full directory since it can be a HUGE number
+ * of entries (think to images -> clip transcoding [i.e. jpeg -> AVI])
+ */
+#define TC_SCAN_MAX_FILES 32
+
+/* informations for one stream found in given directory */
+typedef struct tcdirentryinfo_ TCDirEntryInfo;
+struct tcdirentryinfo_ {
+ uint32_t magic;
+ size_t count;
+ /* how many times a file with this magic was found on directory? */
+ int fd;
+ /* file descriptor of the FIRST file encountered with this magic */
+};
+
+/*
+ * tc_entry_find_magic:
+ * find the element in an array of TCDirEntryInfo strucutes
+ * that has it's magic equals to a given magic id.
+ *
+ * Parameters:
+ * info: pointer to an array of TCDirEntryInfo strucutre to be scanned.
+ * size: number of elements in given array.
+ * magic: magic ID to find
+ * Return value:
+ * -1: given magic ID not found on given array.
+ * >=0: index in array of element with same magic ID as given one.
+ */
+static int tc_entry_info_find_magic(const TCDirEntryInfo *infos,
+ size_t size, uint32_t magic)
+{
+ int ret = -1;
+ size_t i = 0;
+
+ if (infos != NULL && size > 0) {
+ for (i = 0; i < size; i++) {
+ if (infos[i].magic == magic) {
+ ret = (int)i;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+/*
+ * tc_entry_find_max_count:
+ * find the element in an array of TCDirEntryInfo strucutes
+ * that has the maximum count value.
+ *
+ * Parameters:
+ * info: pointer to an array of TCDirEntryInfo strucutre to be scanned.
+ * size: number of elements in given array.
+ * Return value:
+ * index in array of element with most high 'count' value.
+ */
+static int tc_entry_info_find_max_count(const TCDirEntryInfo *infos,
+ size_t size)
+{
+ int ret = 0; /* start pointing to first element */
+ size_t i = 0;
+
+ if (infos != NULL && size > 0) {
+ for (i = 1; i < size; i++) {
+ if (infos[i].count > infos[ret].count) {
+ ret = (int)i;
+ }
+ }
+ }
+ return ret;
+}
+
+/*
+ * tc_entry_info_free:
+ * release resources linked to a TCDirEntryInfo structure.
+ *
+ * Parameters:
+ * de: pointer to a TCDirEntryInfo to be released.
+ * Return value:
+ * None
+ */
+static void tc_entry_info_free(TCDirEntryInfo *de)
+{
+ if (de != NULL) {
+ xio_close(de->fd);
+ de->fd = -1;
+ }
+}
+
+/*
+ * tc_scan_directory_info:
+ * Partially scan a given directory and optionally filla TCDirEntryInfo
+ * structure with data about most common stream format found in.
+ *
+ * Partial scanning is done in order to avoid to waste too much
+ * time/resources in scanning phase. Anyway, partial scan ti's supposed
+ * to give results reliable enough.
+ * Filled TCDirEntryInfo structure will have an already open file
+ * descriptor pointing to the first file of the biggest set of files
+ * with the same magic id.
+ *
+ * Use tc_entry_info_free() to release resources acquired using this
+ * function, do not free()/close() things by hand to avoid undefined
+ * behaviours.
+ *
+ * Parameters:
+ * dname: path of dicrectory to scan.
+ * candidate: optional pointer of TCDirEntryInfo structure to be filled.
+ * can safely be NULL.
+ * Return value:
+ * -1: internal error
+ * 0: succesfull, but directory seems to have mixed content
+ * 1: succesfull, and directory seems to have homogeneous content
+ * Side effects:
+ * Some files (first TC_SCAN_MAX_FILES in filesystem order) in directory
+ * are open and scanned to detect their magic number.
+ */
+static int tc_scan_directory_info(const char *dname,
+ TCDirEntryInfo *candidate)
+{
+ TCDirEntryInfo dinfo[TC_SCAN_MAX_FILES];
+ struct dirent *entry = NULL;
+ size_t i = 0, j = 0, last = 0, probed = 0;
+ int ret = -1;
+ DIR *dir = opendir(dname);
+
+ /* base sanity check first */
+ if (dir == NULL) {
+ return -1;
+ }
+
+ /* round one: collect some stuff */
+ for (i = 0; i < TC_SCAN_MAX_FILES; i++) {
+ char path_buf[PATH_MAX + 1];
+ uint32_t magic = TC_MAGIC_UNKNOWN;
+ struct stat stat_buf;
+ int fd = -1, err;
+
+ entry = readdir(dir);
+ if (entry == NULL) {
+ break;
+ }
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
+ /* it's safe to skip them */
+ continue;
+ }
+
+ tc_snprintf(path_buf, sizeof(path_buf), "%s/%s",
+ dname, entry->d_name);
+ err = stat(path_buf, &stat_buf);
+ if (err || !S_ISREG(stat_buf.st_mode)) {
+ if (verbose >= TC_DEBUG) { /* uhm */
+ tc_log_warn(EXE, "opening '%s': is not a file",
+ path_buf);
+ }
+ continue;
+ }
+ fd = xio_open(path_buf, O_RDONLY);
+ if (fd == -1) {
+ /* switch to tc_log_perror? */
+ tc_log_error(EXE, "opening '%s': %s",
+ path_buf, strerror(errno));
+ continue; /* assume non-fatal error */
+ }
+ magic = fileinfo(fd, 0);
+ j = tc_entry_info_find_magic(dinfo, last, magic);
+ if (j != -1) { /* entry already encountered */
+ dinfo[j].count++;
+ xio_close(fd);
+ /* we want only the first file descriptor of a given set */
+ } else {
+ dinfo[last].fd = fd;
+ dinfo[last].magic = magic;
+ dinfo[last].count = 1;
+ last++;
+ }
+ probed++;
+ }
+ closedir(dir);
+
+ /* round two: let's make a choice */
+ if (last > 0) { /* at least one file scanned succesfully */
+ if (last == 1) {
+ j = 0; /* pretty simple, uh? ;) */
+ ret = 1; /* obviously homogeneous */
+ } else {
+ j = tc_entry_info_find_max_count(dinfo, last);
+ /* save only candidate entry info */
+ for (i = 0; i < last; i++) {
+ if (i != j) {
+ tc_entry_info_free(&dinfo[i]);
+ }
+ }
+ if (dinfo[j].count < probed + 1) {
+ ret = 0;
+ } else {
+ ret = 1;
+ }
+ }
+ if (candidate != NULL) {
+ candidate->fd = dinfo[j].fd;
+ candidate->magic = dinfo[j].magic;
+ candidate->count = dinfo[j].count;
+ }
+ }
+ return ret;
+}
+
+
+#define OPEN_FILE(ipipe, name) do { \
+ (ipipe)->fd_in = xio_open((name), O_RDONLY); \
+ if ((ipipe)->fd_in < 0) { \
+ tc_log_perror(EXE, "file open"); \
+ return TC_IMPORT_ERROR; \
+ } \
+} while (0)
+
+#define PROBE_DIR(ipipe) do { \
+ TCDirEntryInfo info; \
+ int ret = tc_scan_directory_info((ipipe)->name, &info); \
+ if (ret < 0) { \
+ tc_log_error(EXE, "unrecognized filetype for '%s'", \
+ (ipipe)->name); \
+ return TC_IMPORT_ERROR; \
+ } else if (ret == 0) { \
+ tc_log_warn(EXE, "non-homogeneous directory content" \
+ " (different stream type detected)"); \
+ } \
+ (ipipe)->fd_in = info.fd; \
+ (ipipe)->magic = info.magic; \
+} while (0)
+
+/*
+ * info_setup:
+ *
+ * perform second-step initialization on a info_t structure.
+ * While first-step setup can be done statically with simple
+ * assignements, intialization performedon this stage is based
+ * on data given previosuly (i.e.: name).
+ * This function is a catch-all for all the black magic things.
+ * Of course there is still a lot of room for cleaning up and
+ * refactoring.
+ * My thought is that doing things in a _really_ clean way means
+ * rewriting almoost from the ground up the probing infrastructure.
+ *
+ * Parameters:
+ * ipipe: info_t structure to (finish to) initialize
+ * skip: amount of bytes to skip when analyzing a regular file.
+ * Ignored otherwise
+ * mplayer_probe: if input it's a regular file, do the real probing through
+ * mplayer (if avalaible); ignored otherwise.
+ * want_dvd: if !0 and the source looks likea DVD, handle it like a DVD.
+ * I know this is a bit obscure and maybe even sick, it's
+ * legacy and should go away in the future.
+ * Return Value:
+ * TC_IMPORT_OK -> succesfull,
+ * TC_IMPORT_ERROR -> otherwise.
+ * messages are sent to user using tc_log_*() in both cases.
+ * Side effects:
+ * quite a lot =)
+ * Input source is open and read to guess the source type.
+ * This function can do (and usually does) several read attempts.
+ * Preconditions:
+ * given info_t structure is already basically initialized (see
+ * first-step setup above). This measn set at least:
+ * ipipe.verbose, ipipe.fd_in, ipipe.name = name;
+ * Postconditions:
+ * given info_t is ready to be used in probe_stream()
+ *
+ */
+static int info_setup(info_t *ipipe, int skip, int mplayer_probe, int want_dvd)
+{
+ int file_kind = tc_probe_path(ipipe->name);
+
+ switch (file_kind) {
+ case TC_PROBE_PATH_FILE: /* regular file */
+ if (mplayer_probe) {
+ ipipe->magic = TC_MAGIC_MPLAYER;
+ } else if (want_dvd && dvd_is_valid(ipipe->name)) {
+ ipipe->magic = TC_MAGIC_DVD;
+ } else {
+ OPEN_FILE(ipipe, ipipe->name);
+ ipipe->magic = fileinfo(ipipe->fd_in, skip);
+ ipipe->seek_allowed = 1;
+ }
+ break;
+ case TC_PROBE_PATH_RELDIR: /* relative path to directory */
+ PROBE_DIR(ipipe);
+ break;
+ case TC_PROBE_PATH_ABSPATH: /* absolute path */
+ if (dvd_is_valid(ipipe->name)) {
+ ipipe->magic = TC_MAGIC_DVD;
+ } else {
+ PROBE_DIR(ipipe);
+ }
+ break;
+ /* now the easy stuff */
+ case TC_PROBE_PATH_BKTR: /* bktr device */
+ ipipe->magic = TC_MAGIC_BKTR_VIDEO;
+ break;
+ case TC_PROBE_PATH_SUNAU: /* sunau device */
+ ipipe->magic = TC_MAGIC_SUNAU_AUDIO;
+ break;
+ case TC_PROBE_PATH_OSS: /* OSS device */
+ ipipe->magic = TC_MAGIC_OSS_AUDIO;
+ break;
+ case TC_PROBE_PATH_V4L_VIDEO: /* v4l video device */
+ ipipe->magic = TC_MAGIC_V4L_VIDEO;
+ break;
+ case TC_PROBE_PATH_V4L_AUDIO: /* v4l audio device */
+ ipipe->magic = TC_MAGIC_V4L_AUDIO;
+ break;
+ case TC_PROBE_PATH_INVALID: /* non-existent source */
+ default: /* fallthrough */
+ tc_log_error(EXE, "can't determine the file kind");
+ return TC_IMPORT_ERROR;
+ } /* probe_path */
+ return TC_IMPORT_OK;
+}
+
+#undef OPEN_FILE
+#undef PROBE_DIR
+
+/*
+ * info_teardown:
+ *
+ * reverse initialization done in info_setup
+ *
+ * Parameters:
+ * ipipe: info_t structure to (finish to) initialize
+ * Return Value:
+ * None
+ */
+static void info_teardown(info_t *ipipe)
+{
+ if (ipipe->fd_in != STDIN_FILENO) {
+ xio_close(ipipe->fd_in);
+ }
+}
+
+/*************************************************************************/
+
+/* new fancy output handlers */
+
+/*
+ * generic info dump function handler
+ */
+typedef void (*InfoDumpFn)(info_t *ipipe);
+
+/*
+ * dump_info_binary:
+ *
+ * dump a ProbeInfo structure in binary (and platform-dependent,
+ * and probably even not fully safe) way to stdout.
+ * This dump mode is used by tcprobe to communicate with transcode.
+ * Legacy, I'd like to change this communication mode in future
+ * releases.
+ *
+ * Parameters:
+ * ipipe: info_t structure holding the ProbeInfo data to dump.
+ * Return Value:
+ * None
+ */
+static void dump_info_binary(info_t *ipipe)
+{
+ pid_t pid = getpid();
+ tc_pwrite(STDOUT_FILENO, (uint8_t *) &pid, sizeof(pid_t));
+ tc_pwrite(STDOUT_FILENO, (uint8_t *) ipipe->probe_info,
+ sizeof(ProbeInfo));
+}
+
+
+#define PROBED_NEW "(*)" /* value different from tc's defaults */
+#define PROBED_STD "" /* value equals to tc's defaults */
+
+/*
+ * user mode:
+ * recommended transcode command line options:
+ */
+#define MARK_EXPECTED(ex) ((ex) ?(PROBED_STD) :(PROBED_NEW))
+#define CHECK_MARK_EXPECTED(probed, val) \
+ (((val) == (probed)) ?(PROBED_STD) :(PROBED_NEW))
+
+/*
+ * dump_info_old:
+ * dump a ProbeInfo structure in a human-readable format.
+ *
+ * Parameters:
+ * ipipe: info_t structure holding the ProbeInfo data to dump.
+ * Return Value:
+ * None
+ */
+
+static void dump_info_old(info_t *ipipe)
+{
+ long frame_time = 0;
+ int is_std = TC_TRUE; /* flag: select PROBED_??? above */
+ int nsubs = 0, i = 0;
+ char extrabuf[TC_BUF_MIN] = { '\0' };
+ int extrabuf_ready = TC_FALSE;
+ size_t len = 0;
+
+ /* full-blown back-compatibility */
+ fprintf(stderr, "[%s] %s\n", EXE, filetype(ipipe->magic));
+ printf("[%s] summary for %s, %s = not default, 0 = not detected\n",
+ EXE, ((ipipe->magic == TC_STYPE_STDIN) ?"-" :ipipe->name),
+ PROBED_NEW);
+
+ if (ipipe->probe_info->width != PAL_W
+ || ipipe->probe_info->height != PAL_H) {
+ is_std = TC_FALSE;
+ }
+
+ /* video first. */
+ if (ipipe->probe_info->width > 0 && ipipe->probe_info->height > 0) {
+ int n, d, ret;
+
+ extrabuf_ready = TC_FALSE;
+
+ printf("%18s %s %dx%d [%dx%d] %s\n",
+ "import frame size:", "-g",
+ ipipe->probe_info->width, ipipe->probe_info->height,
+ PAL_W, PAL_H, MARK_EXPECTED(is_std));
+
+ ret = tc_asr_code_to_ratio(ipipe->probe_info->asr, &n, &d);
+ if (ret != TC_NULL_MATCH && (n > 0 && d > 0)) {
+ /* back compatibility little hack */
+ printf("%18s %i:%i %s\n",
+ "aspect ratio:", n, d,
+ CHECK_MARK_EXPECTED(ipipe->probe_info->asr, 1));
+ }
+
+ frame_time = (ipipe->probe_info->fps != 0) ?
+ (long)(1. / ipipe->probe_info->fps * 1000) : 0;
+
+ printf("%18s %s %.3f [%.3f] frc=%d %s\n", "frame rate:", "-f",
+ ipipe->probe_info->fps, PAL_FPS, ipipe->probe_info->frc,
+ CHECK_MARK_EXPECTED(ipipe->probe_info->frc, 3));
+
+ tc_snprintf(extrabuf, sizeof(extrabuf), "%18s ", "");
+ /* empty string to have a nice justification */
+ /* video track extra info */
+ if (ipipe->probe_info->pts_start) {
+ len = strlen(extrabuf);
+ tc_snprintf(extrabuf + len, sizeof(extrabuf) - len,
+ "PTS=%.4f, frame_time=%ldms",
+ ipipe->probe_info->pts_start, frame_time);
+ if (ipipe->probe_info->bitrate) {
+ len = strlen(extrabuf);
+ tc_snprintf(extrabuf + len, sizeof(extrabuf) - len,
+ "%sbitrate=%li kbps",
+ (extrabuf_ready) ?", " :" ",
+ /*
+ * add seeparator only if we alread
+ * written something in buffer
+ */
+ ipipe->probe_info->bitrate);
+ }
+ /* at this point extrabuf flag will always be set to on */
+ extrabuf_ready = TC_TRUE;
+ }
+ if (extrabuf_ready) {
+ printf("%s\n", extrabuf);
+ }
+ }
+
+ /* audio next. */
+ for (i = 0; i < TC_MAX_AUD_TRACKS; i++) {
+ int D_arg = 0, D_arg_ms = 0;
+ double pts_diff = 0.;
+
+ if (ipipe->probe_info->track[i].format != 0
+ && ipipe->probe_info->track[i].chan > 0) {
+ extrabuf_ready = TC_FALSE;
+ extrabuf[0] = '\0';
+
+ if (ipipe->probe_info->track[i].samplerate != RATE
+ || ipipe->probe_info->track[i].chan != CHANNELS
+ || ipipe->probe_info->track[i].bits != BITS
+ || ipipe->probe_info->track[i].format != CODEC_AC3) {
+ is_std = TC_FALSE;
+ } else {
+ is_std = TC_TRUE;
+ }
+
+ printf("%18s -a %d [0] -e %d,%d,%d [%d,%d,%d] -n 0x%x [0x%x] %s\n",
+ "audio track:",
+ ipipe->probe_info->track[i].tid,
+ ipipe->probe_info->track[i].samplerate,
+ ipipe->probe_info->track[i].bits,
+ ipipe->probe_info->track[i].chan,
+ RATE, BITS, CHANNELS,
+ ipipe->probe_info->track[i].format,
+ CODEC_AC3,
+ MARK_EXPECTED(is_std));
+
+ /* audio track extra info */
+ if (ipipe->probe_info->track[i].pts_start) {
+ tc_snprintf(extrabuf, sizeof(extrabuf), "PTS=%.4f",
+ ipipe->probe_info->track[i].pts_start);
+ extrabuf_ready = TC_TRUE;
+ }
+ if (ipipe->probe_info->track[i].bitrate) {
+ size_t len = strlen(extrabuf);
+ tc_snprintf(extrabuf + len, sizeof(extrabuf) - len,
+ "%sbitrate=%i kbps", (extrabuf_ready) ?", " :"",
+ ipipe->probe_info->track[i].bitrate);
+ extrabuf_ready = TC_TRUE;
+ }
+ if (extrabuf_ready) {
+ printf("%18s %s\n",
+ "", /* empty string for a nice justification */
+ extrabuf);
+ }
+
+ /* audio track A/V sync suggestion */
+ if (ipipe->probe_info->pts_start > 0
+ && ipipe->probe_info->track[i].pts_start > 0
+ && ipipe->probe_info->fps != 0) {
+ pts_diff = ipipe->probe_info->pts_start \
+ - ipipe->probe_info->track[i].pts_start;
+ D_arg = (int)(pts_diff * ipipe->probe_info->fps);
+ D_arg_ms = (int)((pts_diff - D_arg/ipipe->probe_info->fps)*1000);
+
+ printf("%18s -D %d --av_fine_ms %d (frames & ms) [0] [0]\n",
+ " ", D_arg, D_arg_ms);
+ }
+ }
+ /* have subtitles here? */
+ if (ipipe->probe_info->track[i].attribute & PACKAGE_SUBTITLE) {
+ nsubs++;
+ }
+ }
+
+ /* no audio */
+ if (ipipe->probe_info->num_tracks == 0) {
+ printf("%18s %s", "no audio track:",
+ "(use \"null\" import module for audio)\n");
+ }
+
+ if (nsubs > 0) {
+ printf("detected (%d) subtitle(s)\n", nsubs);
+ }
+
+ /* P-units */
+ if (ipipe->probe_info->unit_cnt) {
+ printf("detected (%d) presentation unit(s) (SCR reset)\n",
+ ipipe->probe_info->unit_cnt+1);
+ }
+
+ /* DVD only: coder bitrate infos */
+ if (ipipe->magic == TC_MAGIC_DVD_PAL || ipipe->magic == TC_MAGIC_DVD_NTSC
+ || ipipe->magic == TC_MAGIC_DVD) {
+ enc_bitrate((long)ceil(ipipe->probe_info->fps * ipipe->probe_info->time),
+ ipipe->probe_info->fps, bitrate*1000, 0);
+ } else {
+ if (ipipe->probe_info->frames > 0) {
+ unsigned long dur_ms;
+ unsigned int dur_h, dur_min, dur_s;
+ if (ipipe->probe_info->fps < 0.100) {
+ dur_ms = (long)ipipe->probe_info->frames*frame_time;
+ } else {
+ dur_ms = (long)((float)ipipe->probe_info->frames * 1000
+ /ipipe->probe_info->fps);
+ }
+ dur_h = dur_ms/3600000;
+ dur_min = (dur_ms %= 3600000)/60000;
+ dur_s = (dur_ms %= 60000)/1000;
+ dur_ms %= 1000;
+ printf("%18s %ld frames, frame_time=%ld msec,"
+ " duration=%u:%02u:%02u.%03lu\n",
+ "length:",
+ ipipe->probe_info->frames, frame_time,
+ dur_h, dur_min, dur_s, dur_ms);
+ }
+ }
+}
+
+
+/*
+ * dump_track_info_raw:
+ *
+ * dump a ProbeTrackInfo structure in a human-readable but machine-friendly
+ * format, resembling, or identical where feasible, the mplayer -identify
+ * output.
+ * Print one field at line, in the format KEY=value.
+ *
+ * Parameters:
+ * tracks: pointer to ProbeTrackInfo array to be dumped
+ * i: dump only the i-th structure on array.
+ * Return Value:
+ * None
+ */
+static void dump_track_info_raw(ProbeTrackInfo *ti, int i)
+{
+ if (ti != NULL && i >= 0) { /* paranoia */
+ const char *ext = "";
+ /* extension to identifiers for non-zero (not first) track */
+ char ext_buf[24];
+
+ if (i > 0) {
+ tc_snprintf(ext_buf, sizeof(ext_buf), "_%i", i);
+ ext = ext_buf;
+ }
+
+ if (ti[i].format != 0 && ti[i].chan > 0) {
+ printf("ID_AUDIO_CODEC%s=%s\n", ext,
+ tc_codec_to_string(ti[i].format));
+ printf("ID_AUDIO_FORMAT%s=%i\n", ext, ti[i].format);
+ printf("ID_AUDIO_BITRATE%s=%i\n", ext, ti[i].bitrate);
+ printf("ID_AUDIO_RATE%s=%i\n", ext, ti[i].samplerate);
+ printf("ID_AUDIO_NCH%s=%i\n", ext, ti[i].chan);
+ printf("ID_AUDIO_BITS%s=%i\n", ext, ti[i].bits);
+ }
+ }
+}
+
+/*
+ * dump_info_raw:
+ *
+ * dump a ProbeInfo structure in a human-readable but machine-friendly
+ * format, resembling, or identical where feasible, the mplayer -identify
+ * output.
+ * Print one field at line, in the format KEY=value.
+ *
+ * Parameters:
+ * ipipe: info_t structure holding the ProbeInfo data to dump.
+ * Return Value:
+ * None
+ */
+static void dump_info_raw(info_t *ipipe)
+{
+ int i;
+ double duration = 0.0; /* seconds */
+
+ /* general information */
+ printf("ID_FILENAME=\"%s\"\n", ipipe->name);
+ printf("ID_FILETYPE=\"%s\"\n", filetype(ipipe->magic));
+
+ /* video track, only the first */
+ printf("ID_VIDEO_WIDTH=%i\n", ipipe->probe_info->width);
+ printf("ID_VIDEO_HEIGHT=%i\n", ipipe->probe_info->height);
+ printf("ID_VIDEO_FPS=%.3f\n", ipipe->probe_info->fps);
+ printf("ID_VIDEO_FRC=%i\n", ipipe->probe_info->frc);
+ printf("ID_VIDEO_ASR=%i\n", ipipe->probe_info->asr);
+ printf("ID_VIDEO_FORMAT=%s\n",
+ tc_codec_to_string(ipipe->probe_info->codec));
+ printf("ID_VIDEO_BITRATE=%li\n", ipipe->probe_info->bitrate);
+
+ /* audio stuff */
+ for (i = 0; i < TC_MAX_AUD_TRACKS; i++) {
+ dump_track_info_raw(ipipe->probe_info->track, i);
+ }
+
+ if (ipipe->probe_info->fps != 0.0) {
+ /* seconds */
+ duration = ((double)ipipe->probe_info->frames/ipipe->probe_info->fps);
+ }
+ /* general information, reprise */
+ printf("ID_LENGTH=%.2f\n", duration);
+}
+
+/*
+ * dump_info_new:
+ * dump a ProbeInfo structure in new, better
+ * human-readable format.
+ *
+ * Parameters:
+ * ipipe: info_t structure holding the ProbeInfo data to dump.
+ * Return Value:
+ * None
+ */
+static void dump_info_new(info_t *ipipe)
+{
+ int i = 0, j = 0;
+ unsigned long dur_ms = 0;
+ unsigned int dur_h = 0, dur_min = 0, dur_s = 0;
+ long frame_time = (ipipe->probe_info->fps != 0)
+ ? (long)(1. / ipipe->probe_info->fps * 1000) : 0;
+
+ if (ipipe->probe_info->fps < 0.100) {
+ dur_ms = (long)ipipe->probe_info->frames * frame_time;
+ } else {
+ dur_ms = (long)((float)ipipe->probe_info->frames * 1000
+ /ipipe->probe_info->fps);
+ }
+ dur_h = dur_ms / 3600000;
+ dur_min = (dur_ms %= 3600000) / 60000;
+ dur_s = (dur_ms %= 60000) / 1000;
+ dur_ms %= 1000;
+
+ printf("* container:\n");
+ printf("%18s: %s\n", "format",
+ filetype(ipipe->probe_info->magic));
+ printf("%18s: '%s'\n", "source",
+ ((ipipe->magic == TC_STYPE_STDIN) ?"-" :ipipe->name));
+ printf("%18s: %li\n", "frames",
+ ipipe->probe_info->frames);
+ printf("%18s: %u:%02u:%02u.%03lu\n", "duration",
+ dur_h, dur_min, dur_s, dur_ms);
+ printf("%18s: %i\n", "SCR reset",
+ ipipe->probe_info->unit_cnt + 1);
+
+ /* video first. */
+ if (ipipe->probe_info->width > 0 && ipipe->probe_info->height > 0) {
+ int n, d;
+
+ tc_asr_code_to_ratio(ipipe->probe_info->asr, &n, &d);
+
+ printf("* video track #0:\n");
+ printf("%18s: %s\n", "format",
+ tc_codec_to_string(ipipe->probe_info->codec));
+ printf("%18s: %ix%i\n", "frame size",
+ ipipe->probe_info->width, ipipe->probe_info->height);
+ printf("%18s: %i:%i (asr=%i)\n", "aspect ratio",
+ n, d, ipipe->probe_info->asr);
+ printf("%18s: %.3f (frc=%i)\n", "frame rate",
+ ipipe->probe_info->fps, ipipe->probe_info->frc);
+ printf("%18s: %li kbps\n", "bitrate", ipipe->probe_info->bitrate);
+ printf("%18s: %.4f\n", "starting PTS",
+ ipipe->probe_info->pts_start);
+ printf("%18s: %li ms\n", "frame time", frame_time);
+ }
+
+ j = 0;
+ for (i = 0; i < TC_MAX_AUD_TRACKS; i++) {
+ if (ipipe->probe_info->track[i].format != 0
+ && ipipe->probe_info->track[i].chan > 0) {
+ double pts_diff = 0.0;
+ int hint_frames = 0, hint_ms = 0;
+ if (ipipe->probe_info->pts_start > 0
+ && ipipe->probe_info->track[i].pts_start > 0
+ && ipipe->probe_info->fps != 0) {
+ pts_diff = ipipe->probe_info->pts_start - ipipe->probe_info->track[i].pts_start;
+ hint_frames = (int)(pts_diff * ipipe->probe_info->fps);
+ hint_ms = (int)((pts_diff - hint_frames / ipipe->probe_info->fps) * 1000);
+ }
+
+ printf("* audio track #%i:\n", j);
+ /* XXX */
+ printf("%18s: %i\n", "track id",
+ ipipe->probe_info->track[i].tid);
+ /* XXX */
+ printf("%18s: 0x%x\n", "format",
+ ipipe->probe_info->track[i].format);
+ printf("%18s: %i\n", "channels",
+ ipipe->probe_info->track[i].chan);
+ printf("%18s: %i Hz\n", "sample rate",
+ ipipe->probe_info->track[i].samplerate);
+ printf("%18s: %i\n", "bits for sample",
+ ipipe->probe_info->track[i].bits);
+
+ printf("%18s: %i kbps\n", "bitrate",
+ ipipe->probe_info->track[i].bitrate);
+ printf("%18s: %.4f\n", "starting PTS",
+ ipipe->probe_info->track[i].pts_start);
+ printf("%18s: %i frames/%i ms\n", "A/V sync hint",
+ hint_frames, hint_ms);
+ /* have subtitles here? */
+ printf("%18s: %s\n", "subtitles",
+ (ipipe->probe_info->track[i].attribute & PACKAGE_SUBTITLE) ?"yes" :"no");
+ j++;
+ }
+ }
+}
+
+
+/*************************************************************************/
+
+/* ------------------------------------------------------------
+ *
+ * print a usage/version message
+ *
+ * ------------------------------------------------------------*/
+
+void version(void)
+{
+ /* print id string to stderr */
+ printf("%s (%s v%s) (C) 2001-2010 Thomas Oestreich, Transcode team\n",
+ EXE, PACKAGE, VERSION);
+}
+
+
+static void usage(int status)
+{
+ version();
+
+ printf("Usage: %s [options] [-]\n", EXE);
+ printf(" -i name input file/directory/device/host"
+ " name [stdin]\n");
+ printf(" -B binary output to stdout"
+ " (used by transcode) [off]\n");
+ printf(" -M use EXPERIMENTAL mplayer probe [off]\n");
+ printf(" -R raw mode: produce machine-friendly"
+ " output [off]\n");
+ printf(" -X new extended output mode [off]\n");
+ printf(" -H n probe n MB of stream [1]\n");
+ printf(" -s n skip first n bytes of stream [0]\n");
+ printf(" -T title probe for DVD title [off]\n");
+ printf(" -b bitrate audio encoder bitrate kBits/s [%d]\n",
+ ABITRATE);
+ printf(" -f seekfile seek/index file [off]\n");
+ printf(" -d verbosity verbosity mode [1]\n");
+ printf(" -v print version\n");
+
+ exit(status);
+}
+
+/* ------------------------------------------------------------
+ * universal probing code frontend
+ * ------------------------------------------------------------*/
+
+/* very basic option sanity check */
+#define VALIDATE_OPTION \
+ if (optarg[0]=='-') { \
+ usage(EXIT_FAILURE); \
+ }
+
+#define VALIDATE_PARAM(parm, opt, min) \
+ if ((parm) < (min)) { \
+ tc_log_error(EXE, "invalid parameter for option %s", (opt)); \
+ exit(16); \
+ }
+
+
+int main(int argc, char *argv[])
+{
+ info_t ipipe;
+ InfoDumpFn output_handler = dump_info_old;
+ /* standard old style output */
+
+ int mplayer_probe = TC_FALSE;
+ int ch, skip = 0, want_dvd = 0, ret;
+ const char *name = NULL;
+
+ /* proper initialization */
+ memset(&ipipe, 0, sizeof(info_t));
+ ipipe.stype = TC_STYPE_UNKNOWN;
+ ipipe.seek_allowed = 0;
+ ipipe.factor = 1;
+ ipipe.dvd_title = 1;
+
+ libtc_init(&argc, &argv);
+
+ while ((ch = getopt(argc, argv, "i:vBMRXd:T:f:b:s:H:?h")) != -1) {
+ switch (ch) {
+ case 'b':
+ VALIDATE_OPTION;
+ bitrate = atoi(optarg);
+ VALIDATE_PARAM(bitrate, "-b", 0);
+ break;
+ case 'i':
+ VALIDATE_OPTION;
+ name = optarg;
+ break;
+ case 'f':
+ VALIDATE_OPTION;
+ ipipe.nav_seek_file = optarg;
+ break;
+ case 'd':
+ VALIDATE_OPTION;
+ verbose = atoi(optarg);
+ break;
+ case 's':
+ VALIDATE_OPTION;
+ skip = atoi(optarg);
+ break;
+ case 'H':
+ VALIDATE_OPTION;
+ ipipe.factor = atoi(optarg); /* how much data for probing? */
+ VALIDATE_PARAM(bitrate, "-H", 0);
+ break;
+ case 'B':
+ output_handler = dump_info_binary;
+ binary_dump = 1; /* XXX: compatibility with probe_mov -- FR */
+ break;
+ case 'M':
+ mplayer_probe = TC_TRUE;
+ break;
+ case 'R':
+ output_handler = dump_info_raw;
+ break;
+ case 'X':
+ output_handler = dump_info_new;
+ break;
+ case 'T':
+ VALIDATE_OPTION;
+ ipipe.dvd_title = atoi(optarg);
+ want_dvd = 1;
+ break;
+ case 'v':
+ version();
+ exit(0);
+ break;
+ case 'h':
+ usage(EXIT_SUCCESS);
+ break;
+ default:
+ usage(EXIT_FAILURE);
+ }
+ }
+
+ /* need at least a file name */
+ if (argc == 1) {
+ usage(EXIT_FAILURE);
+ }
+
+ if (optind < argc) {
+ if (strcmp(argv[optind],"-") != 0) {
+ usage(EXIT_FAILURE);
+ }
+ ipipe.stype = TC_STYPE_STDIN;
+ }
+
+ /* assume defaults */
+ if (name == NULL) {
+ ipipe.stype = TC_STYPE_STDIN;
+ } else {
+ if (tc_x11source_is_display_name(name)) {
+ ipipe.stype = TC_STYPE_X11;
+ }
+ }
+ ipipe.verbose = verbose;
+ ipipe.fd_out = STDOUT_FILENO;
+ ipipe.codec = TC_CODEC_UNKNOWN;
+ ipipe.name = name;
+
+ /* do not try to mess with the stream */
+ if (ipipe.stype == TC_STYPE_STDIN) {
+ ipipe.fd_in = STDIN_FILENO;
+ ipipe.magic = streaminfo(ipipe.fd_in);
+ } else if (ipipe.stype == TC_STYPE_X11) {
+ ipipe.fd_in = STDIN_FILENO; /* XXX */
+ ipipe.magic = TC_MAGIC_X11;
+ } else {
+ ret = info_setup(&ipipe, skip, mplayer_probe, want_dvd);
+ if (ret != TC_IMPORT_OK) {
+ /* already logged out why */
+ exit(1);
+ }
+ }
+
+ /* ------------------------------------------------------------
+ * codec specific section
+ * note: user provided values overwrite autodetection!
+ * ------------------------------------------------------------*/
+
+ probe_stream(&ipipe);
+
+ if (ipipe.error == 0) {
+ output_handler(&ipipe);
+ } else if (ipipe.error == 1) {
+ if (verbose) {
+ tc_log_error(EXE, "failed to probe source");
+ }
+ } else if (ipipe.error == 2) {
+ if (verbose) {
+ tc_log_error(EXE, "filetype/codec not yet supported by '%s'",
+ PACKAGE);
+ }
+ }
+
+ info_teardown(&ipipe);
+ return ipipe.error;
+}
+
+#include "libtc/static_xio.h"
+
+/*************************************************************************/
+
+/*
+ * Local variables:
+ * c-file-style: "stroustrup"
+ * c-file-offsets: ((case-label . *) (statement-case-intro . *))
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vim: expandtab shiftwidth=4:
+ */