stm32h743单片机嵌入式学习笔记8-avi视频解码
* AVI 格式允许视频和音频交错在一起同步播放,支持 256 色和 RLE 压缩,但 AVI 文件并
未限定压缩标准,AVI 仅仅是一个容器,用不同压缩算法生成的 AVI 文件,必须使用相应的解
压缩算法才能播放出来。比如本章,我们使用的 AVI,其音频数据采用 16 位线性 PCM 格式(未
压缩),而视频数据,则采用 MJPG 编码方式。
* 视频文件信息头这里有很多我们要用到的信息,比如 SecPerFrame,通过该参数,我们可以知道每秒钟的帧
率,也就知道了每秒钟需要解码多少帧图片,才能正常播放。TotalFrame 告诉我们整个视频有
多少帧,结合 SecPerFrame 参数,就可以很方便计算整个视频的时间了。
* 而且它告诉我们视频的分辨率(Width 和 Height),以及视频所用的编码器(Compression),因此它
决定了视频的解码。本章例程仅支持解码视频分辨率小于屏幕分辨率,且编解码器必须是 MJPG
的视频格式。
* 本结构体对音频数据解码起决定性的作用,他告诉我们音频信号的编码方式(FormatTag)、
声道数(Channels)和采样率(SampleRate)等重要信息。本章例程仅支持 PCM 格式
(FormatTag=0X0001)的音频数据解码。
也就是说avi视频是由许多帧组成的(每一帧就是一张图片),但是都是avi格式的视频的帧图片和音频却都可以采用不同的编码方式, 比如的A.avi视频的每一帧可能就是用的.png格式编码的,音频采用.wav。B.avi视频的每一帧可能就是用的.jpg格式编码的,音频采用.mp3。但是他们都是.avi格式的视频,所以解码的时候我们读取他的信息头数据,就可以知道应该用什么方式解码了。
由于stm32h743带的是JPG/JPEG图片硬件解码器,所以只能快速解码由 MJPG 编码的 AVI 格式视频播放
那也就是说,为了这个单片机能获得快速的解码,我们播放的视频得提前在电脑上用软件处理为MJPG编码的.avi视频,且音频必须是 PCM 格式(因为阿波罗开发板另外带的是这个解码芯片,我的水星板没有带,那就不播放声音了呗)
程序过程:
最外层函数
//播放一个mjpeg文件
//pname:文件名
//返回值:
//KEY0_PRES:下一曲
//KEY1_PRES:上一曲
//其他:错误
u8 video_play_mjpeg(u8 *pname)
即可,那它里面到底做了啥呢
1.读取这个avi视频文件结构体头信息,得到帧率等参数
//开始avi解析
res=avi_init(pbuf,AVI_VIDEO_BUF_SIZE); //avi解析
这里就会把读取到的参数都赋值给全局变量频文件结构体变量avix了
2.显示出这个视频结构体的参数信息,按照帧率开启定时器定时时间,即按照帧率的时间间隔,来读取视频的数据流,从而实现按照视频指定帧率播放该视频
video_info_show(&avix);
TIM6_Int_Init(avix.SecPerFrame/100-1,20000-1);//10Khz计数频率,加1是100us
当然还会对视频的音频进行初始化
if(avix.SampleRate) //有音频信息,才初始化
{
WM8978_I2S_Cfg(2,0); //飞利浦标准,16位数据长度
SAIA_Init(0,1,4); //设置SAI,主发送,16位数据
SAIA_SampleRate_Set(avix.SampleRate); //设置采样率
SAIA_TX_DMA_Init(saibuf[1],saibuf[2],avix.AudioBufSize/2,1);//配置DMA
sai_tx_callback=audio_sai_dma_callback; //回调函数指向SAI_DMA_Callback
saiplaybuf=0;
saisavebuf=0;
SAI_Play_Start(); //开启sai播放
}
3.就是循环读取每一帧数据了,读取到每一帧(就是一张jpg图片)就调用单片机JPEG硬件进行解码,同时就在这个解码函数内显示在液晶屏上了(这个跟前面学习的fpg图片硬件解码过程一模一样的),解码完一帧后,不急着读下一帧,而是延时一个帧率时间间隔while(frameup==0);即这句代码,然后再读取下一帧且解码,如此循环。。。图片帧数读完且解码完之后,就退出就行了,代码如下
while(1)//播放循环
{
if(avix.StreamID==AVI_VIDS_FLAG) //视频流
{
pbuf=framebuf;
f_read(favi,pbuf,avix.StreamSize+8,&nr); //读入整帧+下一数据流ID信息
res=mjpeg_decode(pbuf,avix.StreamSize);
if(res)
{
printf("decode error!\r\n");
}
while(frameup==0); //等待时间到达(在TIM6的中断里面设置为1),即按照帧率速度
frameup=0; //标志清零
frame++;
。。。读完了所有帧,这里就退出这个死循环了,完成这个视频播放
我们来看看上面这个底层解码函数res=mjpeg_decode(pbuf,avix.StreamSize);关键性的做了啥
JPEG_Decode_Init(&mjpeg); //初始化硬件JPEG解码器
JPEG_IN_DMA_Init((u32)mjpeg.inbuf[0].buf,mjpeg.inbuf[0].size); //配置输入DMA
if(mjpeg.state==JPEG_STATE_FINISHED) //解码完成了
{
mjpeg_fill_color(imgoffx,imgoffy,mjpeg.Conf.ImageWidth,mjpeg.Conf.ImageHeight,rgb565buf);
}
可以看到里面是进行调用JPEG硬件解码,然后配合DMA进行数据高速传输到JPEG硬件和从JPEG硬件直接传输到RGB屏幕的显存区域(必须是横屏模式,但是本例程是竖屏模式,所以DMA无法直接传输到显存)(显存就是sdram的一块内存,480*800的屏幕大概需要2MB显存,这里填啥,屏幕就显示啥了)(横屏这样的DMA方式显示速度是最快的),最后解码出的就是图片的像素点颜色数据了,然后进行调用液晶屏底层的函数显示再屏幕上即可
结果对比:对于 480*272 的视频,本例程最高能播放 30 帧左右的视频,我用了480*800的25帧视频,单片机播放出来大概只有20帧(我的水星开发板液晶屏测试都是480*800的电容屏),但是教材又说了
附 STM32H743 硬件 JPEG 视频解码性能:
对 800*480 分辨率,可达 50 帧
对 1024*600 分辨率,可达 20 帧
对 1280*800 分辨率,可达 10 帧
那为什么我的只有20帧呢,原因应该是因为这个例程是用竖屏模式,DMA无法直接填充颜色数据到显存,还经过了一些转换,所以耗时了,有兴趣的可以直接看看改成横屏模式,搞到50帧(好像综合例程就是横屏模式,可以参考改一下)
如果要想提高帧率,有几个办法:1,降低分辨率;2,降低比特率;3,降低音频采样率。
-------------------------------------------------------------------------------------------------------------------------------------------------------
最后再来分析一下控制帧率的定时器原理:
TIM6_Int_Init(avix.SecPerFrame/100-1,20000-1);//10Khz计数频率,加1是100us,单独开启了定时器6
然后设置了中断方式运行,中断函数:
vu8 frameup;
//定时器6中断服务程序
void TIM6_DAC_IRQHandler(void)
{
if(TIM6->SR&0X0001)//溢出中断
{
frameup=1;
}
TIM6->SR&=~(1<<0);//清除中断标志位
}
就是每隔帧率时间就中断了一下(然后定时器会自动重装载定时值),更新了frameup=1;这个变量,然后解码过程函数就会来查询这个变量是否为1,是的话就说明下一帧到了,赶紧开始解码,同时 frameup=0; //标志清零
那我们来分析一下,如果单片机的一帧解码速度够快,说明解码完上一帧但是下一帧时间还没到,所以就会进行等待,那么就是完全准确的按照帧率播放该视频的。
如果单片机解码一帧速度不够,那么刚解码完一帧,此时一查询frameup是1(新的一帧指示变量早就在定时器中断里面已经更新为1了),就得继续读取且解码下一帧(所以cpu使用率会非常的高),那么这样的话就会出现掉帧的情况:要么是某些帧没有播放到(视频看起来不是连续的变化),要么就是视频时间到了就停止播放所以后面的帧没有播放出来(视频后面部分没有播出来),要么就是播放有卡顿,总播放时间就变长了罢了(这个看程序是怎么写的了,就会有不同的现象)。总体来说,就是感觉卡顿的
while(1)//播放循环
{
if(avix.StreamID==AVI_VIDS_FLAG) //视频流
{
pbuf=framebuf;
f_read(favi,pbuf,avix.StreamSize+8,&nr); //读入整帧+下一数据流ID信息
res=mjpeg_decode(pbuf,avix.StreamSize);
if(res)
{
printf("decode error!\r\n");
}
while(frameup==0); //等待时间到达(在TIM6的中断里面设置为1),即按照帧率速度
frameup=0; //标志清零
frame++;
。。。读完了所有帧,这里就退出这个死循环了,完成这个视频播放
stm32h743单片机嵌入式学习笔记8-avi视频解码相关推荐
- stm32h743单片机嵌入式学习笔记6-压缩图片解码原理
软件解码: JPEG/JPG 的解码过程可以简单的概述为如下几个部分: 1 .从文件头读出文件的相关信息. JPEG 文件数据分为文件头和图像数据两大部分,其中文件头记录了图像的版本. 长宽.采样因子 ...
- stm32h743单片机嵌入式学习笔记7-FPU
* FPU 即浮点运算单元(Float Point Unit).浮点运算,对于定点 CPU(没有 FPU 的 CPU) 来说必须要按照 IEEE-754 标准的算法来完成运算,是相当耗费时间的.而对于 ...
- stm32h743单片机嵌入式学习笔记4-文件系统FATFS
FAT32 文件系统 就是在格式化的时候 选择 FAT32 方式格式化. 然后在 SD 卡存储区会产生一个类似于 目录 的文件系统. 这样存入 SD 卡中的所有 文件 文件夹 都会在这个目录中找到. ...
- 嵌入式学习笔记——基于Cortex-M的单片机介绍
基于Cortex-M的单片机介绍 前言 1生产厂商及其产品线 1.1ARM单片机的产品线 1.2命名规则 作业1 2习单片机的资料准备 2.1STM32开发所需手册 2.1.1芯片的数据手册 芯片基本 ...
- 嵌入式学习笔记——ADC模数转换器
ADC模数转换器 前言 ADC介绍 ADC概述 ADC的数量 ADC的特性 ADC框图 芯片外部框图 芯片内部框图 转换部分框图 状态输出部分 条件触发框图 寄存器介绍 编程思路 模式选择 规则通道的 ...
- cortex_m3_stm32嵌入式学习笔记(十五):待机唤醒实验(WK_UP外部中断)
cortex_m3_stm32嵌入式学习笔记(十五):待机唤醒实验(WK_UP外部中断) https://blog.csdn.net/qq_16255321/article/details/43086 ...
- 嵌入式学习笔记——STM32的USART通信概述
文章目录 前言 常用通信协议分类及其特征介绍 通信协议 通信协议分类 1.同步异步通信 2.全双工/半双工/单工 3.现场总线/板级总线 4. 串行/并行通信 5. 有线通信.无线通信 STM32通信 ...
- 嵌入式学习笔记--jlink 工具RTT使用笔记
嵌入式学习笔记–jlink 工具RTT 使用笔记 最近有调试一个ethcat板卡的需求,板卡设计的很简洁,没有多余的调试串口,正准备飞线到单片机针脚上的时候发现了RTT 的这个工具,记录一下使用的方法 ...
- 嵌入式学习笔记——使用寄存器编程操作GPIO
使用寄存器编程操作GPIO 前言 GPIO相关的寄存器 GPIO 端口模式寄存器 (GPIOx_MODER) (x = A..I) 位操作 GPIO 端口输出类型寄存器 (GPIOx_OTYPER) ...
- 嵌入式学习笔记——寄存器实现控制LED小灯
文章目录 前言 GPIO通用输出模式 初始化LED小灯的GPIO 原理图 初始化代码 初始化的效果 功能函数封装 直接分开宏定义两个 使用条件运算符 封装函数实现简单的功能 KEIL MDK一些技巧 ...
最新文章
- WordPress 性能优化:为什么我的博客比你的快
- LeetCode-剑指 Offer 04. 二维数组中的查找
- 《Java编程思想》《Think in Java》笔记
- boost::integer::mod_inverse用法的测试程序
- MySql和Oracle数据库的区别?
- 前端面试题2021(超详细)
- win10浏览器闪退_win10纯净版系统中edge浏览器闪退的解决方法
- HTML 界面画图工具
- 七夕前夜,地球和月亮搭起“鹊桥”
- 什么?四六级及格线不是425分?!
- ubuntu - sudo file 编辑报错 sudo: no valid sudoers sources found, quitting
- JAVA藏宝阁游戏交易系统计算机毕业设计Mybatis+系统+数据库+调试部署
- 南邮——计算机图像学——光照、冯氏光照模型
- 离散实验sdut3805双射
- win7/win10下KiWi Syslog服务器的安装与配置
- 6.1电机,串口控制,PWM调速
- ora-00600 [25027]
- UE_Visibility Buffer Deferred Material
- linux 能打开exe文件,linux能运行exe文件吗
- ansys添加力矩_ANSYS转矩施加三种方法
热门文章
- OSChina 周日乱弹 —— 我重新说
- signature=45f2913b66c5b2ae668a6622be005d65,国开大《商务英语4》自测试题及答案
- 英伟达P8显卡_英特尔独显芯片上市 AMD 英伟达 英特尔显卡芯片三方对战_笔记本新闻...
- python之while循环、无限循环
- linux怎么打开隐藏文件夹,如何在文件管理器中隐藏文件和文件夹
- 网站CNZZ数据统计的实现方式
- 基于java的企业信息网站发系统
- Excel如何动态获取某个产品最新的库存信息
- 维护设备的库存信息-SERIAL_EQBS_POST
- html5 地铁 代码,基于HTML5WebGL的地铁管理系统