前语

咱们前面三篇文章首要介绍了如安在各个干流途径下装备开发环境,那么从该篇初步就实在进入编码了。由于该系列定义为从 0 到 1 写一个跨途径播映器,所以我计划从浅到深,从根底到进阶的道路来进行。

咱们先来看一个流程图:

跨渠道播映器开发 (四)  开发一个播映器需求用到哪些 FFmpeg 常识

该系列文章就是将上图拆分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 的流程

跨渠道播映器开发 (四)  开发一个播映器需求用到哪些 FFmpeg 常识

看完上图是不是对解封装的 APopengl下载I 有一个大约的了解? 从一个 输入 URL 到读取到 紧缩数据流 就这么几步,很简单的,下面咱们用代码实践演示一下:

1.注册悉数函数

av_register_all()

其实在最新的版别中该函数现已过期了,在最低的版别中仍是有必要线程和进程的区别是什么调用该函数的。

跨渠道播映器开发 (四)  开发一个播映器需求用到哪些 FFmpeg 常识

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.获取音视频流信息

  1. 通过遍历的办法获取
    //获取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-&gtwindows怎样激活;codecpar->width << endl;
cout << "height="算法工程师 <<opengl和directx as->codecparopengl是什么意思->height << endl;
//帧率 fps 分数转化
cout << "video fps = " << r2d(as->avg_frame_rate) << enopengl版别过低怎样办dl;ffmpeg是什么意思
}
}
  1. 通过 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 常识

解码

调用 ffmpeg awindows7旗舰版pi 来对音视频紧缩数据解码的话,其实也很简单,首要windows许可证行将过期怎样办运用如下几个 api ,见下图:

跨渠道播映器开发 (四)  开发一个播映器需求用到哪些 FFmpeg 常识

咱们接着在解封装的代码根底上进行增加,代码如下:

    //找到视频解码器
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 <&ltopengl是什么意思; 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播映视频指令如音频采样信息,视频宽高信息:

跨渠道播映器开发 (四)  开发一个播映器需求用到哪些 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耻辱柱事情化功率比较低,但是咱们仍是能够学习一下的。运用流程如下:

跨渠道播映器开发 (四)  开发一个播映器需求用到哪些 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 来进行重采样呢? 先来看一张流程图:

跨渠道播映器开发 (四)  开发一个播映器需求用到哪些 FFmpeg 常识

咱们仍是以之前的代码继续写,

咱们共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 = " &lt线程池原理;< pkt->pts &ltopengl三重缓冲开不开;< 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扩展包能够通过该地址拜访