minigui/mgncs:利用LoadBitmapFromMem函数对摄像头MJPEG格式图像解码

可能与虚拟机有关,在virtualbox虚拟机环境下,即使设置了为RGB或YUV,通过v4l2视频驱动框架读取摄像头帧图像的格式总是MJPEG。
MJPG是什么格式下说明摘自百度百科:

MJPEG全名为 “Motion Joint Photographic Experts Group”,是一种视频编码格式,中文名称翻译为“技术即运动静止图像(或逐帧)压缩技术”。MJPEG广泛应用于非线性编辑领域可精确到帧编辑和多层图像处理,把运动的视频序列作为连续的静止图像来处理,这种压缩方式单独完整地压缩每一帧,在编辑过程中可随机存储每一帧,可进行精确到帧的编辑,此外M-JPEG的压缩和解压缩是对称的,可由相同的硬件和软件实现。但M-JPEG只对帧内的空间冗余进行压缩。不对帧间的时间冗余进行压缩,故压缩效率不高。采用M-JPEG数字压缩格式,当压缩比7:1时,可提供相当于Betacam SP质量图像的节目。https://baike.baidu.com/item/MJPEG

说白了,就是把视频的每一帧压缩成一个JPEG格式的图像。也就是说每一帧都是一个独立完整的JPEG,把它存成后缀为或的文件,就可以用任意看图软件打开了。
所以对于MJPEG格式的视频,解码也不麻烦,只要把它当JPEG图像解码就好了。

minigui库中正好有函数用于对内存图像数据(bmp,png,jpg)解码,只要调用它,就可以直接将一帧图像转为,然后设置为窗口的背景(mWidget的属性),就可以实现视频在窗口中的显示了,完美!

大致的解码片段就是酱紫:

理想是丰满的,现实却很骨感,代码写完了,第一次运行就报错了,错误就出在调用,错误码为,也就是图像格式没有被识别。跟踪到对jpg图像解码部分的代码()就找到了原因,下面是中函数的代码片段,见代码中本文作者添加的注释:

判断开始两个字节是否为JPEG格式的魔数FFDB,这个没有错,但问题是根据JPEG标准的定义,接下来的判断就限定了只认JFIF和Exif两个格式,就不对了,Exif和JFIF格式是被广泛使用的JPEG的文件存储格式,但由此限定JPG只有这两种格式就狭隘了。
MJPEG格式属于视频流就没有文件存储定义,所以可以没有Exif和JFIF标记。
我收到的MJPEG帧图像就没有这个标记,不同的设备表现还不同,台式机上用的摄像头收到的MJPEG帧
开始2个字节FFD8后直接就是FFC0(SOFO,Start Of Frame, 帧图像开始)标记,所以在这一步报错了。
而在笔记本内置的摄像头上收到数据如下:(2,3字节为FFE0,6,7,8,9为AVI1)

这里写图片描述
找到问题原因解决办法就很简单,删除源码中这个判断语句重新编译就OK

另外在函数中也是同样的判断逻辑,处理办法一样,一并修改掉。

2018/09/01 补记:
事后想想,本文的解决办法其实也不严谨,如何正确严谨的判断JPEG格式,请参见我新写的博文:

《c/c++:判断数据(stream)是否为JPEG图像快速而准确的方法》

参考资料

《JPEG文件格式 JFIF & Exif》
《JPEG文件格式介绍》

来源:10km

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2018年7月25日
下一篇 2018年7月25日

相关推荐