#创作者激励# 音视频开发_获取媒体文件的详细信息 原创

DS小龙哥
发布于 2023-3-15 13:12
浏览
0收藏

一、前言

做音视频开发过程中,经常需要获取媒体文件的详细信息。

比如:获取视频文件的总时间、帧率、尺寸、码率等等信息。 获取音频文件的的总时间、帧率、码率,声道等信息。 这篇文章贴出2个我封装好的函数,直接调用就能获取媒体信息返回,copy过去就能使用,非常方便。

如果要获取详细信息,可以使用ffprobe实现,也可以调用ffmpeg函数直接打开视频解析获取。

下面会演示两种方式,一种直接调用 ffprobe.exe实现,一种是调用ffmpeg函数直接打开视频解析获取。

如果调用ffprobe.exe实现,可以编译ffmpeg源码,以静态方式编译ffprobe.exe,这样调用起来比较方便,不需要带任何的依赖库。

下面 调用ffprobe.exe以JSON形式输出媒体文件的详细信息。

ffprobe -v quiet -of json -i D:/123.mp4  -show_streams

执行之后直接通过JSON格式输出:

C:\Users\11266>ffprobe -v quiet -of json -i D:/123.mp4  -show_streams
{
    "streams": [
        {
            "index": 0,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "LC",
            "codec_type": "audio",
            "codec_time_base": "1/88200",
            "codec_tag_string": "mp4a",
            "codec_tag": "0x6134706d",
            "sample_fmt": "fltp",
            "sample_rate": "88200",
            "channels": 2,
            "channel_layout": "stereo",
            "bits_per_sample": 0,
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/44100",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 4141046,
            "duration": "93.901270",
            "bit_rate": "127948",
            "max_bit_rate": "132760",
            "nb_frames": "4045",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2015-04-30T02:43:22.000000Z",
                "language": "und",
                "handler_name": "GPAC ISO Audio Handler"
            }
        },
        {
            "index": 1,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
            "profile": "Main",
            "codec_type": "video",
            "codec_time_base": "2349/70450",
            "codec_tag_string": "avc1",
            "codec_tag": "0x31637661",
            "width": 1280,
            "height": 720,
            "coded_width": 1280,
            "coded_height": 720,
            "has_b_frames": 0,
            "sample_aspect_ratio": "1:1",
            "display_aspect_ratio": "16:9",
            "pix_fmt": "yuv420p",
            "level": 51,
            "chroma_location": "left",
            "refs": 1,
            "is_avc": "true",
            "nal_length_size": "4",
            "r_frame_rate": "25/1",
            "avg_frame_rate": "35225/2349",
            "time_base": "1/30000",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 2816400,
            "duration": "93.880000",
            "bit_rate": "582474",
            "bits_per_raw_sample": "8",
            "nb_frames": "1409",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2015-04-30T02:43:23.000000Z",
                "language": "und",
                "handler_name": "GPAC ISO Video Handler"
            }
        }
    ]
}

如果只是想要得到 媒体的总时长、尺寸信息,那么执行下面命令即可:

C:\Users\11266>ffprobe -i D:/123.mp4
ffprobe version 4.2.2 Copyright (c) 2007-2019 the FFmpeg developers
  built with gcc 9.2.1 (GCC) 20200122
  configuration: --disable-static --enable-shared --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'D:/123.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: mp42isom
    creation_time   : 2015-04-30T02:43:22.000000Z
  Duration: 00:01:33.90, start: 0.000000, bitrate: 715 kb/s
    Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 88200 Hz, stereo, fltp, 127 kb/s (default)
    Metadata:
      creation_time   : 2015-04-30T02:43:22.000000Z
      handler_name    : GPAC ISO Audio Handler
    Stream #0:1(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 582 kb/s, 15 fps, 25 tbr, 30k tbn, 20000k tbc (default)
    Metadata:
      creation_time   : 2015-04-30T02:43:23.000000Z
      handler_name    : GPAC ISO Video Handler

二、调用ffprobe获取媒体信息

下面利用Qt编写代码调用ffprobe可执行文件,解析媒体信息输出。

下面封装了2个函数,完整媒体信息的解析返回。

【1】获取尺寸和时长

//媒体信息
struct MEDIA_INFO
{
	int width;  //宽度
	int	height; //高度
	qint64 duration;//视频总时长--毫秒 
};


//获取视频的尺寸和总时间信息
struct MEDIA_INFO GetVideo_SizeInfo(QString file)
{
	int w, h;
	struct MEDIA_INFO info = {0,0,0};

	//拼接ffmpge的路径
	QString cmd = QString("%1 -i \"%2\"").arg(FFPROBE_NAME).arg(file);


	QProcess process;
	process.setProcessChannelMode(QProcess::MergedChannels);
	process.start(cmd.toUtf8());
	process.waitForFinished();
	process.waitForReadyRead();

	//qDebug() << "cmd:" << cmd;

	if (process.exitCode() == 0)
	{
		log_printf(QString("Run Success"));

		QString qba = process.readAll();

		QByteArray utf8_str = qba.toUtf8();

		// Match duration
		QRegularExpression reDuration("Duration: (\\d{2}:\\d{2}:\\d{2}\\.\\d{2})");
		QRegularExpressionMatch matchDuration = reDuration.match(utf8_str);

		if (matchDuration.hasMatch()) 
		{
			QString duration = matchDuration.captured(1);

			// "00:06:37.15"
			qDebug() << "视频总时间:" << duration;
			int hour=duration.section(":", 0, 0).toInt();
			int minute = duration.section(":", 1, 1).toInt();
			int second = duration.section(":", 2, 3).section(".",0,0).toInt();
			int ms = duration.section(":", 2, 3).section(".", 1, 1).toInt();
			info.duration= hour * 60 * 60 *1000 + minute * 60 *1000 + second*1000 + ms;
		}
		else 
		{
			qDebug() << "No duration match found.";
		}

		// Match resolution
		QRegularExpression reResolution("\\d{3,4}x\\d{3,4}");
		QRegularExpressionMatch matchResolution = reResolution.match(utf8_str);

		if (matchResolution.hasMatch()) 
		{
			QString resolution = matchResolution.captured(0);
			//qDebug() << "视频尺寸:" << resolution;
			//qDebug() << "视频尺寸--w:" << resolution.section("x", 0, 0);
			//qDebug() << "视频尺寸--h:" << resolution.section("x", 1, 1);

			info.width = resolution.section("x", 0, 0).toInt();
			info.height = resolution.section("x", 1, 1).toInt();
		}
		else 
		{
			qDebug() << "No resolution match found.";
		}

	}
	else
	{
		log_printf(QString("Run ERROR"));
		return info;
	}

	return info;
}

【2】获取媒体详细并解析出来

// 定义用于存储解析结果的结构体
struct Stream {
	int index;
	QString codecName;
	QString codecLongName;
	QString profile;
	QString codecType;
	QString codecTimeBase;
	QString codecTagString;
	QString codecTag;
	int width;
	int height;
	int codedWidth;
	int codedHeight;
	bool hasBFrames;
	QString pixFmt;
	int level;
	QString colorRange;
	QString colorSpace;
	QString colorTransfer;
	QString colorPrimaries;
	QString chromaLocation;
	int refs;
	bool isAVC;
	int nalLengthSize;
	QString rFrameRate;
	QString avgFrameRate;
	QString timeBase;
	qint64 startPts;
	QString startTime;
	qint64 durationTs;
	QString duration;
	int bitRate;
	int bitsPerRawSample;
	int nbFrames;
	struct Disposition {
		int defaultValue;
		int dub;
		int original;
		int comment;
		int lyrics;
		int karaoke;
		int forced;
		int hearingImpaired;
		int visualImpaired;
		int cleanEffects;
		int attachedPic;
		int timedThumbnails;
	} disposition;
	struct Tags {
		QString language;
		QString handlerName;
	} tags;
};



//解析存放媒体信息的JSON结构
QVector<Stream> DecodeMediaInfo(QString mediafile)
{
	QByteArray  byte_data=mediafile.toUtf8();

	//获取媒体信息
	QByteArray jsonStr = GetMediaInfo(byte_data.data());


	// 将json字符串转换为json文档对象
	QJsonDocument doc = QJsonDocument::fromJson(jsonStr);

	// 获取顶层json对象
	QJsonObject topLevelObj = doc.object();

	// 获取streams数组
	QJsonArray streamsArray = topLevelObj.value("streams").toArray();

	// 遍历streams数组,将每个元素转换为Stream结构体
	QVector<Stream> streamVec;
	for (const QJsonValue & streamValue : streamsArray) {
		QJsonObject streamObj = streamValue.toObject();

		// 创建新的Stream实例,并设置属性值
		Stream stream;
		stream.index = streamObj.value("index").toInt();
		stream.codecName = streamObj.value("codec_name").toString();
		stream.codecLongName = streamObj.value("codec_long_name").toString();
		stream.profile = streamObj.value("profile").toString();
		stream.codecType = streamObj.value("codec_type").toString();
		stream.codecTimeBase = streamObj.value("codec_time_base").toString();
		stream.codecTagString = streamObj.value("codec_tag_string").toString();
		stream.codecTag = streamObj.value("codec_tag").toString();
		stream.width = streamObj.value("width").toInt();
		stream.height = streamObj.value("height").toInt();
		stream.codedWidth = streamObj.value("coded_width").toInt();
		stream.codedHeight = streamObj.value("coded_height").toInt();
		stream.hasBFrames = streamObj.value("has_b_frames").toBool();
		stream.pixFmt = streamObj.value("pix_fmt").toString();
		stream.level = streamObj.value("level").toInt();
		stream.colorRange = streamObj.value("color_range").toString();
		stream.colorSpace = streamObj.value("color_space").toString();
		stream.colorTransfer = streamObj.value("color_transfer").toString();
		stream.colorPrimaries = streamObj.value("color_primaries").toString();
		stream.chromaLocation = streamObj.value("chroma_location").toString();
		stream.refs = streamObj.value("refs").toInt();
		stream.isAVC = streamObj.value("is_avc").toBool();
		stream.nalLengthSize = streamObj.value("nal_length_size").toInt();
		stream.rFrameRate = streamObj.value("r_frame_rate").toString();
		stream.avgFrameRate = streamObj.value("avg_frame_rate").toString();
		stream.timeBase = streamObj.value("time_base").toString();
		stream.startPts = streamObj.value("start_pts").toInt();
		stream.startTime = streamObj.value("start_time").toString();
		stream.durationTs = streamObj.value("duration_ts").toInt();
		stream.duration = streamObj.value("duration").toString();
		stream.bitRate = streamObj.value("bit_rate").toInt();
		stream.bitsPerRawSample = streamObj.value("bits_per_raw_sample").toInt();
		stream.nbFrames = streamObj.value("nb_frames").toInt();

		// 解析disposition对象
		QJsonObject dispositionObj = streamObj.value("disposition").toObject();
		stream.disposition.defaultValue = dispositionObj.value("default").toInt();
		stream.disposition.dub = dispositionObj.value("dub").toInt();
		stream.disposition.original = dispositionObj.value("original").toInt();
		stream.disposition.comment = dispositionObj.value("comment").toInt();
		stream.disposition.lyrics = dispositionObj.value("lyrics").toInt();
		stream.disposition.karaoke = dispositionObj.value("karaoke").toInt();
		stream.disposition.forced = dispositionObj.value("forced").toInt();
		stream.disposition.hearingImpaired = dispositionObj.value("hearing_impaired").toInt();
		stream.disposition.visualImpaired = dispositionObj.value("visual_impaired").toInt();
		stream.disposition.cleanEffects = dispositionObj.value("clean_effects").toInt();
		stream.disposition.attachedPic = dispositionObj.value("attached_pic").toInt();
		stream.disposition.timedThumbnails = dispositionObj.value("timed_thumbnails").toInt();

		// 解析tags对象
		QJsonObject tagsObj = streamObj.value("tags").toObject();
		stream.tags.language = tagsObj.value("language").toString();
		stream.tags.handlerName = tagsObj.value("handler_name").toString();

		// 将Stream实例添加到vector中
		streamVec.append(stream);

		// 打印解析结果
		for (const Stream & stream : streamVec) {
			qDebug() << "Index:" << stream.index
				<< "Codec Name:" << stream.codecName
				<< "Codec Long Name:" << stream.codecLongName
				<< "Profile:" << stream.profile
				<< "Codec Type:" << stream.codecType
				<< "Codec Time Base:" << stream.codecTimeBase
				<< "Codec Tag String:" << stream.codecTagString
				<< "Codec Tag:" << stream.codecTag
				<< "Width:" << stream.width
				<< "Height:" << stream.height
				<< "Coded Width:" << stream.codedWidth
				<< "Coded Height:" << stream.codedHeight
				<< "Has B Frames:" << stream.hasBFrames
				<< "Pixel Format:" << stream.pixFmt
				<< "Level:" << stream.level
				<< "Color Range:" << stream.colorRange
				<< "Color Space:" << stream.colorSpace
				<< "Color Transfer:" << stream.colorTransfer
				<< "Color Primaries:" << stream.colorPrimaries
				<< "Chroma Location:" << stream.chromaLocation
				<< "Refs:" << stream.refs
				<< "Is AVC:" << stream.isAVC
				<< "NAL Length Size:" << stream.nalLengthSize
				<< "R Frame Rate:" << stream.rFrameRate
				<< "Avg Frame Rate:" << stream.avgFrameRate
				<< "Time Base:" << stream.timeBase
				<< "Start PTS:" << stream.startPts
				<< "Start Time:" << stream.startTime
				<< "Duration TS:" << stream.durationTs
				<< "Duration:" << stream.duration
				<< "Bitrate:" << stream.bitRate
				<< "Bits per Raw Sample:" << stream.bitsPerRawSample
				<< "Number of Frames:" << stream.nbFrames
				<< "Disposition Default Value:" << stream.disposition.defaultValue
				<< "Disposition Dub:" << stream.disposition.dub
				<< "Disposition Original:" << stream.disposition.original
				<< "Disposition Comment:" << stream.disposition.comment
				<< "Disposition Lyrics:" << stream.disposition.lyrics
				<< "Disposition Karaoke:" << stream.disposition.karaoke
				<< "Disposition Forced:" << stream.disposition.forced
				<< "Disposition Hearing Impaired:" << stream.disposition.hearingImpaired
				<< "Disposition Visual Impaired:" << stream.disposition.visualImpaired
				<< "Disposition Clean Effects:" << stream.disposition.cleanEffects
				<< "Disposition Attached Pic:" << stream.disposition.attachedPic
				<< "Disposition Timed Thumbnails:" << stream.disposition.timedThumbnails
				<< "Tags Language:" << stream.tags.language
				<< "Tags Handler Name:" << stream.tags.handlerName;
		}
	}
	return streamVec;
}

三、调用ffmpeg函数获取媒体信息

如果在程序里不方便调用ffprobe.exe,那么也可以直接调用ffmpeg的函数,打开视频、音频解析媒体数据。

【1】获取视频信息

下面给出代码:

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/dict.h>

int main()
{
    AVFormatContext *format_ctx = NULL;
    int ret;

    // 打开视频文件
    ret = avformat_open_input(&format_ctx, "video.mp4", NULL, NULL);
    if (ret != 0) {
        printf("无法打开视频文件\n");
        return -1;
    }

    // 获取视频文件中每个流的详细信息
    ret = avformat_find_stream_info(format_ctx, NULL);
    if (ret < 0) {
        printf("无法获取视频流信息\n");
        return -1;
    }

    // 输出视频流的详细信息
    for (int i = 0; i < format_ctx->nb_streams; i++) {
        AVStream *stream = format_ctx->streams[i];
        AVCodecParameters *params = stream->codecpar;
        AVRational time_base = stream->time_base;
        printf("流%d:\n", i);
        printf("  时间基数:%d/%d\n", time_base.num, time_base.den);
        printf("  编码器ID:%d\n", params->codec_id);
        printf("  视频宽度:%d\n", params->width);
        printf("  视频高度:%d\n", params->height);
        printf("  帧率:%d/%d\n", stream->avg_frame_rate.num, stream->avg_frame_rate.den);
    }

    // 获取元数据(metadata)
    AVDictionaryEntry *tag = NULL;
    while ((tag = av_dict_get(format_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
        printf("%s=%s\n", tag->key, tag->value);
    }

    // 关闭输入文件
    avformat_close_input(&format_ctx);
    return 0;
}

这个代码片段可以在Linux或Windows操作系统上编译,并且需要在编译时链接FFmpeg库。

【2】获取视频、音频详细信息

#include <stdio.h>
#include <libavformat/avformat.h>

int main(int argc, char **argv) {

    AVFormatContext *fmt_ctx = NULL;
    AVDictionaryEntry *tag = NULL;

    // 打开输入媒体文件
    if (avformat_open_input(&fmt_ctx, argv[1], NULL, NULL) < 0) {
        fprintf(stderr, "Cannot open input file\n");
        return -1;
    }

    // 获取媒体文件信息
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Cannot find stream information\n");
        avformat_close_input(&fmt_ctx);
        return -1;
    }

    // 输出媒体文件信息
    printf("File: %s\n", argv[1]);
    printf("Format: %s\n", fmt_ctx->iformat->name);
    printf("Duration: %lld seconds\n", fmt_ctx->duration / AV_TIME_BASE);

    for (int i = 0; i < fmt_ctx->nb_streams; i++) {
        AVStream *stream = fmt_ctx->streams[i];

        const char *type = "Unknown";
        if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            type = "Video";
            printf("\n%s Stream #%d:\n", type, i);
            printf("Codec: %s\n", avcodec_get_name(stream->codecpar->codec_id));
            printf("Resolution: %dx%d\n", stream->codecpar->width, stream->codecpar->height);
            printf("Frame Rate: %.2f fps\n", av_q2d(stream->avg_frame_rate));
            printf("Bit Rate: %lld kbps\n", stream->codecpar->bit_rate / 1000);
        } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            type = "Audio";
            printf("\n%s Stream #%d:\n", type, i);
            printf("Codec: %s\n", avcodec_get_name(stream->codecpar->codec_id));
            printf("Sample Rate: %d Hz\n", stream->codecpar->sample_rate);
            printf("Channels: %d\n", stream->codecpar->channels);
            printf("Bit Rate: %lld kbps\n", stream->codecpar->bit_rate / 1000);
        }

        // 输出流的元数据信息
        while ((tag = av_dict_get(stream->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
            printf("%s=%s\n", tag->key, tag->value);
        }
    }

    // 关闭输入媒体文件
    avformat_close_input(&fmt_ctx);

    return 0;
}

使用方法:

  1. 将示例代码保存为ffprobe.c文件。
  2. 在命令行中进入该文件所在目录,执行以下命令进行编译:
gcc -o ffprobe ffprobe.c -lavformat -lavcodec -lavutil
  1. 执行以下命令获取视频或音频文件的全部参数信息:
./ffprobe [input_file]

其中,[input_file]是输入的视频或音频文件路径。

例如,执行以下命令获取test.mp4视频文件的全部参数信息:

./ffprobe test.mp4

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
ffmpeg.exe+ffprobe.exe+ffplay.exe.rar 45.77M 8次下载
1
收藏
回复
举报
回复
    相关推荐