vlc+encodeh264编码的坑
1,vlc和encodeh264的编译问题本文不做讨论。
2,vlc中采用使用
libvlc_video_set_callbacks(this->m_pVLC_Player,
lock,
unlock,
vlcVideo::display,this);
libvlc_video_set_format_callbacks(this->m_pVLC_Player,
libvlc_video_format_cb,
libvlc_video_cleanup_cb);
这两个函数获取视频图像数据。需要注意的是,如果设置了libvlc_video_set_callbacks 函数。那么原始提供给vlc的显示视频的窗口将不起作用。需要自己写代码把视频映射到自己指定的窗口上面
。还有一点就是,上面两个函数的回调函数,如果设置成类函数,需要设置成static静态函数。因为,非静态函数是this-call传址方式。隐形参数this也会被传进去,这样就导致了回调函数默认参数
和实际传入的参数不一致导致的崩溃等各种问题。
那么,如果需要使用类中的一些非静态数据,如何调用类中的数据。这个也不难,先看下libvlc_video_set_callbacks这个函数的最后一个参数,这个参数和lock unlock display三个回调函数里面的第一个参数是同一个数据。
比如 把libvlc_video_set_callbacks里面的最后一个参数传入this指针。那么只需要把回调函数第一个参数转换成此类的指针即可。
1,lock回调 void *vlcVideo::lock(void *data, void **p_pixels)
{
THIS_V->mutex.lock();
// *p_pixels=THIS_V->out_buffer; //这个一定要有 外部申请一块内存弓箭给*pixels
switch(THIS_V->m_videoFormat)
{
case VideoFormt::VFormt_YUV420:
p_pixels[0]=THIS_V->out_buffer;
p_pixels[1]=THIS_V->out_buffer+THIS_V->width()*THIS_V->height();
p_pixels[2]=(char *)p_pixels[1]+THIS_V->width()*THIS_V->height()/4;
break;
case VideoFormt::VFormt_RGB888:
p_pixels[0]=THIS_V->out_buffer;
break;
default:
break;
}
return 0;
}
首先说下THIS_V这是定义的一个宏,目的是方便调用类中非静态数据。
代码如下
static inline vlcVideo *t_this2(void *data){return static_cast<vlcVideo*>(data);}
static inline vlcVideo *t_this2(void **data){return static_cast<vlcVideo *>(*data);}
#define THIS_V t_this2(data)
THIS_V可以当做非静态函数里的this指针使用。但是要注意 其他回调函数里的第一个参数名要使用data,转换函数中使用inline修饰成内联函数,编译中不会产生call ret 等一些代码。提高代码执行效率
官方文档lock函数是这样定义的:typedef void*(* libvlc_video_lock_cb) (void *opaque, void **planes)。第二个参数 官方文档使用planes.p_pixels表示像素数据
planes表示平面。基于本人对图像格式的理解 官方的plane名字更合适一些。
要记得在lock中把一块内存赋值给planes.
例如。需要输出的图像格式是RV24(就是RGB888,用24bits存储一个rgb像素数据。),rv24格式的数据,他的平面,也就是plane是1.这个时候我们直接把申请到的和内存赋值给*plane即可。
或者赋值给plane[0].
但是如果输出格式是I420 也就是YUV420.那么需要3个平面。这个时候planes需要每个平面都指定一个地址。如上lock代码中所示。
2 unlock.获取图像数据在unlock中。这个时候p_pixels指向的就是图像数据。
3,display 是显示回调。是处理图像显示的。我们直接在unlock中处理即可。 这个三个回调调用顺序是 lock display unlock.
再说说libvlc_video_set_format_callbacks。这个是设置输出图像格式,长宽,等个个参数的。当然。libvlc_video_set_format也可以设置。但是libvlc_video_set_format好像只能设置1个平面的图像格式。如果是I420多平面格式图像,还需要使用回调函数设置
libvlc_video_format_cb 的定义libvlc_video_format_cb(void **data, char *chroma, unsigned *width, unsigned *height, unsigned *pitches, unsigned *lines)
第一个参数 data,和videocallback中最后一个参数一样。不做详谈。
2,chroma 图片格式。如RV24 RV32 I420 I422 I444等 如果不设置 他的默认值我的电脑是XD11.好像和平台相关
3。width 和 height 图片的长宽。可更改为自己需要的长宽
4,pitches 跨度。意思是planes数据中每行占用的字节数。比如 RV24格式。因为一个像素需要3个字节表示。所以这个*pitches=*width*3; 如果是YUV的Y平面 那么就是 pitches[0]=*width*1;U平面 pitches[1]=*width/2
5,lines 为每个planes数据的高度。比如比如 RV24格式。因*lines =*heitht; 如果是YUV的Y平面 那么就是 lines[0]=*height*1; U平面lines[0]=*height*1lines[1]=*height/2;
详细libvlc_video_set_format_callbacks 设置如下代码
unsigned vlcVideo::libvlc_video_format_cb(void **data, char *chroma, unsigned *width, unsigned *height, unsigned *pitches, unsigned *lines)
{
switch(THIS_V->m_videoFormat)
{
case VideoFormt::VFormt_YUV420:
qstrcpy(chroma,THIS_V->m_sformat);
// THIS_V->m_width=*width;
// THIS_V->m_height=*height;
*width=THIS_V->m_width;
*height=THIS_V->m_height;
pitches[0]=THIS_V->m_width;//Y
pitches[1]=THIS_V->m_width/2;//U
pitches[2]=THIS_V->m_width/2;//V
lines[0]=THIS_V->m_height;//Y
lines[1]=THIS_V->m_height/2;//U
lines[2]=THIS_V->m_height/2;//V
//THIS_V->out_buffer=(char*)realloc(THIS_V->out_buffer, THIS_V->m_width*THIS_V->m_height*THIS_V->sizeRate);
break;
case VideoFormt::VFormt_RGB888:
qstrcpy(chroma,THIS_V->m_sformat);
*width=THIS_V->m_width;
*height=THIS_V->m_height;
pitches[0]=THIS_V->m_width*THIS_V->sizeRate;
lines[0]=THIS_V->m_height;
;
break;
default:
break;
}
lines[0]=*height*1
继续讲encode264中的主要函数
首先是初始化参数的设置。这个不讲。百度上很多例子、只讲几个注意点。
param->i_csp=x264_csp_1420 这个参数和vlc回调函数中设置的图片格式对应。如果不匹配会编码失败。RV24 对应x264_csp_RGB I420对应x264_csp_i420
还有就是把图像数据赋值给picture_in pic_in->img->plane 如果图片格式中只有一个plane那么直接复制。如果 有多个,需要类似lock中分段赋值。
this->m_pX264Pic_in->img.plane[0]
m_pX264Param->i_csp = this->m_csp; //x264_csp_i420