mpeg压缩输入格式---打包模式和平面模式
版本 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 <Address 0xb7bf6000 out of bounds>
(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?)
mpeg压缩输入格式---打包模式和平面模式的更多相关文章
- MapReduce输入格式
文件是 MapReduce 任务数据的初始存储地.正常情况下,输入文件一般是存储在 HDFS 里面.这些文件的格式可以是任意的:我们可以使用基于行的日志文件, 也可以使用二进制格式,多行输入记录或者其 ...
- MapReduce的输入格式
1. InputFormat接口 InputFormat接口包含了两个抽象方法:getSplits()和creatRecordReader().InputFormat决定了Hadoop如何对文件进行分 ...
- X264库直接压缩BITMAP格式数据
最近帮朋友看了下X264压缩视频,主要参考了雷霄骅(leixiaohua1020)的专栏的开源代码: http://blog.csdn.net/leixiaohua1020/article/detai ...
- linux 压缩解压打包工具大集合
压缩.解压缩及归档工具有很多,今天小编就整理几个大家较为常用的. compress gzip bzip2 xz zip tar cpio 一.压缩.解压工具 用法 压缩 工具 压缩后 压缩包格式 解 ...
- linux命令:压缩解压打包工具大集合
目录 (1)zip 压缩.解压缩及归档工具有很多,今天小编就整理几个大家较为常用的. compress gzip bzip2 xz zip tar cpio 一.压缩.解压工具 用法 压缩 工具 压 ...
- hadoopMR自定义输入格式
输入格式 1.输入分片与记录 2.文件输入 3.文本输入 4.二进制输入 5.多文件输入 6.数据库格式输入 详细的介绍:https://blog.csdn.net/py_123456/ar ...
- MapReduce实战:自定义输入格式实现成绩管理
1. 项目需求 我们取有一份学生五门课程的期末考试成绩数据,现在我们希望统计每个学生的总成绩和平均成绩. 样本数据如下所示,每行数据的数据格式为:学号.姓名.语文成绩.数学成绩.英语成绩.物理成绩.化 ...
- Hadoop MapReduce编程 API入门系列之MapReduce多种输入格式(十七)
不多说,直接上代码. 代码 package zhouls.bigdata.myMapReduce.ScoreCount; import java.io.DataInput; import java.i ...
- Hadoop MapReduce编程 API入门系列之自定义多种输入格式数据类型和排序多种输出格式(十一)
推荐 MapReduce分析明星微博数据 http://git.oschina.net/ljc520313/codeexample/tree/master/bigdata/hadoop/mapredu ...
随机推荐
- 批处理学习笔记6 - 重定向符>和>>
重定向符大概有6,7种,和%符号差不多各有各的用途.这里学习>和>> > 是左边的值把右边的值覆盖 >> 是左边的值添加在右边的值上面 rem 是批处理的注释,类 ...
- 【Android】3.17 示例17--周边雷达功能
分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 一.简介 周边雷达功能同步支持Android和iOS端.它本质是一个连接百度LBS开放平台前端SDK产品和后端 ...
- sudo和man的tab自动补全
要加入sudo和man的tab自动补全功能,只需在~/.bashrc中加入: #Enabling tab-completioncomplete -cf sudocomplete -cf man
- python(25):Unicode 转成中文
代码转换如下: if __name__ == "__main__": data = "\u5c71\u5cb3\u548c\u4e00\u5207\u4e18\u9675 ...
- SQLAlchemy的“缓存”问题导致的BUG
问题描述: 最近做项目,遇到一个问题,两个项目操作同一个数据库,其中A项目用的pymysql链接操作数据库,B项目用的sqlalchemy,当我请求B项目中的一个接口,会通知A项目操作数据库,然后返回 ...
- feignclient设置hystrix参数
序 feign默认集成了hystrix,那么问题来了,如何像hystrix command那样设置每个方法的hystrix属性呢. 实例 @FeignClient("product" ...
- u-boot中添加自定义命令
1.u-boot命令机制u-boot中,每个命令都使用一个struct cmd_tbl_s结构体定义,该定义在include/command.h中实现:struct cmd_tbl_s{ char * ...
- web.xml中init-param中的param-name
转载自:http://www.cnblogs.com/hzj-/articles/1689836.html <context-param>的作用:web.xml的配置中<contex ...
- java 多线程5: java 终止线程及中断机制 (stop()、interrupt() 、interrupted()、isInterrupted())
JAVA中有3种方式可以终止正在运行的线程 ①线程正常退出,即run()方法执行完毕了 ②使用Thread类中的stop()方法强行终止线程.但stop()方法已经过期了,不推荐使用 ③使用中断机制i ...
- 纯css3实现图片三角形排列
当今是个读图时代.纯大部分网页或多或少都会用到图片.特别是图片较多的网页.图片的布局和排版就非常重要了.今天要给大写带来一款纯css3实现图片三角形排列.适合一系列的图片.效果图如下: 在线预览 ...