Skip to content
Snippets Groups Projects
ffprobe.c 82.8 KiB
Newer Older
  • Learn to ignore specific revisions
  •         av_dict_copy(&section->entries_to_show, entries, 0);
        }
    }
    
    static int match_section(const char *section_name,
                             int show_all_entries, AVDictionary *entries)
    {
        int i, ret = 0;
    
        for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) {
            const struct section *section = &sections[i];
            if (!strcmp(section_name, section->name) ||
                (section->unique_name && !strcmp(section_name, section->unique_name))) {
                av_log(NULL, AV_LOG_DEBUG,
                       "'%s' matches section with unique name '%s'\n", section_name,
                       (char *)av_x_if_null(section->unique_name, section->name));
                ret++;
                mark_section_show_entries(section->id, show_all_entries, entries);
            }
        }
        return ret;
    }
    
    static int opt_show_entries(void *optctx, const char *opt, const char *arg)
    {
        const char *p = arg;
        int ret = 0;
    
        while (*p) {
            AVDictionary *entries = NULL;
            char *section_name = av_get_token(&p, "=:");
            int show_all_entries = 0;
    
            if (!section_name) {
                av_log(NULL, AV_LOG_ERROR,
                       "Missing section name for option '%s'\n", opt);
                return AVERROR(EINVAL);
            }
    
            if (*p == '=') {
                p++;
                while (*p && *p != ':') {
                    char *entry = av_get_token(&p, ",:");
                    if (!entry)
                        break;
                    av_log(NULL, AV_LOG_VERBOSE,
                           "Adding '%s' to the entries to show in section '%s'\n",
                           entry, section_name);
                    av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY);
                    if (*p == ',')
                        p++;
                }
            } else {
                show_all_entries = 1;
            }
    
            ret = match_section(section_name, show_all_entries, entries);
            if (ret == 0) {
                av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name);
                ret = AVERROR(EINVAL);
            }
    
            av_dict_free(&entries);
    
    static int opt_show_format_entry(void *optctx, const char *opt, const char *arg)
    
        char *buf = av_asprintf("format=%s", arg);
        int ret;
    
        av_log(NULL, AV_LOG_WARNING,
               "Option '%s' is deprecated, use '-show_entries format=%s' instead\n",
               opt, arg);
        ret = opt_show_entries(optctx, opt, buf);
        av_free(buf);
        return ret;
    
    static void opt_input_file(void *optctx, const char *arg)
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
    {
    
        if (input_filename) {
    
            av_log(NULL, AV_LOG_ERROR,
                    "Argument '%s' provided as input filename, but '%s' was already specified.\n",
                    arg, input_filename);
    
        if (!strcmp(arg, "-"))
            arg = "pipe:";
        input_filename = arg;
    
    static int opt_input_file_i(void *optctx, const char *opt, const char *arg)
    {
        opt_input_file(optctx, arg);
        return 0;
    }
    
    
    void show_help_default(const char *opt, const char *arg)
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
    {
    
        av_log_set_callback(log_callback_help);
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
        show_usage();
    
        show_help_options(options, "Main options:", 0, 0, 0);
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
        printf("\n");
    
    
        show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM);
    
    static int opt_pretty(void *optctx, const char *opt, const char *arg)
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
    {
        show_value_unit              = 1;
        use_value_prefix             = 1;
        use_byte_value_binary_prefix = 1;
        use_value_sexagesimal_format = 1;
    
    static void print_section(SectionID id, int level)
    {
        const SectionID *pid;
        const struct section *section = &sections[id];
        printf("%c%c%c",
               section->flags & SECTION_FLAG_IS_WRAPPER           ? 'W' : '.',
               section->flags & SECTION_FLAG_IS_ARRAY             ? 'A' : '.',
               section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS  ? 'V' : '.');
        printf("%*c  %s", level * 4, ' ', section->name);
        if (section->unique_name)
            printf("/%s", section->unique_name);
        printf("\n");
    
        for (pid = section->children_ids; *pid != -1; pid++)
            print_section(*pid, level+1);
    }
    
    static int opt_sections(void *optctx, const char *opt, const char *arg)
    {
        printf("Sections:\n"
               "W.. = Section is a wrapper (contains other sections, no local entries)\n"
               ".A. = Section contains an array of elements of the same type\n"
               "..V = Section may contain a variable number of fields with variable keys\n"
               "FLAGS NAME/UNIQUE_NAME\n"
               "---\n");
        print_section(SECTION_ID_ROOT, 0);
        return 0;
    }
    
    
    static int opt_show_versions(const char *opt, const char *arg)
    {
    
        mark_section_show_entries(SECTION_ID_PROGRAM_VERSION, 1, NULL);
        mark_section_show_entries(SECTION_ID_LIBRARY_VERSION, 1, NULL);
    
    #define DEFINE_OPT_SHOW_SECTION(section, target_section_id)             \
        static int opt_show_##section(const char *opt, const char *arg)     \
        {                                                                   \
            mark_section_show_entries(SECTION_ID_##target_section_id, 1, NULL); \
            return 0;                                                       \
        }
    
    DEFINE_OPT_SHOW_SECTION(error,            ERROR);
    DEFINE_OPT_SHOW_SECTION(format,           FORMAT);
    DEFINE_OPT_SHOW_SECTION(frames,           FRAMES);
    DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS);
    DEFINE_OPT_SHOW_SECTION(packets,          PACKETS);
    DEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION);
    DEFINE_OPT_SHOW_SECTION(streams,          STREAMS);
    
    
    static const OptionDef real_options[] = {
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
    #include "cmdutils_common_opts.h"
    
        { "f", HAS_ARG, {.func_arg = opt_format}, "force format", "format" },
        { "unit", OPT_BOOL, {&show_value_unit}, "show unit of the displayed values" },
        { "prefix", OPT_BOOL, {&use_value_prefix}, "use SI prefixes for the displayed values" },
        { "byte_binary_prefix", OPT_BOOL, {&use_byte_value_binary_prefix},
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
          "use binary prefixes for byte units" },
    
        { "sexagesimal", OPT_BOOL,  {&use_value_sexagesimal_format},
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
          "use sexagesimal format HOURS:MM:SS.MICROSECONDS for time units" },
    
        { "pretty", 0, {.func_arg = opt_pretty},
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
          "prettify the format of displayed values, make it more human readable" },
    
        { "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format},
    
          "set the output printing format (available formats are: default, compact, csv, flat, ini, json, xml)", "format" },
    
        { "of", OPT_STRING | HAS_ARG, {(void*)&print_format}, "alias for -print_format", "format" },
    
        { "select_streams", OPT_STRING | HAS_ARG, {(void*)&stream_specifier}, "select the specified streams", "stream_specifier" },
    
        { "sections", OPT_EXIT, {.func_arg = opt_sections}, "print sections structure and section information, and exit" },
    
        { "show_data",    OPT_BOOL, {(void*)&do_show_data}, "show packets data" },
    
        { "show_error",   0, {(void*)&opt_show_error},  "show probing error" },
        { "show_format",  0, {(void*)&opt_show_format}, "show format/container info" },
        { "show_frames",  0, {(void*)&opt_show_frames}, "show frames info" },
    
        { "show_format_entry", HAS_ARG, {.func_arg = opt_show_format_entry},
    
          "show a particular entry from the format/container info", "entry" },
    
        { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
          "show a set of specified entries", "entry_list" },
        { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
        { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
    
        { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
        { "count_packets", OPT_BOOL, {(void*)&do_count_packets}, "count the number of packets per stream" },
    
        { "show_program_version",  0, {(void*)&opt_show_program_version},  "show ffprobe version" },
        { "show_library_versions", 0, {(void*)&opt_show_library_versions}, "show library versions" },
    
        { "show_versions",         0, {(void*)&opt_show_versions}, "show program and library versions" },
    
        { "show_private_data", OPT_BOOL, {(void*)&show_private_data}, "show private data" },
        { "private",           OPT_BOOL, {(void*)&show_private_data}, "same as show_private_data" },
    
        { "bitexact", OPT_BOOL, {&do_bitexact}, "force bitexact output" },
    
        { "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, {.func_arg = opt_default}, "generic catch all option", "" },
    
        { "i", HAS_ARG, {.func_arg = opt_input_file_i}, "read specified file", "input_file"},
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
        { NULL, },
    };
    
    
    static inline int check_section_show_entries(int section_id)
    {
        int *id;
        struct section *section = &sections[section_id];
        if (sections[section_id].show_all_entries || sections[section_id].entries_to_show)
            return 1;
        for (id = section->children_ids; *id != -1; id++)
            if (check_section_show_entries(*id))
                return 1;
        return 0;
    }
    
    #define SET_DO_SHOW(id, varname) do {                                   \
            if (check_section_show_entries(SECTION_ID_##id))                \
                do_show_##varname = 1;                                      \
        } while (0)
    
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
    int main(int argc, char **argv)
    {
    
        const Writer *w;
        WriterContext *wctx;
        char *buf;
        char *w_name = NULL, *w_args = NULL;
    
        av_log_set_flags(AV_LOG_SKIP_REPEATED);
    
        parse_loglevel(argc, argv, options);
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
        av_register_all();
    
        avformat_network_init();
    
        init_opts();
    
    #if CONFIG_AVDEVICE
        avdevice_register_all();
    #endif
    
        show_banner(argc, argv, options);
    
        parse_options(NULL, argc, argv, options, opt_input_file);
    
        /* mark things to show, based on -show_entries */
        SET_DO_SHOW(ERROR, error);
        SET_DO_SHOW(FORMAT, format);
        SET_DO_SHOW(FRAMES, frames);
        SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
        SET_DO_SHOW(PACKETS, packets);
        SET_DO_SHOW(PROGRAM_VERSION, program_version);
        SET_DO_SHOW(STREAMS, streams);
        SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
    
    
        if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
            av_log(NULL, AV_LOG_ERROR,
                   "-bitexact and -show_program_version or -show_library_versions "
                   "options are incompatible\n");
            ret = AVERROR(EINVAL);
            goto end;
        }
    
    
        writer_register_all();
    
        if (!print_format)
            print_format = av_strdup("default");
    
        if (!print_format) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
    
        w_name = av_strtok(print_format, "=", &buf);
        w_args = buf;
    
        w = writer_get_by_name(w_name);
        if (!w) {
            av_log(NULL, AV_LOG_ERROR, "Unknown output format with name '%s'\n", w_name);
            ret = AVERROR(EINVAL);
            goto end;
    
        if ((ret = writer_open(&wctx, w, w_args,
                               sections, FF_ARRAY_ELEMS(sections))) >= 0) {
            writer_print_section_header(wctx, SECTION_ID_ROOT);
    
            if (do_show_program_version)
                ffprobe_show_program_version(wctx);
            if (do_show_library_versions)
                ffprobe_show_library_versions(wctx);
    
            if (!input_filename &&
                ((do_show_format || do_show_streams || do_show_packets || do_show_error) ||
                 (!do_show_program_version && !do_show_library_versions))) {
    
                show_usage();
                av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
                av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
                ret = AVERROR(EINVAL);
    
                ret = probe_file(wctx, input_filename);
    
                if (ret < 0 && do_show_error)
                    show_error(wctx, ret);
            }
    
            writer_print_section_footer(wctx);
    
        for (i = 0; i < FF_ARRAY_ELEMS(sections); i++)
            av_dict_free(&(sections[i].entries_to_show));
    
        avformat_network_deinit();
    
    
    Stefano Sabatini's avatar
    Stefano Sabatini committed
    }