ffmpeg开发入门(开发一个播放器需要用到哪些)

咱们先来看一个流程图:

本篇咱们主要讲解如何利用 FFmpeg API 来对一个输入数据进行解封装,读取原始音频视频信息,然后对音频视频做一些基本操作。基本上在播放器模块中用到的 FFmpeg API 咱们都要对它有一个了解。

FFmpeg 基础知识

解封装

利用 FFmpeg api 来对输入视频进行解封装,先来看一下使用 api 的流程

看完上图是不是对解封装的 API 有一个大概的了解? 从一个 输入 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_input(
&ic,
inpath,
0, // 0表示自动选择解封器
&opts //参数设置,比如rtsp的延时时间
);
//返回值 0 成功
if (re != 0) {
char buf[1024] = {0};
av_strerror(re, buf, sizeof(buf) - 1);
cout << "open " << inpath << " failed! :" << buf << endl;
getchar();
return -1;
}

这里要注意,调用该函数那么在结尾处一定要调用 avformat_close_input()

4.读取媒体文件数据包

//return >=0 if OK, AVERROR_xxx on error
re = avformat_find_stream_info(ic, 0);

//打印视频流详细信息
av_dump_format(ic, 0, inpath, 0);

5.获取音视频流信息

通过遍历的方式获取

//获取音视频流信息 (遍历,函数获取)
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
if (as->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audioStream = i;
cout << i << "音频信息" << endl;
cout << "sample_rate = " << 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;
}
}

2.通过 API 方式获取

//获取视频流
videoStream = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
AVStream *as = ic->streams[videoStream];
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;

6.读取压缩数据包

AVPacket *pkt = av_packet_alloc();

for (;;) {
int re = av_read_frame(ic, pkt);
if (re != 0) {
//循环播放
cout << "==============================end==============================" << endl;
break;
}
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);
}

调试之后的 log

领取音视频开发资料包:音视频流媒体高级开发FFmpegWebRTCRTMPRTSPHLSRTP播放器

企鵝君羊994289133领取资料

解码

调用 ·ffmpeg api 来对音视频压缩数据解码的话,其实也很简单,主要使用如下几个 api ,见下图:

我们接着在解封装的代码基础上进行添加,代码如下:

//找到视频解码器
AVCodec *vcodec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
if (!vcodec) {
cout << "can't find the codec id" << ic->streams[videoStream]->codecpar->codec_id << endl;
getchar();
return -1;
}
//创建视频解码器上下文
AVCodecContext *vctx = avcodec_alloc_context3(vcodec);
//配置解码器上下文参数
avcodec_parameters_to_context(vctx, ic->streams[videoStream]->codecpar);
//配置解码线程
vctx->thread_count = 8;
//打开解码器上下文
re = avcodec_open2(vctx, 0, 0);
if (re != 0) {
char buf[1024] = {0};
av_strerror(re, buf, sizeof(buf) - 1);
cout << "video avcodec_open2 failed!" << buf << endl;
getchar();
return -1;
}
cout << "video avcodec_open2 success!" << endl;

找解码器也可以通过如下 API 形式进行:

AVCodec *avcodec_find_decoder_by_name(const char *name);

如果想要打开音频解码器,代码一样,换下参数即可,下面进行真正解码:

//malloc AVPacket并初始化 AVPacket *pkt = av_packet_alloc(); //接收解码的原始数据 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 for (;;) { re = avcodec_receive_frame(avcc, frame); if (re != 0)break; //释放,引用计数-1 为0释放空间 av_frame_unref(frame); }

这样就可以进行解码了,现在我们添加一些打印参数,比如音频采样信息,视频宽高信息:

总时长:totalMs = 10534 ms视频信息:bitrate=907_500fps = 30.0003codec_id = 86018format = AV_PIX_FMT_YUV420P 11521080 - 1920pict_type= AV_PICTURE_TYPE_I音频信息:sample_rate = 48000channels = 2

视频像素格式转换

视频像素格式其实就是 YUV 转 RGB 的一个过程, FFmpeg 也提供了对应的 API ,它是使用 CPU 运算能力来转换,效率是比较低的。咱们播放器使用 OpenGL GPU 来转,效率比较高。虽然 FFmpeg API 转换效率比较低,但是我们还是可以学习一下的。使用流程如下:

仅仅 2 个 API 就可以达到对 YUV 的转换或者裁剪,代码示例:

const int in_width = frame->width; const int in_height = frame->height; const int out_width = in_width / 2; const int out_height = in_height / 2; /** * @param context : 缩放上下文,如果为 NULL,那么内部会进行创建, * 如果已经存在,参数也没有发生变化,那么就直接返回当前,否者释放缩放上下文,重新创建。 * @param srcW : 输入的宽 * @param srcH : 输入的高 * @param srcFormat : 输入的格式 * @param dstW : 输出的宽 * @param dstH : 输出的高 * @param dstFormat : 输出的格式 * @param flags : 提供了一系列的算法,快速线性,差值,矩阵,不同的算法性能也不同, 快速线性算法性能相对较高。只针对尺寸的变换。 * @param srcFilter : 输入过滤器 * @param dstFilter : 输出过滤器 * @param param : 这个跟 flags 算法相关,一般传入 O * @return : 缩放的上下文 */ vsctx = sws_getCachedContext( vsctx,//传入NULL 会新创建 in_width, in_height, (AVPixelFormat) frame->format, //输入的宽高,格式 out_width, out_height, AV_PIX_FMT_RGBA, //输出的宽高,格式 SWS_BILINEAR, //尺寸变换的算法 0, 0, 0 ); /** * @param c 缩放上下文 * @param srcSlice YUV 切换数据可以是指针,也可以是数组 * @param srcStride 对应 YUV 一行的大小 * @param srcSliceY 这个用不到传入 0 即可 * @param srcSliceH YUV 的高 * @param dst 输出的像素格式数据 * @param dstStride 输出的像素格式数据的大小 * @return 返回转换后的高 */ re = sws_scale(vsctx, frame->data, //输入数据 frame->linesize,//输入行大小 0, frame->height,//输出高度 (uint8_t *const *) (data), //输出数据 lines//输出大小 );

上面的注释都很详细,相信大家也能看的明白,最后我们看下调试后的log,如下:

像素格式尺寸转换上下文创建或者获取成功!in_width=1080in_height=1920out_width=540out_height=960sws_scale success! return height of the output slice =960==============================end==============================

重采样

重采样的意思就是将音频的输入参数统一输出某个特定的值,这样做的好处就是归一化播放器的声音输出。那么怎么使用 FFmpeg API 来进行重采样呢? 先来看一张流程图:

我们还是以之前的代码继续写,

我们统一输出的参数为 sample_rate=48000,sample_channel=2,sample_fml=AV_SAMPLE_FMT_S16

...//音频重采样 SwrContext *asctx = swr_alloc(); //设置重采样参数 asctx = swr_alloc_set_opts(asctx //重采样上下文 , av_get_default_channel_layout(2)//输出声道格式 , AV_SAMPLE_FMT_S16 //输出声音样本格式 , 48000 //输出采样率 , av_get_default_channel_layout(actx->channels)//输入通道数 , actx->sample_fmt //输入声音样本格式 , actx->sample_rate, 0, 0 //输入音频采样率 ); //初始化采样上下文 re = swr_init(asctx); if (re != 0) { char buf[1024] = {0}; av_strerror(re, buf, sizeof(buf) - 1); cout << "audio swr_init failed!" << buf << endl; return -1; } ... //重采样之后存入的数据 unsigned char *pcm = NULL; 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; break; } 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; AVCodecContext *avcc = NULL; if (pkt->stream_index == videoStream) { cout << "图像" << endl; avcc = vctx; } if (pkt->stream_index == audioStream) { cout << "音频" << endl; avcc = actx; } //解码视频 //发送 packet 到解码线程 re = avcodec_send_packet(avcc, pkt); //释放,引用计数-1 为0释放空间 av_packet_unref(pkt); if (re != 0) { char buf[1024] = {0}; av_strerror(re, buf, sizeof(buf) - 1); cout << "video avcodec_send_packet failed!" << buf << endl; continue; } //一次 send 可能对于多次 receive 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 uint8_t **) frame->data, frame->nb_samples //输入 ); if (len >= 0) { cout << "swr_convert success return len = " << len << endl; } else { cout << "swr_convert failed return len = " << len << endl; } } }... } if (asctx)swr_close(asctx); if (asctx)swr_free(&asctx);

转换后的log:

swr_convert success return len = 1024

seek 操作

我们如果想要指定某个时间看某段画面的话就需要对视频做 seek 操作,FFmpeg 提供了 av_seek_frame 函数来对视频的跳转,它有 4 个输入参数,含义如下:

/**
* 根据时间戳和音频或视频的索引 seek 到关键帧的操作
*
* @param s 媒体格式上下文
* @param stream_index 流索引,传入 -1 为默认
* @param timestamp 需要跳转到时间戳的位置
* @param flags seek 的模式
* @return >= 0 on success
*/
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,
int flags);

我们着重看下最后一个 flags 参数

//AVSEEK_FLAG_BACKWARD

seek 到后面的关键帧

//AVSEEK_FLAG_BYTE

基于以字节为单位的位置查找

//AVSEEK_FLAG_ANY

Seek 到任意一帧,注意不是关键帧,那么会有花屏的可能。

//AVSEEK_FLAG_FRAME

seek 到关键帧的位置

我们一般以这样的形式来进行 seek 操作:

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);

上面的含义就是定位到 3000 ms 位置后面的关键帧处开始播放。后面播放器 seek 功能的时候我们会介绍如何精准 seek 操作

该篇文章对于 FFmpeg 的知识我们就介绍到这里,后面在开发中如果有新遇见的我会再详细介绍一下。

总结

播放器要用到的 FFmpeg 知识 大概就这么多,可以发现这些 API 其实都比较简单。此刻我相信你已经对这些 API 有一定的印象和了解了吧。

,

开一个猫咖需要些什么

怎么开一个猫咖

猫咖猫咪咖啡馆是主要以猫咪为主题的咖啡馆。在猫咪咖啡馆里,猫咪是主体。是否拥有金钱,拥有权力对它们来说都不重要,所有人都是平等的。在这里,喝咖啡是其次,最主要的是跟猫咪一起玩耍能缓解压力和孤独
特色服务:有下午茶,有无烟区,有wifi,提供在线菜单。

开一个猫咖需要些什么

如何现实可行地开一家猫咪咖啡馆?

大前提是现实可行,且具有盈利性。问题包括:1.大概需要的本金2.必须具备的地理条件或最佳选址3.如何打理…

想在大学校园开个猫咖,可行吗?

很多人私信我问我可不可以分享经验。其实真挺难受的。抱歉这里更正,这个联系我的男生并不是题主小姐姐,…

开猫咖需要多少钱?

在上海开一家猫咖 有没有提议或者建议加盟还是自己开门店还是居民楼有没有在上海也想开店的合伙人 请指导…

想开个猫咖,需要注意哪些?

猫咖与普通咖啡厅的区别在于猫,所以需要注意的点也应该着重于猫上。1.猫的性格。猫的性格一定要温顺、稳…

开“猫咖”需要办些什么样的营业证呢?

营业执照,卫生许可证,其余看你开展的业务吧。

开一个猫咖的成本需要多少?

开一个猫咖的成本需要几十万元。当初和朋友一起集资35W,开了一家在居民区里面8楼的猫咖,起了个名字叫猫岛。(其中十万没用到)
大约是在17年8月份把房子租下来,装修了一个多月。在十月一日正式开业。178平米5个房间一个厨房,一个猫休息吃饭的房间,三个桌游房,两个洗手间。(地址是在地铁站楼上,科技园,大学附近)
开业第一个月,营业额靠朋友的一些消费,大概一万多。到了12月份大概差不多2万营业额,最高峰大概4万多接近5万。现在比较稳定每个月大概3万多,盈利大概一万多。前段时间合伙人在店经营,培训兼职,现在周中全交给兼职打理,晚上我们合伙人自己过来看,周末轮流过来全天。如果是街边店铺,预算要提高,租金转让费、商业水电、物业费是很贵的。

想开一家猫咖具体有哪些应该计算的成本?

我想知道开一家咖啡店具体有哪些应该计算的成本?谢邀。三个大头,房租,装修,设备。房租按市口来,猫咖压力小很多。装修,猫咖压力也小。设备,猫咖压力还是小。...

想开一家猫咖,需要做好哪些方面考虑?

先解释下猫咪咖啡馆是指什么?主要以猫咪为主题的咖啡馆。在猫咪咖啡馆里,猫咪是主体。是否拥有金钱,拥有权力对它们来说都不重要,所有人都是平等的。在这里,喝咖啡是其次,最主要的是跟猫咪一起玩耍能缓解压力和孤独。1.前提投资
前提投资与你的所在的城市,所在的地理位置和咖啡馆的面积大小等等有关系,想知道你将要开的咖啡馆投资多少,给你一个简单的方法:你找一个你期望中的猫咖,去考察一下,店员一般就把问题给你回答了
2.如何积累前期客源
找准精准客户,我认为主要以情怀为主,以共同价值为主,可以利用公众号等各自媒体平台,沟通情感,多做一些活动(线下聚体,体验活动,以爱为主题的活动等等)蓄客,然后你的文章、视频拍的多了,自然会有人给你传播,有了共同的理念和价值观,如果你有不错的营销策略的话,很多人会响应你的,这里可以做一个裂变策略,营销不是三言两语能说清楚的。3.发展壮大
你的知识,你的思维已经决定了你是否能够做大,一开始你要做战略布局了
4 .推荐的
每个地区都有很多,以北京上海大城市为主

开个猫舍需要哪些条件

开猫舍要有多少资金才可以,一个月大概消费

猫舍除了布偶猫,其他几乎都不怎么挣钱,除非你养的数量非常多,几十只以上的猫舍。你要是想认真养,提高养猫的环境和饮食标准,需要的花费也不少。整整两间房子和阳台,几个大型好几层的猫笼子,每一层都需要喂食器,水盆,猫砂盆。整个房间需要空气净化器,紫外线消毒灯,消毒喷壶,加湿器香薰等等,常用的猫粮、猫砂每个月都要好多,每天都要铲屎+消毒,非常累。一个小型猫舍,种公要2000-4000档次以上的才行;母猫最少也要1000左右的,就算只养十几只,最少也要3万!每只猫一个月吃8斤,包括1/3肉馅+2/3猫粮,还要补充一点微量元素和药,具体花多少钱就看你要养多少只猫了。开猫舍一定要注意,猫和狗不一样,是纯吃肉的,开销大,拉屎撒尿特别臭,养得越多,你家空气、环境越乱!相反,如果你只养三四只布偶猫,可能比你养十多只英短,美短还赚钱。工作量小,家里干净。喂食,打扫轻松很多。所以我建议想开猫舍的,直接入手布偶猫试试,其他的不要想!

开个猫舍需要哪些条件

开猫舍的基本条件

钱多,地方宽

想开个猫舍有经验的好心前辈给我一些建议,谢谢!

我本人不是很赞成开猫舍 因为经常被周边的宠物店猛宰所以影响不怎么好 不过我觉得…你不一定要以开始就开猫舍,那样的话你会遇到好多问题的,像种猫的来路,育苗和疾病,场地的租金。还有我要强调,我打过工的,就在猫舍里,我可以负责地告诉你,光经营猫舍的话一定会进入负增长,那些红红的字会狠狠地打击你的自信心。我是觉得有一些成功的案例可以参考:我认识一家店一边卖小猫一边卖衣服,开格子铺,还卖很多猫咪,宠物的周边。个人推荐这样的开店方法,所有的商品都可以互相衬托,互相宣传。还有你养过猫吗,你感受过每天给猫咪抄BB的感觉吗?不是每只猫都会上厕所的。我家猫一次最多拉了14条,那根本不是用恶臭来形容的!还有如果小猫死了或者什么的话那就囧了,首先心里受不了其次这个店…不过,既然你要养猫,给你一个我DIY的排名:1、银色虎纹折耳猫(女生里人气很高)2、暹罗猫(虽然脸是黑的不过很活泼很好客很可爱,有狗狗一样的性格)3、白色长短毛猫,鸳鸯眼则为最佳(传统的观念决定了这是爸爸妈妈爷爷奶奶更加偏爱的形态,而且看起来也漂亮)4、长短毛黑猫(不要以为黑猫不受欢迎,在90后的眼里那才是非主流!5、蓝猫,俄罗斯蓝猫,英国短毛猫一类的(那蓝色…迷人和罕见,实在是已独特而出名,在猫友中的影响也不低那,只是价格让人望而却步)注意!你养到一半敢说一声我不养了试试?所有看过这贴进过你店的看咱们鄙视不死你 万万别卖异国短毛猫,就是加菲那种,那个塌进去的鼻子真是囧死人不偿命那!说白了就是卖不出去 我是想不出什么还可以告诉你的了,原谅我的碎碎念。你做好心里准备,如果开始养,就没有退路了。每个十年是不许你放弃的。价钱要公道啊…公道…

自己开猫舍做繁育,需要具备哪些条件?爱问知识人

首先不要是自己喜欢猫一时冲动,一定要做好充分客服困难的心理准备,开猫舍并没有表面看上去那么简单

想办布偶猫舍,要具备什么条件,多少资金

肯定要非常好的种公种母了,至少冠军血线和冠军头衔不能少。繁育级的国外好一点的猫舍加上运费上万人民币没得跑了,几万一只正常。猫舍前期投 大,养的话费用也不便宜,你还要带种猫们去参加比赛拿头衔。你可以多关注下布偶猫的cfa和tica的比赛,欧美都关注,然后你就逐渐明白哪个猫舍好、哪个猫舍的猫长得甜,还有布偶繁育相关知识也学了,掌握这些之后你应该就会看猫了。然后就盯着你喜欢的几只种猫等他们的小猫,提前联系好那个种猫所在的猫舍说你要引进种猫,然后等生了你一般可以第一个挑选。之后的流程猫舍会负责的。很久没关注国内布偶了,现在这种走正规流程的猫舍小猫都近1万起价吧?而且还是提前挺早都预定完了。补充一下,和国外猫舍主要联系方式是邮件,他们官网上有写的。主要还是你要会看猫,确定自己没被坑。

想要开一个猫舍需要什么准备吗?

答主@北极英短 已经把硬件设施说得非常到位了。我来补充个心理方向的:1、对猫下“狠”手,活物免不了吃…

国内猫舍现状如何?开个高级猫舍需要注意什么?

朋友很喜欢猫咪,打算开个高级猫舍,繁育些美国短毛和一些矮脚猫。在上海。想知道国内猫舍现状如何,开猫…

我想开个CFA注册猫舍。怎么办理呢?需要具备哪些条件?是不是还要从他们...

根据CFA的规定,真正的注册猫舍应该是需要具备一些条件,并且要有CFA的人来检查这些条件的,有cfa猫舍不一定要有cfa猫,有cfa猫不一定要有cfa猫舍。

开一个家庭猫舍需要什么证件?

需要宠物营业执照,根知据自己的预算确定猫舍要选定哪一个猫种,学习猫的喂养,繁育,医疗等专业知识。开猫舍是一件非常需要耐心和顶道得住压力的事。选好种群,回筛选合适的猫资源,做小猫科学喂养,常见病的治疗等等如过没有经验丰富的人教授经验 都是需答要精心做大量知识储备的。

开猫舍前需要准备什么?

首先,先大概说下,猫的繁殖能力如此之强,为什么名种猫还卖那么贵?品种猫保证的是血统,血统提供品相,…

本文Hash:08628ff1916cd9923a92f93d675c2e5a1929d598

声明:此文由 区块大康 分享发布,并不意味布布狗赞同其观点。文章内容仅供参考,此文如侵犯到您的合法权益,请联系我们。