Skip to content
Snippets Groups Projects
ffprobe.c 71.9 KiB
Newer Older
Stefano Sabatini's avatar
Stefano Sabatini committed
/*
 * Copyright (c) 2007-2010 Stefano Sabatini
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * simple media prober based on the FFmpeg libraries
 */

#include "config.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
#include "libavutil/opt.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
#include "libavutil/pixdesc.h"
#include "libavutil/dict.h"
#include "libavutil/libm.h"
#include "libavutil/timecode.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libpostproc/postprocess.h"
Stefano Sabatini's avatar
Stefano Sabatini committed
#include "cmdutils.h"

const char program_name[] = "ffprobe";
Stefano Sabatini's avatar
Stefano Sabatini committed
const int program_birth_year = 2007;

static int do_count_frames = 0;
static int do_count_packets = 0;
static int do_read_frames  = 0;
static int do_read_packets = 0;
static int do_show_error   = 0;
Stefano Sabatini's avatar
Stefano Sabatini committed
static int do_show_format  = 0;
static int do_show_frames  = 0;
static AVDictionary *fmt_entries_to_show = NULL;
static int do_show_packets = 0;
Stefano Sabatini's avatar
Stefano Sabatini committed
static int do_show_streams = 0;
static int do_show_data    = 0;
static int do_show_program_version  = 0;
static int do_show_library_versions = 0;
Stefano Sabatini's avatar
Stefano Sabatini committed

static int show_value_unit              = 0;
static int use_value_prefix             = 0;
static int use_byte_value_binary_prefix = 0;
static int use_value_sexagesimal_format = 0;
static int show_private_data            = 1;
Stefano Sabatini's avatar
Stefano Sabatini committed

static char *print_format;

static const OptionDef *options;
Stefano Sabatini's avatar
Stefano Sabatini committed

/* FFprobe context */
static const char *input_filename;
static AVInputFormat *iformat = NULL;
Stefano Sabatini's avatar
Stefano Sabatini committed

static const char *const binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
static const char *const decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P"  };
Stefano Sabatini's avatar
Stefano Sabatini committed

static const char unit_second_str[]         = "s"    ;
static const char unit_hertz_str[]          = "Hz"   ;
static const char unit_byte_str[]           = "byte" ;
static const char unit_bit_per_second_str[] = "bit/s";
static uint64_t *nb_streams_packets;
static uint64_t *nb_streams_frames;
Stefano Sabatini's avatar
Stefano Sabatini committed

void av_noreturn exit_program(int ret)
    av_dict_free(&fmt_entries_to_show);
    union { double d; long long int i; } val;
    const char *unit;
};

static char *value_string(char *buf, int buf_size, struct unit_value uv)
Stefano Sabatini's avatar
Stefano Sabatini committed
{
    double vald;
    int show_float = 0;

    if (uv.unit == unit_second_str) {
        vald = uv.val.d;
        show_float = 1;
    } else {
        vald = uv.val.i;
    }

    if (uv.unit == unit_second_str && use_value_sexagesimal_format) {
Stefano Sabatini's avatar
Stefano Sabatini committed
        double secs;
        int hours, mins;
Stefano Sabatini's avatar
Stefano Sabatini committed
        mins  = (int)secs / 60;
        secs  = secs - mins * 60;
        hours = mins / 60;
        mins %= 60;
        snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs);
    } else {
        const char *prefix_string = "";
            long long int index;

            if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) {
                index = (long long int) (log2(vald)) / 10;
                index = av_clip(index, 0, FF_ARRAY_ELEMS(binary_unit_prefixes) - 1);
                vald /= pow(2, index * 10);
                prefix_string = binary_unit_prefixes[index];
            } else {
                index = (long long int) (log10(vald)) / 3;
                index = av_clip(index, 0, FF_ARRAY_ELEMS(decimal_unit_prefixes) - 1);
                vald /= pow(10, index * 3);
                prefix_string = decimal_unit_prefixes[index];
            }
        if (show_float || (use_value_prefix && vald != (long long int)vald))
            l = snprintf(buf, buf_size, "%f", vald);
        else
            l = snprintf(buf, buf_size, "%lld", (long long int)vald);
        snprintf(buf+l, buf_size-l, "%s%s%s", *prefix_string || show_value_unit ? " " : "",
                 prefix_string, show_value_unit ? uv.unit : "");
typedef struct WriterContext WriterContext;
#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1
#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2
typedef struct Writer {
    int priv_size;                  ///< private size for the writer context
    const char *name;
    int  (*init)  (WriterContext *wctx, const char *args, void *opaque);
    void (*uninit)(WriterContext *wctx);

    void (*print_header)(WriterContext *ctx);
    void (*print_footer)(WriterContext *ctx);

    void (*print_chapter_header)(WriterContext *wctx, const char *);
    void (*print_chapter_footer)(WriterContext *wctx, const char *);
    void (*print_section_header)(WriterContext *wctx, const char *);
    void (*print_section_footer)(WriterContext *wctx, const char *);
    void (*print_integer)       (WriterContext *wctx, const char *, long long int);
    void (*print_rational)      (WriterContext *wctx, AVRational *q, char *sep);
    void (*print_string)        (WriterContext *wctx, const char *, const char *);
    void (*show_tags)           (WriterContext *wctx, AVDictionary *dict);
    int flags;                  ///< a combination or WRITER_FLAG_*
} Writer;

struct WriterContext {
    const AVClass *class;           ///< class of the writer
    const Writer *writer;           ///< the Writer of which this is an instance
    char *name;                     ///< name of this writer instance
    void *priv;                     ///< private data for use by the filter
    unsigned int nb_item;           ///< number of the item printed in the given section, starting at 0
    unsigned int nb_section;        ///< number of the section printed in the given section sequence, starting at 0
    unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section
    unsigned int nb_section_frame;  ///< number of the frame  section in case we are in "packets_and_frames" section
    unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames
    unsigned int nb_chapter;        ///< number of the chapter, starting at 0
    int multiple_sections;          ///< tells if the current chapter can contain multiple sections
    int is_fmt_chapter;             ///< tells if the current chapter is "format", required by the print_format_entry option
    int is_packets_and_frames;      ///< tells if the current section is "packets_and_frames"
static const char *writer_get_name(void *p)
{
    WriterContext *wctx = p;
    return wctx->writer->name;
}

static const AVClass writer_class = {
    "Writer",
Loading
Loading full blame...