收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
存储一帧压缩编码数据。
- AVFrame
存储一帧解码后像素(采样)数据。
2.2解码示例
🟢解码类的定义:
//ffmpeg使用c语言实现的,引入用c写的代码就要用extern
extern "C"
{
#include <libavcodec/avcodec.h> //编码
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h> //封装格式处理
#include <libavutil/error.h>
#include <libswscale/swscale.h> //像素处理
#include <libswresample/swresample.h> //缩放
}
class fdecode
{
public:
fdecode();
//注册组件
void registerFFmpeg();
//打开视频流
void openVIdeoStream(QString filename);
//视频名称
QString filename;
protected:
private:
};
具体实现如下:
🟢注册所有组件
void fdecode::registerFFmpeg()
{
//注册所有的组件
av_register_all();
}
🟢打开视频文件
AVFormatContext *forContent;//用来保存视频相关信息的结构体
forContent=avformat_alloc_context();//分配空间
//打开视频文件
int res=avformat_open_input(&forContent,filename.toStdString().c_str(),nullptr,nullptr);
if(res!=0)//判断是否打开视频文件
{
qDebug()<<"无法打开视频文件";
return;
}
🟢****获取视频文件信息
//打开视频文件成功,获取文件信息
res = avformat_find_stream_info(forContent,nullptr);//查看有没有相关视频流信息
if(res<0)
{
qDebug()<<"没有流媒体信息"<<endl;
return;
}
//一个视频流有多股码流,存在forContentext中streams数组中
int videoType=-1;
//nb_streams代表封装格式里面的结构体信息有几个,正常两个:音频信息、视频信息
for(int i=0;i<forContent->nb_streams;i++) //i小于流的个数
{
if(forContent->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//视频流
{
videoType=i;//标识类型
break;
}
}
//判断是否有视频流信息
if(videoType==-1)
{
qDebug()<<"没有视频流相关信息"<<endl;
return;
}
🟢****根据编解码上下文中的编码ID查找对应解码器
//编解码器对应的上下文对象结构体:保存解码器信息以及图形的宽高、像素信息
AVCodecContext *codec=forContent->streams[videoType]->codec;
//查找对应的视频流解码器
AVCodec *decoder = avcodec_find_decoder(codec->codec_id);
if(decoder==nullptr)//判断是否找到解码器
{
qDebug()<<"没有对应的解码器"<<endl;
return;
}
🟢打开解码器
//找到了解码器,打开解码器
res = avcodec_open2(codec,decoder,nullptr);
if(res!=0)
{
qDebug()<<"解码器打开失败"<<endl;
return;
}
🟢读取准备 获取YUV和RGB像素数据
//为准备读取帧数据做准备--AVPacket 用来存储一帧一帧的压缩数据(h264)
AVPacket *pkt=nullptr;
//设置缓冲区,开空间
pkt=(AVPacket *) malloc(sizeof(AVPacket));
int size=codec->width*codec->height;//计算一张图片数据大小
av_new_packet(pkt,size);
/* pictureRGB 保存解码后的RGB像素数据
* pictureYUV 保存解码后的YUV像素数据
* picture 保存未处理的像素数据
*/
AVFrame *pictureRGB,*pictureYUV,*picture=nullptr;
//内存分配
pictureRGB=av_frame_alloc();
pictureYUV=av_frame_alloc();
picture=av_frame_alloc();
//大小以及格式设置RGB
pictureRGB->width=codec->width;//宽度
pictureRGB->height=codec->height;//高度
pictureRGB->format=codec->pix_fmt;//格式设置
//大小以及格式设置YUV
pictureYUV->width=codec->width;//宽度
pictureYUV->height=codec->height;//高度
pictureYUV->format=codec->pix_fmt;//格式设置
//一帧码流数据解码后得到YUV RGB像素数据有多大
int numByte_RGB=avpicture_get_size(AV_PIX_FMT_RGB32,codec->width,codec->height);
int numByte_YUV=avpicture_get_size(AV_PIX_FMT_YUV420P,codec->width,codec->height);
//开的空间用来保存YUV RGB像素数据大小
uint8_t *buffer_RGB=(uint8_t *)av_malloc(numByte_RGB*sizeof(uint8_t));
uint8_t *buffer_YUV=(uint8_t *)av_malloc(numByte_YUV*sizeof(uint8_t));
//像素数据的填充
avpicture_fill((AVPicture *)pictureRGB,buffer_RGB,AV_PIX_FMT_RGB32,codec->width,codec->height);
avpicture_fill((AVPicture *)pictureYUV,buffer_YUV,AV_PIX_FMT_YUV420P,codec->width,codec->height);
//转换规则
SwsContext *sws_RGB=nullptr;//保存转换规则的结构体
SwsContext *sws_YUV=nullptr;//保存转换规则的结构体
//转换规则的设置 AV_PIX_FMT_YUV420P AV_PIX_FMT_RGB32
sws_RGB=sws_getContext(codec->width,codec->height,codec->pix_fmt,
codec->width,codec->height,AV_PIX_FMT_RGB32, //目标格式
SWS_BICUBIC,nullptr,nullptr,nullptr); //转换规则
sws_YUV=sws_getContext(codec->width,codec->height,codec->pix_fmt,
codec->width,codec->height,AV_PIX_FMT_YUV420P,//目标格式
SWS_BICUBIC,nullptr,nullptr,nullptr); //转换规则
//保存h.264压缩码流数据的文件
FILE *fp=fopen("fileout/alenH264.h264","wb+");//文件名字可以自行定义
//保存yuv像素数据的文件
FILE *fp_yuv=fopen("fileout/alenyuv.yuv","wb+");//文件名字可以自行定义
🟢一帧一帧的读取压缩数据 保存码流数据和YUV、RGB像素数据
int count=0;//存图片
//一帧一帧的读取压缩数据
while(av_read_frame(forContent,pkt)==0)//读到数据
{
if(pkt->stream_index == videoType)//判断一帧码流数据是不是需要得到的视频流
{
fwrite(pkt->data,pkt->size,1,fp);//写入文件中
int got_picture_ptr=-1;
//解码得到YUV
res = avcodec_decode_video2(codec,picture,&got_picture_ptr,pkt);
if(res < 0)
{
qDebug()<<"解码错误"<<endl;
return;
}
//压缩码流数据,解码后的像素数据,判断有没有数据可以解码,对谁进行解码
if(got_picture_ptr!=0)//解码操作
{
//把解码得到的坏数据剔除
sws_scale(sws_RGB,picture->data,picture->linesize,0,picture->height,
pictureRGB->data,pictureRGB->linesize);//RGB
sws_scale(sws_YUV,picture->data,picture->linesize,0,picture->height,
pictureYUV->data,pictureYUV->linesize);//YUV
//输出的YUV文件
//AVFrame像素帧写入文件
fwrite(pictureYUV->data[0],size,1,fp_yuv); //y数据
fwrite(pictureYUV->data[1],size/4,1,fp_yuv);//u数据
fwrite(pictureYUV->data[2],size/4,1,fp_yuv);//v数据
//设置每25帧输出一张图片
count++;
if(count%25==0)
{
QImage image((uchar *)pictureRGB->data[0],pictureRGB->width,pictureRGB->height,QImage::Format_RGB32);//像素数据
QString imageName = QString("image/test%1.jpg").arg(count);
image.save(imageName);//保存图片函数
}
}
}
//释放包以及AVFrame资源
av_packet_unref(pkt);
av_frame_unref(picture);
}
qDebug()<<"保存码流数据成功"<<endl;
🟢资源释放
//关闭h.264
fclose(fp);
//关闭YUV文件
fclose(fp_yuv);
//释放AVFrame
av_frame_free(&picture);
//关闭解码器
avcodec_close(codec);
//释放视频信息结构体
avformat_free_context(forContent);
🟢测试主函数代码,如下所示:
int main(int argc, char *argv[])
{
//QApplication a(argc, argv);
//Widget w;
//w.show();
fdecode *decode = new fdecode;
decode->registerFFmpeg();
decode->openVIdeoStream("filein/alen.avi");
//return a.exec();
}
保存的H.264、yuv文件以及图片数据,如下所示:
🔵H.264、yuv文件
🔵图片数据(每25帧截图一张)
🔵 利用以下应用程序可以播放我们得到的H.264和YUV文件
🔵来播放博主喜欢的日漫吧!
效果如下:
🚀FFMPEG技术—环境配置,详见:
FFmpeg+Qt开发(一):Windows下 环境搭建 详细步骤_猿力猪的博客-CSDN博客_ffmpeg库
🚀FFMPEG技术—编码流程,详见:
【FFmpeg+Qt开发】编码流程 普通视频编码+示例详解 一学就会_猿力猪的博客-CSDN博客
🚀FFMPEG技术—转码流程,详见:
【FFmpeg+Qt开发】转码流程 H.264 转(mov、mp4、avi、flv)等视频格式 示例详解_猿力猪的博客-CSDN博客
✍ 本文主要介绍了FFmpeg技术中的解码部分,如有疑问,欢迎各位评论区学习交流!
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
,如有疑问,欢迎各位评论区学习交流!**
[外链图片转存中…(img-9RG3HdDR-1715797231602)]
[外链图片转存中…(img-7HzTrB2D-1715797231602)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)