热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

格式

版本 v1.0,存在内存问题 在 void v4l2_process_image(struct buffer buf)中对 v4l2 采集来的一帧进行处理,存在 struct buffer bu f
版本 v1.0,存在内存问题


在 void v4l2_process_image(struct buffer buf)中对 v4l2 采集来的一帧进行处理,存在 struct buffer bu


f 中


buffer 结构定义为:


struct buffer {


void *    start;


size_t   length;


};


buffer.start 为 YUV422 格式数据的起始地址。


有关 YUV 格式:


YUV 格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将 YUV 分量存放在同一个数组中,


通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放 YUV 三个分量,就像


是一个三维平面一样。


对于 YUV422(YUV2,V4L2_PIX_FMT_YUYV)格式,属于打包格式,存储顺序为:


Byte Order. Each cell is one byte.


start + 0:     Y'00 Cb00 Y'01 Cr00 Y'02 Cb01 Y'03 Cr01


start + 8:     Y'10 Cb10 Y'11 Cr10 Y'12 Cb11 Y'13 Cr11


start + 16: Y'20 Cb20 Y'21 Cr20 Y'22 Cb21 Y'23 Cr21


start + 24: Y'30 Cb30 Y'31 Cr30 Y'32 Cb31 Y'33 Cr31


参见: http://www.linuxtv.org/downloads/v4l-dvb-apis/re09.html#id2765148 (2010.7.12)


对于 YUV420(YUV2,V4L2_PIX_FMT_YVU420)格式,属于平面格式,存储顺序为:


Byte Order. Each cell is one byte.


start + 0:      Y'00 Y'01 Y'02 Y'03


start + 4:      Y'10 Y'11 Y'12 Y'13


start + 8:      Y'20 Y'21 Y'22 Y'23


start + 12: Y'30 Y'31 Y'32 Y'33


start + 16: Cr00 Cr01


start + 18: Cr10 Cr11


start + 20: Cb00 Cb01


start + 22: Cb10 Cb11


参见: http://www.linuxtv.org/downloads/v4l-dvb-apis/re14.html#id2770792 (2010.7.12)


v4l2 抓取的帧为 YUV422,但 ffmpeg 中 mpeg4 编码的输入帧格式为 YUV420,在 ffmpeg 编码中输入的帧结构


为 AVFrame ,其数据结构中有关帧数据的部分为:


{


uint8_t *data[4];


int linesize[4];   // number of bytes per line


其它信息(是否是 key_frame,已编码图像书 coded_picture_number、


是否作为参考帧 reference、宏块类型 *mb_type 等等,目前未用到);


}


另外要提到的一种数据结构 AVPicture :


typedef struct AVPicture {


uint8_t *data[4];


int linesize[4];   //number of bytes per line


} AVPicture;


AVPicture 的存在有以下原因,AVPicture 将 Picture 的概念从 Frame 中提取出来,就只


由 Picture(图片)本身的信息,亮度、色度和行大小。而 Frame 还有如是否是 key_frame 之类的信息。


所以要从 v4l2 采集到的帧(v4l2_process_image 中 buf.start)转换为 YUV420 格式给编码器,需要两个 A


VFrame(其实 AVPicture 已经足够了):


AVFrame *srcbuf ;  //源格式 YUV422


AVFrame *dstbuf ;    //目标 YUV420


对于 YUV422 格式只用到了 srcbuf->data[0]存放 YUV 数据(打包格式),和 srcbuf->linesize[0]这是一


帧每行所站的 bytes 数(YUV422 为 width *2)。


对于 YUV420 格式(平面格式),则 data[0]、data[1]、data[2]对应 YUV 三个平面。


data[0]:Y 起始 addr,size 个 y 数据。       (size=width *height)


data[1] = data[0] + size;    // U 起始 addr ,size/4 个 U


data[2] = data[1] + size / 4;   // V 起始 addr,size/4 个 V


从 YUV422 转换为 YUV420 格式可以利用 ffmpeg 下 libavcodec/imgconvert.c 中的


void yuyv422_to_yuv420p(AVPicture *dst, const AVPicture *src,


int width, int height) 函数,


但要设置好 srcbuf , dstbuf,(强制类型转换)并为分配好内存,刚开始就是在这方面出现问题,后面


再提。


总结,现在有了 buffer buf 结构的帧数据(在 buf.start 中以 YUV422 存储),先要将其放到 AVFrame                    *


srcbuf 中(仍为 YUV422 格式),再用 yuyv422_to_yuv420p 转换为 YUV420 格式并存在 AVFrame *dstb


uf ,dstbuf 交给编码器 mpeg4 编码。


在版本 v1.0,为初次遇到的内存错误:





dstbuf = avcodec_alloc_frame();


只是这样就以为为 srcbuf ,               dstbuf 分配好了内存。


srcbuf->data[0] = (uint8_t*)buf.start;srcbuf->data[0]指向 buf.start 就开始 yuyv422_to_yuv42


0p 转换了。(见 main.c v4l2_process_image 函数)


运行时错误信息: 段错误


调试信息:


Breakpoint 1, v4l2_process_image (buf=...) at main.c:29


29        srcbuf = avcodec_alloc_frame();


(gdb) s


30        dstbuf = avcodec_alloc_frame();


(gdb) s


31       srcbuf->data[0] = (uint8_t*)buf.start;


(gdb) s


32       srcbuf->linesize[0] = V4L2_WIDTH*2;


(gdb) p srcbuf->data[0]


$1 = (uint8_t *) 0xb7bf6000



(gdb) p srcbuf->data[0][0]@10


Cannot access memory at address 0xb7bf6000


(gdb) p   buf.start[0]@10


Attempt to dereference a generic pointer.


(gdb) p dstbuf->data[0]


$2 = (uint8_t *) 0x0


(gdb) p dstbuf->data[0][0]@5


Cannot access memory at address 0x0


srcbuf->data[0]已指向 buf.start,但是无法访问数组的数据,可能是指针为 void*的原因,(uint8_t


*)强制转换也没用。


dstbuf->data[0]的值为 (uint8_t *) 0x0,并没有指向可用的内存。所以 srcbuf = avcodec_alloc_fr


ame()并没有分配内存,可能只是声明了 srcbuf 为 AVFrame。还需要用 malloc()分配内存。


在版本 v1.1,针对以上问题的处理为:





uint8_t   *picture_bufdst,*picture_bufsrc;


AVFrame *srcbuf = NULL;  //源 YUV422


AVFrame *dstbuf = NULL; //目标 YUV420


srcbuf = avcodec_alloc_frame();


dstbuf = avcodec_alloc_frame();


picture_bufsrc = malloc(640 * 480 *2);


srcbuf->data[0] = picture_bufsrc;


memcpy(srcbuf->data[0], buf.start, 640 * 480 * 2);


srcbuf->linesize[0] = V4L2_WIDTH*2;        //每行 bytes 数


picture_bufdst = malloc((640 * 480 * 3) / 2); /* size for YUV 420 */


dstbuf->data[0] = picture_bufdst;  //Y 起始 addr,size 个 Y


dstbuf->data[1] = dstbuf->data[0] + 640*480;   // U 起始 addr ,size/4 个 U


dstbuf->data[2] = dstbuf->data[1] + 640*480/4;   //  V 起始 addr,size/4 个 V


dstbuf->linesize[0] = c->width;


dstbuf->linesize[1] = c->width / 2;


dstbuf->linesize[2] = c->width / 2;


可见,不但要分配内存,还要使 data[0]等指针指向正确的位置。即对 AVFrame 的初始化(其实也就是内


存分配)。


以下为调试信息:


(gdb) p srcbuf->data[0][0]@10


$2 = "\213r\214t\214t\213u\212r"


(gdb) p   buf.start[0]@10


Attempt to dereference a generic pointer.


(gdb)   p dstbuf->data[0][0]@5


$3 = "\000\000\000\000"


buf.start[0]仍无法访问, srcbuf , dstbuf 已可用.


在版本 v1.2 改进:





encod_init() 为编码的初始化相关的函数。


Srcbuf 直接指向 buf.start ,省略了 memcpy()。


在版本 v1.3 改进:





AVCodecContext *c,c->pix_fmt = PIX_FMT_YUYV422 可设置 Pixel forma,将其设为 YUV422 格式,


出错:only YUV420 and YUV422 are supported ,原来是设错了,但知道了支持的格式了。


改为 c->pix_fmt = PIX_FMT_YUV422P ,这样省去了到 YUV420 的转换。


首先 srcbuf 直接指向 buf.start ,出现了段错误,


(gdb) p srcbuf->data[0][0]@10


Cannot access memory at address 0xb7bf5000


(gdb) s


73           out_size = avcodec_encode_video(c, outbuf, OUTBUF_SIZE, srcbuf);


(gdb) s


Program received signal SIGSEGV, Segmentation fault.


0x00b76fc6 in ?? () from /lib/tls/i686/cmov/libc.so.6


(gdb) q


再用 memcpy(srcbuf->data[0], buf.start, 640 * 480 * 2);


(gdb) p srcbuf->data[0][0]@10


$1 = "Bk@|>l>{Bm"


77           out_size = avcodec_encode_video(c, outbuf, OUTBUF_SIZE, srcbuf);


(gdb) p out_size


$1 = 0


(gdb) s


Program received signal SIGSEGV, Segmentation fault.


0x00b76fc6 in ?? () from /lib/tls/i686/cmov/libc.so.6


srcbuf->data[0]有数据,但仍然在 avcodec_encode_video 中出现段错误。


原因呢?


在 ffmpeg 中对各种格式的解释为:


PIX_FMT_YUV422P


planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)


PIX_FMT_YUV420P


planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)


PIX_FMT_YUYV422


packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr


引自:file:///usr/share/doc/ffmpeg-doc/html/pixfmt_8h.html#a60883d4958a60b91661e97027a85072a


在 V4L2 下的解释:


V4L2_PIX_FMT_YUV422P 4 × 4 pixel image


Byte Order. Each cell is one byte.


start + 0:     Y'00 Y'01 Y'02 Y'03


start + 4:     Y'10 Y'11 Y'12 Y'13


start + 8:     Y'20 Y'21 Y'22 Y'23


start + 12: Y'30 Y'31 Y'32 Y'33


start + 16: Cb00 Cb01


start + 18: Cb10 Cb11


start + 20: Cb20 Cb21


start + 22: Cb30 Cb31


start + 24: Cr00 Cr01


start + 26: Cr10 Cr11


start + 28: Cr20 Cr21


start + 30: Cr30 Cr31


引自:http://www.linuxtv.org/downloads/v4l-dvb-apis/re16.html#id3090524




其 YUV422 是指 PIX_FMT_YUV422P ,仍为平面格式(planar),而 video4linux 输入的应该是 PIX_FMT


_YUYV422 打包格式,所以始终还是要进行转换。


所以本文涉及的 YUV 三中格式总结为:


YUYV422:v4l 输出格式,打包格式


YUV420P,YUV422P:平面格式,ffmpeg 编码器支持的输入格式。(带 P 的为 planar?)

推荐阅读
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了一个从入门到高手的VB.NET源代码,通过学习这些源代码,可以在21天内成为VB.NET高手。文章提供了下载地址,并提醒读者加入作者的QQ群和收藏作者的博客。 ... [详细]
  • 本文介绍了使用C++Builder实现获取USB优盘序列号的方法,包括相关的代码和说明。通过该方法,可以获取指定盘符的USB优盘序列号,并将其存放在缓冲中。该方法可以在Windows系统中有效地获取USB优盘序列号,并且适用于C++Builder开发环境。 ... [详细]
  • loader资源模块加载器webpack资源模块加载webpack内部(内部loader)默认只会处理javascript文件,也就是说它会把打包过程中所有遇到的 ... [详细]
  • STM32 IO口模拟串口通讯
    转自:http:ziye334.blog.163.comblogstatic224306191201452833850647前阵子,调项目时需要用到低波 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
author-avatar
mySi2502876237
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有