编码一个文件, 用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