1. 获取像素格式转换的上下文
sws_getCachedContext
2. 像素转换
sws_scale
#include
#include
using namespace std;
//测试解封装
extern "C"{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
}
//引用库
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"swscale.lib")
//static修饰的分数转浮点函数,避免功能性函数重定义
static double r2d(AVRational r)
{
return (r.den == 0) ? 0 : (double)r.num/(double)r.den;
}
void XSleep(int ms)
{
// c++11
chrono::milliseconds du(ms);
this_thread::sleep_for(du);
}
int main(int argc, char* argv[])
{
cout << "Test Demux FFmpeg.club" << endl;
//初始化封装库
av_register_all();
//初始化网络库 可以打开rtsp rtmp http 协议的流媒体视频)
avformat_network_init();
//注册解码器
avcodec_register_all();
//参数设置
AVFormatContext *ic = NULL;
const char* path = "abc.mp4";
AVDictionary *opts = NULL;//NULL表示使用默认配置
//设置rtsp流,以tcp协议打开
//av_dict_set(&opts, "rtsp_transport", "tcp", 0);
//设置网络延时时间
//av_dict_set(&opts, "max_delay", "500", 0);
//解封装上下文
int ret = avformat_open_input(
&ic,
path, //视频源
0, //0表示自动选择解封装器
&opts //参数设置,比如rtsp的延时时间
);
if (ret != 0)
{
char buff[1024] = { 0 };
av_strerror(ret, buff, sizeof(buff) - 1);
cout << "open " << path << " failed ! :" << buff << endl;
getchar();
return -1;
}
cout << "open " << path << " succeed !" << endl;
//获取流信息
ret = avformat_find_stream_info(ic, 0);
//总时长
int totalTime = ic->duration/AV_TIME_BASE;
cout << path << " total time is " << totalTime << " s." << endl;
//打印视频流详细信息
av_dump_format(ic, 0, path, 0);
//音视频索引,用于读取时区分音视频数据
int audioStream = 0;
int videoStream = 1;
//获取音视频流信息 (通过遍历,或函数获取)
//遍历方式
for (int i = 0; i < ic->nb_streams; i++)
{
AVStream *as = ic->streams[i];
cout << "format = " << as->codecpar->format << endl;
cout << "codec_id = " << as->codecpar->codec_id << endl;
//音频
if (as->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
{
audioStream = i;
cout << i << "音频信息" << endl;
cout << "sample_rate = " <codecpar->sample_rate << endl;
//AVSampleFormat
cout << "channels = " << as->codecpar->channels << endl;
//一帧数据:单通道样本数
cout << "frame size = " << as->codecpar->frame_size << endl;
}
//视频
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;
}
}
//函数方式获取
audioStream = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
///
//视频解码器打开
//找到解码器
AVCodec *vcodec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
if (!vcodec)
{
cout << "couldn't found the codec, codec_id is " << ic->streams[videoStream]->codecpar->codec_id << endl;
getchar();
return -1;
}
cout << "video AVCodec id is :" << ic->streams[videoStream]->codecpar->codec_id << endl;
//创建解码器上下文
AVCodecContext *vc = avcodec_alloc_context3(vcodec);
//配置解码器上下文参数(由streams中的配置复制过来)
avcodec_parameters_to_context(vc, ic->streams[videoStream]->codecpar);
//8线程解码
vc->thread_count = 8;
//打开解码器上下文
ret = avcodec_open2(vc, 0, 0);
if (ret != 0)
{
char buff[1024] = { 0 };
av_strerror(ret, buff, sizeof(buff) - 1);
cout << "avcodec_open2 error ! " << buff << endl;
getchar();
return -1;
}
cout << "video avcodec_open2 succeed ! " << endl;
getchar();
///
//音频解码器打开
//找到解码器
AVCodec *acodec = avcodec_find_decoder(ic->streams[audioStream]->codecpar->codec_id);
if (!acodec)
{
cout << "couldn't found the codec, codec_id is " << ic->streams[audioStream]->codecpar->codec_id << endl;
getchar();
return -1;
}
cout << "audio AVCodec id is :" << ic->streams[audioStream]->codecpar->codec_id << endl;
//创建解码器上下文
AVCodecContext *ac = avcodec_alloc_context3(acodec);
//配置解码器上下文参数(由streams中的配置复制过来)
avcodec_parameters_to_context(ac, ic->streams[audioStream]->codecpar);
//8线程解码
vc->thread_count = 8;
//打开解码器上下文
ret = avcodec_open2(ac, 0, 0);
if (ret != 0)
{
char buff[1024] = { 0 };
av_strerror(ret, buff, sizeof(buff) - 1);
cout << "avcodec_open2 error ! " << buff << endl;
getchar();
return -1;
}
cout << "audio avcodec_open2 succeed ! " << endl;
getchar();
//AVPacket 申请空间、初始化
AVPacket *pkt = av_packet_alloc();
//AVFrame 申请空间、初始化
AVFrame *frame = av_frame_alloc();
//像素格式转换上下文
SwsContext *vctx = NULL;
unsigned char *rgb = NULL;
while (1)
{
int ret = av_read_frame(ic, pkt);
if (ret)
{
//读到结尾
cout << "==============end==============" << endl;
//跳转到3秒位置
int ms = 3000;//3秒,根据时间基数转换
int64_t pos = (double)ms / (double)1000 * r2d(ic->streams[pkt->stream_index]->time_base);
av_seek_frame(ic, 0, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
cout << " \\ \\ \\ \\ \\ \\ \\ \\ at 3 ms" << endl;
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;
//XSleep(500);
//解码的时间
cout << "pkt->dts = " << pkt->dts << endl;
//解码上下文
AVCodecContext *cc = 0;
if (pkt->stream_index == videoStream)
{
cc = vc;
cout << "图像" << endl;
}
if (pkt->stream_index == audioStream)
{
cc = ac;
cout << "音频" << endl;
}
///解码视频
//发送packet到线程解码,发完立即返回
ret = avcodec_send_packet(cc, pkt);
//释放库内部单次使用的内存,并将引用计数-1
av_packet_unref(pkt);
if (ret != 0)
{
char buff[1024] = { 0 };
av_strerror(ret, buff, sizeof(buff) - 1);
cout << " avcodec_send_packet error, " << buff << endl;
continue;
}
while (1)
{
//从线程中拿解码后的数据,一次send可能对应多次receive
ret = avcodec_receive_frame(cc, frame);
if (ret != 0)
{
break;
}
cout << " recv frame " << frame->format << " " << frame->linesize[0] << endl;
//视频像素转换
if (cc == vc)
{
//创建或拿到转换上下文
vctx = sws_getCachedContext(
vctx, //传递NULL会新创建
frame->width, frame->height, //输入的宽高
(AVPixelFormat)frame->format, //输入的格式
frame->width, frame->height, //输出的宽高
AV_PIX_FMT_RGBA, //输出格式RGBA
SWS_BILINEAR, //转换的算法
0,0,0);
if (vctx)
{
cout << " 像素格式尺寸转换上下文创建或者获取成功 ! " << endl;
if (rgb == NULL)
{
rgb = new unsigned char[frame->width*frame->height * 4];
}
uint8_t *data[2] = { 0 };
data[0] = rgb;
int lines[2] = { 0 };
lines[0] = frame->width * 4;
//调用像素转换
sws_scale(
vctx,
frame->data, //输入数据
frame->linesize, //输入行大小
0,
frame->height, //输入高度
data, //输出的数据和大小
lines
);
}
else
{
cout << " 像素格式尺寸转换上下文创建或者获取失败 ! " << endl;
}
}
}
}
//释放空间
av_frame_free(&frame);
av_packet_free(&pkt);
if (ic)
{
//释放封装上下文,并把ic并置0
avformat_close_input(&ic);
}
getchar();
return 0;
}