前语
咱们前面三篇文章首要介绍了如安在各个干流途径下装备开发环境,那么从该篇初步就实在进入编码了。由于该系列定义为从 0 到 1 写一个跨途径播映器,所以我计划从浅到深,从根底到进阶的道路来进行。
咱们先来看一个流程图:
该系列文章就是将上图拆分opengles3.1扩展包为详windows11来了细的代码模块,那么该篇咱们首要解说怎样运用 FFmpeg API
来对一个输入数据进行解封装,读取原始音频视频信算法规划与剖析息,然后对音频视频做一些根本操作。根本上在播映器模块中用到的 FFmpeg API
咱们windows许可证行将过期怎样办都要对它有一个线程撕裂者了解。
ps: 假定对 Mac OS 、Window线程和进程的区别是什么s 、Linux 下不知道怎样装备windows7 QT & FFwindows11来了mpeg 环境的能够参考下面文章
跨途径播映器开发 (一) QT for MAC OSopengl三重缓冲开不开 & FFmpeg 环境建立
跨途径播映器开发 (二) QT for Linux & FFmpeg 环境建立
跨途径播映器开发线程池的七个参数 (三) QT for Windows & FFmpeg 环境建立
FFmpeg 根底常识
解封装
运用 FFmpeg api
来对输入视频进行ffmpeg.dll找不到是什么状况解封装,先来看一下运用 api 的流程
看完上图是不是对解封装的 APopengl下载I 有一个大约的了解? 从一个 输入 URL
到读取到 紧缩数据流 就这么几步,很简单的,下面咱们用代码实践演示一下:
1.注册悉数函数
av_register_all()
其实在最新的版别中该函数现已过期了,在最低的版别中仍是有必要线程和进程的区别是什么调用该函数的。
2.注册网络模块
//初始化网络库(能够翻开 rtmp、rtsp、http 等协议的流媒体视频)
avformat_network_init();
3.翻开输入流并读取头信息
//参数设置
AVDictionary *opts = NULL;
//设置rtsp流已tcp协议翻开
av_dict_set(&opts, "rtsp_transport", "tcp", 0);
//网络延时时刻
av_dict_set(&opts, "max_delay", "1000", 0);
//解封装上下文
AVFormatContext *ic = NULL;
int re = avformat_open_inopengl三重缓冲开不开put(
&ic,
inpath,
0, // 0标明主动挑选解封器
&opts //参数设置,比如rtsp的延时时刻
);
//回来值 0 成功
if (re != 0) {
char buf[1024] = {0};
av_strerror(re, buf, sizeof(buf) - 1);
cout << "open " << iwindows怎样激活npath << " failed! :" << buf << endl;
getchar();
return -1;
}
这儿要留心,调用该函数那么在结尾处必定要调用 avffmpeg播映视频指令format_close_input()
4.读取媒体文件数据包
/windows7/return >=0 if OK, AVERROR_xxx on error
re = avformat_find_stream_info(ic, 0);
//打印视频流具体信息
av算法的时刻复杂度是指什么_dump_windows10激活密钥format(ic, 0, inpath, 0);
5.获取音视频流信息
- 通过遍历的办法获取
//获取opengl烘托gpu怎样设置音视频流信息 (遍历,函数获取)
for (int i = 0; i < ic->nb_streams; i++) {
AVStream *as = ic->streams[i];
cout << "codec_id = " <<ffmpeg.dll丢掉怎样办 as->codecpar->codec_id << endl;
cout << "format = " << as->codecpar->format << endl;
//音频 AVMEDIA_TYPE_AUD线程的几种状况IO
if (as->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audioSffmpeg从入门到通晓tream = i;
cout << i << "音频信息" << endl;
cout << "sample_rate = " << as->codecpar->sample_rate << endl;
//AVSampleFormat;
cout << "channels = " << as->codecpar->ch算法导论annels << endl;
//一帧数据?? 单通道样本数
cout << "frame_size = " << as->codecpar->frame_siz算法工程师e << endl;
//1024 * 2 * 2 = 4096 fps = sopengl下载ample_rate/frame_size
}
//视频 AVMED线程和进程的区别是什么IA_TYPE_VIDEO
else if (as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
cout << i << "视频信息" << endl;
cout &ffmpeg从入门到通晓lwindows怎样激活t;< "width=" << as->windows怎样激活;codecpar->width << endl;
cout << "height="算法工程师 <<opengl和directx as->codecparopengl是什么意思->height << endl;
//帧率 fps 分数转化
cout << "video fps = " << r2d(as->avg_frame_rate) << enopengl版别过低怎样办dl;ffmpeg是什么意思
}
}
- 通过 API 办法获取
//获取视频流
videoStream =FFmpeg av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
AVStream *as = ic->streams[videoStream];
cout << i <&lopengl-legacy什么意思t; "视频信息" << enffmpeg从入门到通晓dl;
cout << "width=" << as-&线程池的七个参数gt;codecpar->width << enopengl下载dl;
cout << "height=" << as->codecpar->height << endl;
//帧率ffmpeg从入门到通晓 fps 分数转化
c算法规划与剖析ouopengl烘托t << "video fps = " <<FFmpeg r2d(as->avg_frame_rate) << endl;
6.读取紧缩数据包
AVWindowsPacket *pkt = av_packet_alloc();
for (;;) {
int re = av_read_opengl版别过低怎样办fram算法e(icwindows7, pkt);
if (re != 0) {
//循环播映
coutopengl和directx << "==============================end==================算法工程师============" &l线程的几种状况t;< endl;
break;
}
cout << "pkt->算法size = " &lffmpeg教程t;< pkt->size << endl;
//显现的时刻
cout << "pkt->pwindows10激活密钥ts = " << pkt->pts << endl;
//转化为毫秒,便作为同步
cout << "pkt->pts ms = " << pkt->pts * (r2d(ic->streams[pkt->stream_indexwindows7激活密钥]->time_bawindows许可证行将过期怎样办se) * 1000) &lffmpeg播映视频指令t;< endl;
//解码时刻
cout << "pkt线程->dts = " << pkt->dts << endl;
if (pkt->stream_index == videoStream) {
cout << "图像" << endl;
}
if (pkt->stream_index == audioStream) {
cou线程撕裂者t << "音频" << endopengl版别过低怎样办l;
}
//开释,引证ffmpeg安卓版别下载计数-1 为0开释空间
av_pacFFmpegket_unref(pkt);线程撕裂者
}
调试之后的 log
解码
调用 ffmpeg awindows7旗舰版pi
来对音视频紧缩数据解码的话,其实也很简单,首要windows许可证行将过期怎样办运用如下几个 api ,见下图:
咱们接着在解封装的代码根底上进行增加,代码如下:
//找到视频解码器
AVCodec *vcodec =opengl-legacy什么意思 avc算法导论odec_find_decoder(ic->stwindows许可证行将过期怎样办reams[videoStream]->codecpar->codec_id);
if (!vcodec) {
cout << "ffmpeg.dll找不到是什么状况can't find the codec id" << ic->streams[videoStream线程安全]->codecpar->codec_id <<opengl是什么意思; endl;
getchar();
return -1;
}windows11来了
//创立视频解码器上下文
AVCodecContext *vctx = avcodec_alloc_context3(vcodec);
//装备解码器上下文参数
avcodec_parameters_to_context(vctx, ic->strwindows体系eams[videoStream]->codecpar);
//装备解码线程
vctx->thread_countffmpeg从入门到通晓 = 8;
//翻开解码器上下文
re = avcodec_open2(vctx, 0, 0);
if (re != 0) {
cha线程r buf[1024] = {0};
av_strerror(re, buf, sizeof(buf) - 1);
cout << "video avcodec_openopengl下载2 fail算法是什么ed!" << buf <<ffmpeg.dll丢掉怎样办 endl;
getcharwindows7旗舰版();
return -1;
}
cout <ffmpeg装置< "video avcodec_open2 success!" << endl;
找解码器也能够通过如下 API 办法进行:
AVCodec *avcodec_find_decoder_by_name(co线程安全nst char *name);
假定算法导论想要翻开音频解码器,代码相同,换下参数即可,下面进行实在解码:
//malloc AVPacke线程池t并初始化 AV线程池Packet *pkt = av_packewindows10t_ffmpeg从入门到通晓alloc(); //接收解码的原ffmpeg下载始数据 AVFrame *frame = av_frame_alloc(); for (;;) { int re = av_read_frame(ic, pkt); if (re != 0) { break; } //解码视频 //发送 packet 到解码线程 re = avcodec_send_packet(avcc, pkt); //开释,引证计数-1 为0开释空间 av_packet_unref(pkt); //一次 send 或许关于多次 receive fo算法的有穷性是指r (;;) { re = avcodec_receive_frame(avcc, frame); if (re != 0)break; //开释,引证计数-opengl下载1 为0开释空间 av_frame_unref(frame); }
这样就能够进行解码了,现在咱们增加一些打印参数,比ffmpeg播映视频指令如音频采样信息,视频宽高信息:
总时长:totalMs = 10534 ms视频信息:bitrate=907_500fps = 30.0003codec_id = 86018format = AV_PIX_FMT_YUV420P 115opengl烘托21080 - 1920pict_type= AV_PICTU算法工程师RE_TYPE_I音频信息:sample_rate = 48000channels = 2
视频像素格局转化
视频像素格局其实就是 YUV 转 RGB 的一个进程, FFmpeg 也供给了对应的 API ,它是运用 CPU 运算才能来转化,算法工程师功率是比较低的。咱们播映器运用 OpenGL GPU 来转,功率比较高。虽然 FFmpeg API 转ffmpeg耻辱柱事情化功率比较低,但是咱们仍是能够学习一下的。运用流程如下:
仅仅 2 个 API 就能够抵达对 YUV 的转化线程安全或许裁剪,代码示例:
const int in_wffmpeg是什么意思idth = frame->width; const int in_height = frame->height; const int out_width = in_w线程和进程的区别是什么idth / 2; const int out_height = inopengl下载_height / 2; /** * @param context : 缩放上下文,假定为 NULL,那么内部会进行创立, * 假定现已存在,参数也没有发生变化,那么就直接回ffmpeg下载来其时,否者开释缩放上下文,从头创立。 * @param srcW : 输入的宽 * @param srcH : 输入的高 * @param srcFormat : 输入的格局 * @param dstW : 输出的宽 * @param dstH : 输出的高 * @param dstFormat : 输出的格局 * @param flags : 供给了一系列的算法,快速线性,差值,矩阵,不同的算法功用也不同, 快速线性线程安全算法功用相对较高。只针对规范的转换。 * @param srcFilter : 输入过滤器 * @param dstwindows7激活密钥Filter : 输出过滤器 * @param param : 这个跟 flags 算法相关,一般传入 O * @return : 缩放的上下文 */ vsctx = sws_getCachedContext( vsctx,//传入NULL 会新创立 in_width, in_hewindows10ight, (AVPixelFormat) frame->format, //输入opengl怎样升级的宽高,格局 out_width, out_height, AV_PIX_FMT_RGBA, //输出的宽高,格局 SWS_BILINEAR, //标ffmpeg下载准转换的算法 0, 0, 0 ); /** * @param c 缩放上下文 * @parffmpeg是什么意思am srcSlice YUV 切换数据能够是指针,也能够是数组 * @param srcStriopengl烘托gpu怎样设置de 对应 YUV 一行的大小 * @param srcSliceY 这个用不到传入 0 即可 * @param srcSliceH YUV 的高 * @param dst 输出的像素格局数据 * @param dstStride 输出的像素格局数据的大小 * @return 回来转化后的高 */ re = sws_scale(vsctx, frame->data, //输入数据 frame-&g算法的时刻复杂度是指什么t;linesize,//输入行大小 0, frame->height,//输出高度 (ui线程池的七个参数nt8_t *const *) (data), //输出数算法的有穷性是指据 lines//输出大小 );
上面的注释都很具体,信赖大家也能看ffmpeg播映视频指令的opengl和directx了解,终究咱们看线程下调试后的log,如下:
像素格局规范转化上下文创立或许获取成功!in_width=1080in_height=1920out_width=540out_height=960sws_scale success! return height of the线程的几种状况 output slice =960==============================end==============================
重算法是什么采样
重采样的意思就是将音频的输入参数一起输出某个特定的值,这样做的长处就是归一化播映器的动态输出。那么怎样运算法导论用 FFmpeg Affmpeg安卓版别下载PI 来进行重采样呢? 先来看一张流程图:
咱们仍是以之前的代码继续写,
咱们共windows7激活密钥同输出的参数为 sample_rate=48000,sample_channel=2,saffmpeg下载mple_fml=AV_SAMPLE_FMopengl烘托T_S16
... //音频重windows许可证行将过期怎样办采样 SwrContext *asctx = swr_alloc(); //设置重采opengl-legacy什么意思样参数 asctx = sw算法规划与剖析r_a算法剖析的意图是lloc_set_opts(asctx //重采样上下文 , av_get_dwindows10激活密钥efault_channel_layout(2)//输出声道格局 , AV_SAMPLE_FMT_S16 //输出动态样本格局 , 48000 //输出采样率 , av_get_default_chanwindows10nel_layout(actx->channels)//输入通道数 , actx->sample_fmt //输入动态样本格局 , actx->sampl线程池的七个参数e_rate, 0, 0 //输入音频采样率 ); //初始化采样上下文 re = swr_init(asctx); if (re !=windows10激活密钥 0) { char buf[1024] = {0}; av_strerror(windows10激活密钥re, buf, sizopengl怎样升级eof(buf) - 1); cout << "audio swr_init failed!" << buffmpeg下载f << end算法剖析的意图是l; return -1; } ... //重ffmpeg安卓版别下载采样之后存入的数据 unsigned char *pcm = NULL; for (;;) { int re = av_read_frame(ic,算法的有穷性是指 pkt);ffmpeg是什么意思 if (re != 0) { //循环播映 cout << "==============================endopengl是什么意思==============================" << endl;// int ms =windows体系 3000; //三秒方位 根据时刻基数(分数)转化// long long pos = (double)opengles3.1扩展包 ms / (doub算法的五个特性le) 1000 * r2d(ic->streams[pkt->stream_index]->time_base);// av_seek_frame(windows体系ic, videoStream, pos, AVSEEK_FLAG_BACKWAR线程池原理D |线程和进程的区别是什么 AVSEEK_FLAG_FRAME);线程池的七个参数// cont线程撕裂者inue; break; } cout << "pkt->size = " << pkt->size << endl;opengl三重缓冲开不开 //显现的时刻 cout &lopengl和directxt;< "pkt->pts = " <线程池原理;< pkt->pts <opengl三重缓冲开不开;< endl; //转化为毫秒,便作为同步 cout << "pkt->pts ms = " << pwindows7旗舰版kt->pts * (r2d(ic->streams[pkt->stream_indopengl怎样升级ex]->time_线程池base) * 1000) << endl; //解码时刻 cout << "pkt->dts = " << pkt->dts <&ffmpeg.dll丢掉怎样办lt; endl; AVCodecContext *avcc = NULL; if (pkt->strewindows10am_index == videoStream) { cout << "图像" << endl; avcc = vctx; } if (pkt->stream_index == audioStream) { cout << "音频" << endl; avcc = actx; } //解码视频 //发送 packet 到解码线程 re = avcodec_seOpenGLnd_packet(av线程撕裂者cc, pkt); //开释,引证计数-1 为0开释windows体系空间 av_packet_unref(pkt); if (re != 0) { char buf[1024] = {0}; av_stffmpeg.dll找不到是什么状况rerror(re, buf,ffmpeg安卓版别下载 sizeof(buf) - 1); cout << "v线程和进程的区别是什么ideo avcodec_s算法end_pacffmpeg.dll找不到是什么状况ket failed!" << buf << endl; continue; } //一次 send 或许关于多次 receiffmpeg.dll找不到是什么状况ve for (;;) { re = avcodec_receive_frame(avcc,线程 frame); if (re != 0)break; ... if (avcc == actx) {//音频 uint8_t *data[2] = {0}; if (!pcm) pcm =算法的有穷性是指 new uint8_t[frame->nb_samples * 16/8 * 2]; data算法[0] = {pcm}; int len = swr_convert(asctx, data, frame->nb_samples //输出 , (const uiwindows11来了nt8_t **) frame->data, frame->nb_samples //输入windows10 ); if (len >=ffmpeg从入门到通晓 0) { cout << "swr_convert success return len = " << len << endl; } else { cout << "swr_convert failed retu算法的五个特性rn len = " << len <&l线程池创立的四种t; endl; } } } ... } if (asctx)swr_close(asctx); if (ffmpeg是什么意思asctx)swr_free(&asctx);
转化后的log:
swr_con算法的时刻复杂度是指什么vert success return len = 1024windows许可证行将过期怎样办
seek线程池原理 操作
咱们假定想要指定某个时刻看某段画面的话就需求对视频做 seek 操作,FFmpeg 供给线程池了 av_seek_frame 函数来对视频的跳转,它有 4 个输入参数,意义如下:
/**
* 根据线程的几种状况时刻戳和音频或视频的索引 seek 到关键帧的操作
*
* @param s 媒体格局上下文
* @param stream_index 流索引,传入 -1 为默许
* @pa线程池的七个参数ram timestamp 需求算法的时刻复杂度取决于跳转到时刻戳的方位
* @param flags seek 的办法
* @return >= 0 on success
*/
iffmpeg教程nt av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
int flag线程撕裂者s);
咱们侧重看下终究一个 flags 参数
//AVSEEK_FLAG_BACKWARD
seek 到后边的关键帧
//AVSEEK_FLAG_BYTE
根据以字节为单位的方位查找
//AVSEEK_FLAG_ANY
Seek 到任意一帧,留心不是关键帧线程池面试题,那么会有花屏的或许。
//AVSEEK_FLAG_FRAME
seek 到关键帧的方位
咱们一般以这样的办法来进行 seffmpeg下载ek 操作:
int mffmpeg.dll丢掉怎样办s = 3000; //三秒方位 根据时刻基数(分算法的特征数)转化
long long pos = (d线程是什么意思ouble) ms / (double) 1000 * r2d(ic->streams[pkt->s线程撕裂者tream_index]->time_base);
av_seek_frame(ic, viopengl烘托gpu怎样设置deoStream, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
上面的意义就是定位到 3000 ms 方位后边的关键帧处初步播映。后边播映器 swindows7旗舰版eek 功用的时分咱们会介绍怎样精准 seek 操作
该篇文章线程关于 FFmpeg
的常识咱们就介绍到这儿,后边在开发中假定有新遇见的我会再具体介绍一下。
总结
播映器要用到的 FFmpeg 常识
大约就这么多,能够发现这些 API 其实都比较简单。此时我信赖你现已对这些 API 有必定的形象和了解了吧。
下一windows7篇文章将带来 QT 怎样烘托 PCM 和 YUV 的数据。
以上代码opengles3.1扩展包能够通过该地址拜访