将ffprobe文件简化, 用于分析。 文件放在ffmpeg根目录,编译 gcc probe_test.c -I/mnt/hgfs/shared/ffmpeg/ffmpeg-4.0 -lavutil -lavformat -lavcodec , 已经提前安装ffmpeg库。
#include <string.h>
#include "libavformat/avformat.h"
#include "libavutil/opt.h"
#include "fftools/cmdutils.h"
typedef struct InputStream {
AVStream *st;
AVCodecContext *dec_ctx;
} InputStream;
typedef struct InputFile {
AVFormatContext *fmt_ctx;
InputStream *streams;
int nb_streams;
} InputFile;
AVDictionary *format_opts, *codec_opts;
int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
{
int ret = avformat_match_stream_specifier(s, st, spec);
if (ret < 0)
av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec);
return ret;
}
AVDictionary *filter_codec_opts(AVDictionary *opts, enum AVCodecID codec_id,
AVFormatContext *s, AVStream *st, AVCodec *codec)
{
AVDictionary *ret = NULL;
AVDictionaryEntry *t = NULL;
int flags = s->oformat ? AV_OPT_FLAG_ENCODING_PARAM
: AV_OPT_FLAG_DECODING_PARAM;
char prefix = 0;
const AVClass *cc = avcodec_get_class();
if (!codec)
codec = s->oformat ? avcodec_find_encoder(codec_id)
: avcodec_find_decoder(codec_id);
switch (st->codecpar->codec_type) {
case AVMEDIA_TYPE_VIDEO:
prefix = 'v';
flags |= AV_OPT_FLAG_VIDEO_PARAM;
break;
case AVMEDIA_TYPE_AUDIO:
prefix = 'a';
flags |= AV_OPT_FLAG_AUDIO_PARAM;
break;
case AVMEDIA_TYPE_SUBTITLE:
prefix = 's';
flags |= AV_OPT_FLAG_SUBTITLE_PARAM;
break;
}
while (t = av_dict_get(opts, "", t, AV_DICT_IGNORE_SUFFIX)) {
char *p = strchr(t->key, ':');
/* check stream specification in opt name */
if (p)
switch (check_stream_specifier(s, st, p + 1)) {
case 1: *p = 0; break;
case 0: continue;
default: exit(1);
}
if (av_opt_find(&cc, t->key, NULL, flags, AV_OPT_SEARCH_FAKE_OBJ) ||
!codec ||
(codec->priv_class &&
av_opt_find(&codec->priv_class, t->key, NULL, flags,
AV_OPT_SEARCH_FAKE_OBJ)))
av_dict_set(&ret, t->key, t->value, 0);
else if (t->key[0] == prefix &&
av_opt_find(&cc, t->key + 1, NULL, flags,
AV_OPT_SEARCH_FAKE_OBJ))
av_dict_set(&ret, t->key + 1, t->value, 0);
if (p)
*p = ':';
}
return ret;
}
AVDictionary **setup_find_stream_info_opts(AVFormatContext *s,
AVDictionary *codec_opts)
{
int i;
AVDictionary **opts;
if (!s->nb_streams)
return NULL;
opts = av_mallocz_array(s->nb_streams, sizeof(*opts));
if (!opts) {
av_log(NULL, AV_LOG_ERROR,
"Could not alloc memory for stream options.\n");
return NULL;
}
for (i = 0; i < s->nb_streams; i++)
opts[i] = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id,
s, s->streams[i], NULL);
return opts;
}
static int open_input_file(InputFile *ifile, const char *filename)
{
int err, i;
AVFormatContext *fmt_ctx = NULL;
AVDictionaryEntry *t;
AVInputFormat *iformat = NULL;
int find_stream_info = 1;
fmt_ctx = avformat_alloc_context();
if (!fmt_ctx) {
printf("error: avformat_alloc_context\n");
}
if ((err = avformat_open_input(&fmt_ctx, filename,
iformat, &format_opts)) < 0){
return err;
}
ifile->fmt_ctx = fmt_ctx;
if (find_stream_info) {
AVDictionary **opts = setup_find_stream_info_opts(fmt_ctx, codec_opts);
int orig_nb_streams = fmt_ctx->nb_streams;
err = avformat_find_stream_info(fmt_ctx, opts);
for (i = 0; i < orig_nb_streams; i++)
av_dict_free(&opts[i]);
av_freep(&opts);
if (err < 0) {
return err;
}
}
av_dump_format(fmt_ctx, 0, filename, 0);
ifile->streams = av_mallocz_array(fmt_ctx->nb_streams,
sizeof(*ifile->streams));
if (!ifile->streams)
exit(1);
ifile->nb_streams = fmt_ctx->nb_streams;
ifile->fmt_ctx = fmt_ctx;
return 0;
}
static void close_input_file(InputFile *ifile)
{
av_freep(&ifile->streams);
ifile->nb_streams = 0;
avformat_close_input(&ifile->fmt_ctx);
}
static int probe_file(const char *filename)
{
InputFile ifile = { 0 };
open_input_file(&ifile, filename);
if (ifile.fmt_ctx)
close_input_file(&ifile);
return 1;
}
int main(int argc, char **argv)
{
char input_filename[128]={0};
if(argc>1)
{
if(strlen(argv[1])<128)
{
memcpy(input_filename, argv[1], strlen(argv[1]));
input_filename[strlen(argv[1])] = '\0';
probe_file(input_filename);
}
else
{
printf("file path too long.\n");
}
}
else
{
printf("Usage: %s filename\n", argv[0]);
}
return 1;
}