一、
AVFormatContext 结构体描述了一个媒体文件或媒体流的构成和基本信息
int avformat_open_input(AVFormatContext **ps,
const char *url, //URL of the stream to open
AVInputFormat *fmt,
AVDictionary **options
);
int re=avformat_open_input(&ic, path, 0 ,0);
void avformat_close_input(AVFormatContext **s);
具体的错误描述信息
av_strerror(re, buf, sizeof (buf)-1);
av_strerror(re, buf, sizeof (buf)-1);
流的持续时间,以平均时间为单位秒
int64_t duration;
AV_TIME_BASE
#define AV_TIME_BASE 1000000
打印有关输入或输出格式的详细信息,例如持续时间、比特率、流、容器、程序、元数据、边数据,编解码器和tinme base。
void av_dump_format(AVFormatContext *ic,
int index, //streamde 索引
const char *url, //源文件或者目标文件
int is_output); 选择上下文是输入(0)还是输出(1)
av_dump_format(ic,0,path,0);
初始化网络库(可以打开rtsp rtmp http 协议的流媒体视频)
avformat_network_init();
设置rtsp流使用tcp协议打开
av_dict_set(&opts, "rtsp_transport", "tcp", 0);
网络延迟时间
av_dict_set(&opts,"max_delay", "500", 0);
获取流信息
re =avformat_find_stream_info(ic,0);
AVCodecParameters结构体描述编码流的属性。
二、获取音视频流信息通畅使用遍历和函数
for (int i = 0; i < ic->nb_streams; i++)
{
AVStream *as = ic->streams[i]; //索引大小
cout << "codec_id = " << as->codecpar->codec_id << endl;
cout << "format = " << as->codecpar->format << endl;
遍历
//音频 AVMEDIA_TYPE_AUDIO
//as->codecpar包含了一些类型数据
if (as->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
audioStream = i;
cout <<i<< "音频信息" << endl;
cout << "帧率= " << as->codecpar->sample_rate << endl;
//AVSampleFormat;
cout << "channels = " << as->codecpar->channels << endl;
//一帧数据 单通道样本数
cout << "frame_size = " << as->codecpar->frame_size << endl;
//双通道 1024 * 2 * 2 = 4096 fps = sample_rate/frame_size
}
//视频 AVMEDIA_TYPE_VIDEO
else if (as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
cout << i << "视频信息" << endl;
cout << "width=" << as->codecpar->width << endl;
cout << "height=" << as->codecpar->height << endl;
//帧率 fps 分数转换
cout<<"video fps = " <<r2d(as->avg_frame_rate)<<endl;
}
}
获取视频流函数
videoStream = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
///ic->streams[videoStream]
三、AV_read_frame中相关参数及函数
AVPacket:
AVBufferRef *buf 引用通常不用管
pts 显示时间 dts 解码时间
AVPacket *av_Packet_alloc(Void);创建并初始化,只创建对象(堆)
AVPacket *av_Pakcet_clone(const AVPacket *src); //创建并用计数
同步需要两个队列进行同步,需要克隆
int av_Packet_ref(AvPacket *dst,const AVPacket *src); //引用增加
int av_Packet_unref(AVPacket *pkt); //引用减少
void av_packet_free(AVPacket **pkt); //清空对象并减引用计数
int av_Packet_from_data(AVPacket *pkt,uint8_t *data,int size); //制作packet
int av_copy_packet(); //老式版本,类似于深拷贝,比较浪费时间。
av_seek_frame 滑动条拖动时需要
int av_seek_frame(AVFormatContext *s,
int stream_index, //-1 default
int64_t timestamp, //AVstream,timebase
int flags);
其中flag:
#define AVSEEK_FLAG_BACKWARD 1 //seekbackward
#define AVSEEK_FLAG_BYTE 2
#define AVSEEK_FLAG_ANY 4 //找最近任一帧
#define AVSEEK_FLAG_FRAME 8 //找关键帧
示例代码:
#include <thread>
void XSleep(int ms)
{
//c++ 11 为了支持跨平台
chrono::milliseconds du(ms);
this_thread::sleep_for(du);
}
#pragma comment(lib,"avcodec.lib")
static double r2d(AVRational r)
{
return r.den == 0 ? 0:(double)r.num / (double)r.den;
}
//malloc AVPacket并初始化
AVPacket *pkt = av_packet_alloc();
for (;;)
{
int re = av_read_frame(ic, pkt);
if (re != 0)
{
//循环播放
cout << "==============================end==============================" << endl;
int ms = 3000; //三秒位置 根据时间基数(分数)转换
long long pos = (double)ms/ (double)1000*r2d(ic->streams[pkt->stream_index]->time_base);
av_seek_frame(ic, videoStream, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
continue;
}
cout << "pkt->size = "<< pkt->size << endl;
//显示的时间
cout << "pkt->pts = " << pkt->pts << endl;
//转换为毫秒,方便做同步
cout << "pkt->pts ms = " << pkt->pts * (r2d(ic->streams[pkt->stream_index]->time_base) * 1000) << endl;
//解码时间
cout << "pkt->dts = " << pkt->dts << endl;
if (pkt->stream_index == videoStream)
{
cout << "图像" << endl;
}
if (pkt->stream_index == audioStream)
{
cout << "音频" << endl;
}
//释放,引用计数-1 为0释放空间
av_packet_unref(pkt);
//XSleep(500);
}
av_packet_free(&pkt);