ffmpeg av_dump_format 信息分析

编码一个文件, 用av_dump_format 打印出了如下信息, 到底是什么意思呢?

 Output #0, hls, to 'playlist.m3u8':
 Stream #0:0: Video: h264, yuv420p(tv, progressive), 640x480 [SAR 4:3 DAR 16:9], q=2-31, 2000 kb/s, 25 fps, 90k tbn
    Metadata:
      encoder         : Lavc58.134.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 0/0/2000000 buffer size: 0 vbv_delay: N/A
  Stream #0:1(eng): Audio: aac (LC), 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc58.134.100 aac


下面具体分析一下:
void av_dump_format(AVFormatContext *ic, int index, const char *url, int is_output)
-----------------------------------------------------------------------------------
 Output #0, hls, to 'playlist.m3u8':

编码时, is_output 为true , 打印 "Output" "to" 字符串
 0 : index, 代表第一个编码文件.
 hls : ic->oformat->name , 输出格式名称
 playlist.m3u8 : url    , 输出文件名


后面的信息是流信息,用以下函数形成的.
static void dump_stream_format(const AVFormatContext *ic, int i, int index, int is_output)
------------------------------------------------------------------------------------------
i:  是流的index, 例如第一个流是视频流,第二个流是音频流等, 从0开始. ic->streams[i]就是AVStream 流.
index: 是文件index, 例如第一个文件是输出0,第二个文件是输出1等. 从0开始.

它调用了:
avcodec_string(buf, sizeof(buf), avctx, is_output);
void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode)
------------------------------------------------------------------------------------------
1. 从AVFormatContext ic 可以得到AVCodecContext avctx, 参数从流参数中得到.
    avctx = avcodec_alloc_context3(NULL);
    ret = avcodec_parameters_to_context(avctx, st->codecpar); //还有未导入的参数,可以手工导入.
2.  字符串意义解释:

  $8 = "Video: h264, 1 reference frame, yuv420p(tv, progressive, left), 640x480 (0x0) [SAR 4:3 DAR 16:9], 0/1, q=2-31, 2000 kb/s
  AVCodecContext *enc,

    codec_type = av_get_media_type_string(enc->codec_type);  // Video(AVMEDIA_TYPE_VIDEO) 编码类型
    codec_name = avcodec_get_name(enc->codec_id);    // h264(AV_CODEC_ID_H264)    编码ID
                                      enc->refs     // 1 reference frame          frame 引用数
    av_get_pix_fmt_name(enc->pix_fmt)                // yuv420p(AV_PIX_FMT_YUV420P)    点格式
    av_color_range_name(enc->color_range)            // tv(AVCOL_RANGE_MPEG)            颜色范围
    enc->field_order                                // progressive                    填充顺序
    av_chroma_location_name(enc->chroma_sample_location) // left(AVCHROMA_LOC_LEFT)    色度采样位置
    enc->width * enc->height                        //640 * 480                        大小
    enc->coded_width * enc->codec_height            // 0*0                            编码大小

    enc->sample_aspect_ratio.num, enc->sample_aspect_ratio.den // SAR 4:3            采样宽高比

    display_aspect_ratio.num, display_aspect_ratio.den    // DAR 16:9                    显示宽高比
    DAR 的计算:

    av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,                    显示宽高比的计算.
              enc->width * (int64_t)enc->sample_aspect_ratio.num,         DAR=SAR * W/H
              enc->height * (int64_t)enc->sample_aspect_ratio.den,
              1024 * 1024)
    就是分数运算,计算640*4/(480*3) = 16:9  (准确值)
    enc->time_base.num/enc->time_base.den            // 0/1                    编码时基
    enc->qmin - enc->qmax                            //2-31                    编码质量
    bitrate = get_bit_rate(enc);                    //2000kb/s                bit 率

    st->avg_frame_rate                        // 25 fps
    st->r_frame_rate                        // 为0 时不打印 tbr
    st->time_base                            // 90K tbn
    st->codec->time_base                    // 50 tbc

内容有点乱,概念多, 附送一个自己写的测试程序把玩, 多用printf 打印就明白了.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern "C"
{
#include <libavformat/avformat.h>
#include <libavutil/pixdesc.h>
}
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
const char *path="/opt/test/caitiao_same_10s.ts";
int main()
{
	AVFormatContext *fmt_ctx=NULL;
	int ret=avformat_open_input(&fmt_ctx,path,NULL,0);
	if(ret!=0)
	{
		printf("error open file %s\n",path);
		exit(1);
	}
	printf("file opened\n");
	avformat_find_stream_info(fmt_ctx,NULL);
	av_dump_format(fmt_ctx,0,path,0);

	//自己打印的,心里才踏实!
	//格式,时长,比特率
	printf("format: %s\n",fmt_ctx->iformat->name);
	printf("duration:%ld\n",fmt_ctx->duration);
	printf("start time:%ld\n",fmt_ctx->start_time);
	printf("bitrate:%ld\n",fmt_ctx->bit_rate);
	//节目个数
	printf("节目个数:%d\n",fmt_ctx->nb_programs);
	//流信息和编码信息
	// codec 参数,视频编码方式,宽高,像素格式,音频编码格式,采样率,声道布局,等
	for(unsigned int i=0;i<fmt_ctx->nb_programs;i++)
	{
		AVProgram *program = fmt_ctx->programs[i];
		printf("program ID:%d\n",program->id);
		printf("节目信息: %d 个流\n",program->nb_stream_indexes);
		for(unsigned int j=0;j<program->nb_stream_indexes;j++)
		{
//			dump_stream_format(fmt_ctx,program->stream_index[i],i,0);
			int stream_index = program->stream_index[j];
			AVStream *st = fmt_ctx->streams[stream_index];
			AVCodecParameters* params=st->codecpar;
			printf("stream_index:%d, stream ID:%d\n",stream_index,st->id);
			const char *strCodecType=av_get_media_type_string(params->codec_type);
			const char *strCodecName=avcodec_get_name(params->codec_id);
			printf("codecID:%d,codecName:%s,codecType:%s\n",params->codec_id,strCodecName,strCodecType);
			if(st->codecpar->codec_type==AVMEDIA_TYPE_VIDEO)
			{
				const char *profileName=avcodec_profile_name(params->codec_id,params->profile);
				printf("profile:%s\n",profileName);
				//pix_fmt 格式?
				printf("pix_fmt:%s\n",av_get_pix_fmt_name((AVPixelFormat)params->format)); //用的format参数
				const char *field_order = "progressive";
				if(params->field_order==AV_FIELD_TT) field_order="top first";
				else if(params->field_order==AV_FIELD_BB) field_order="bottom first";
				else if(params->field_order==AV_FIELD_TB) field_order="top coded first";
				else if(params->field_order==AV_FIELD_BT) field_order="bottom coded first";
				printf("field_order:%s\n",field_order);
				printf("%d(w)*%d(h)\n",params->width,params->height);
				printf("SAR:%d:%d\n",params->sample_aspect_ratio.num,params->sample_aspect_ratio.den);
				//节目信息
				int fps = st->avg_frame_rate.den && st->avg_frame_rate.num;
				int tbr = st->r_frame_rate.den && st->r_frame_rate.num;
				int tbn = st->time_base.den && st->time_base.num;				
//        int tbc = st->codec->time_base.den && st->codec->time_base.num;
				if (fps)
					printf("%1.4f fps,平均帧率\n",av_q2d(st->avg_frame_rate));
				if (tbr)
					printf("%1.4f tbr,额定帧率\n",av_q2d(st->r_frame_rate));
				if (tbn)
					printf("%1.0fk time_base,流时基\n",1/av_q2d(st->time_base)/1000);
//				printf("q=%d-%d",params->qmin,params->qmax);
			}
			else if(st->codecpar->codec_type==AVMEDIA_TYPE_AUDIO)
			{
				printf("sample_rate:%d\n",params->sample_rate);
				int channels = av_get_channel_layout_nb_channels(params->channel_layout);
				//params->channels, 与channels 想同
				char buf[256];
				av_get_channel_layout_string(buf,sizeof(buf),params->channels,params->channel_layout);
				printf("channels:%d,channel_layout:%s(%ld)\n",channels,buf,params->channel_layout);
				printf("sample_fmt:%s\n",av_get_sample_fmt_name((AVSampleFormat)params->format)); //用的format 参数
				//音频bit率?
				int bit_rate = 0;
				int bits_per_sample = av_get_bits_per_sample(params->codec_id);
				if (bits_per_sample)
				{
					bit_rate = params->sample_rate * params->channels * bits_per_sample;
				}
				else
				{
					bit_rate = params->bit_rate;
				}
				printf("bit_rate:%d\n",bit_rate);
				
			}
		}
		
	}
	return 0; // 调试程序, 所以中途退出
	int vindex=av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
	if(vindex<0)
	{
		printf("not find video stream\n");
	}
	printf("vindex:%d\n",vindex);
	int aindex=av_find_best_stream(fmt_ctx,AVMEDIA_TYPE_AUDIO,-1,-1,NULL,0);
	if(aindex<0)
	{
		printf("not find audio stream\n");
	}
	printf("aindex:%d\n",aindex);
	
	AVPacket pkt;
	int c_v=0;
//	int c_a=0;
	long  a_old_dts=0;
	long  a_offset_dts;
	long  v_old_pts=0;
	long  v_offset_pts;
	while(1)
	{
		ret=av_read_frame(fmt_ctx,&pkt);
		if(ret==AVERROR_EOF) break;
		if(pkt.stream_index == vindex)
		{
			v_offset_pts = pkt.pts-v_old_pts;
			printf("v:%d,pkt.pts:%ld, dts:%ld,offset:%ld\n",c_v++,pkt.pts,pkt.dts,v_offset_pts);
			v_old_pts=pkt.pts;
		}
		else if (pkt.stream_index == aindex)
		{
			a_offset_dts = pkt.dts-a_old_dts;
//			printf("a:%d,pkt.pts:%ld, dts:%ld, duration:%ld, offset:%ld\n",c_a++,pkt.pts,pkt.dts,pkt.duration, a_offset_dts);
			a_old_dts = pkt.dts;
		}
	}
	return 0;
}

输出:

 ./av_dump_format
file opened
Input #0, mpegts, from '/opt/test/caitiao_same_10s.ts':
  Duration: 00:00:10.02, start: 1.474667, bitrate: 909 kb/s
  Program 1
    Metadata:
      service_name    : Service01
      service_provider: FFmpeg
  Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuvj420p(pc, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 90k tbn, 50 tbc
  Stream #0:1[0x101](eng): Audio: ac3 ([129][0][0][0] / 0x0081), 48000 Hz, stereo, fltp, 192 kb/s
format: mpegts
duration:10016000
start time:1474667
bitrate:909367
节目个数:1
program ID:1
节目信息: 2 个流
stream_index:0, stream ID:256
codecID:27,codecName:h264,codecType:video
profile:High
pix_fmt:yuvj420p
field_order:progressive
1920(w)*1080(h)
SAR:1:1
25.0000 fps,平均帧率
25.0000 tbr,额定帧率
90k time_base,流时基
stream_index:1, stream ID:257
codecID:86019,codecName:ac3,codecType:audio
sample_rate:48000
channels:2,channel_layout:stereo(3)
sample_fmt:fltp
bit_rate:192000

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
av_dump_format函数是FFmpeg中的一个非常有用的函数,可以用来打印音视频文件的信息,比如文件格式、时长、编码器等等。 该函数的定义如下: ```c void av_dump_format(AVFormatContext *ic, int index, const char *url, int is_output); ``` 其中,参数ic是一个AVFormatContext指针,表示音视频文件的上下文,它包含了音视频文件的所有信息;参数index表示要打印的流的索引,如果index为负数,则表示打印所有流的信息;参数url是一个字符串,表示音视频文件的文件名;参数is_output表示该文件是输入文件还是输出文件,如果是输入文件,则is_output为0,否则为1。 使用av_dump_format函数非常简单,只需要在打开音视频文件后调用该函数即可,例如: ```c AVFormatContext *ic = avformat_alloc_context(); if (avformat_open_input(&ic, filename, NULL, NULL) < 0) { printf("Failed to open file '%s'\n", filename); return -1; } if (avformat_find_stream_info(ic, NULL) < 0) { printf("Failed to retrieve input stream information\n"); return -1; } av_dump_format(ic, 0, filename, 0); ``` 这个例子中,我们首先使用avformat_alloc_context函数创建了一个AVFormatContext对象,然后通过avformat_open_input函数打开了音视频文件,再通过avformat_find_stream_info函数获取音视频文件的流信息,最后调用av_dump_format函数打印出文件的信息。 注意,av_dump_format函数会将信息打印到标准输出流中,如果需要将信息保存到文件中,可以重定向标准输出流。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值