前言
书接上文,发现 YUV420p各个通道不一致的问题后。就猜测FFmpeg里面应该对这点做了处理了吧
自己构造AVFrame
ffmepg里面的demo,encode_video.c,里面已经有了,我稍微修改了下。
网上很多构造AVFrame视频帧的代码已经过时了。
void ProducerScreenCapture::appendYuvFrame(char *yData,int yPerRowBytes,
char *uData,int uPerRowBytes,
char *vData,int vPerRowBytes,
int frameWidth,int frameHeight)
{
AVFrame *t_pFrame = av_frame_alloc();//av_frame_free()
t_pFrame->width = frameWidth;
t_pFrame->height = frameHeight;
t_pFrame->format = AV_PIX_FMT_YUV420P;
int t_ret = av_frame_get_buffer(t_pFrame,32);//申请了AVFrame的内存
if(t_ret < 0)
{
qDebug()<<"robin:av_frame_get_buffer,Could not allocate the video frame data";
return;
}
av_frame_make_writable(t_pFrame);
av_image_copy_plane(t_pFrame->data[0],t_pFrame->linesize[0],(const uint8_t*)yData,yPerRowBytes,yPerRowBytes,frameHeight);
av_image_copy_plane(t_pFrame->data[1],t_pFrame->linesize[1],(const uint8_t*)uData,uPerRowBytes,yPerRowBytes / 2,frameHeight);
av_image_copy_plane(t_pFrame->data[2],t_pFrame->linesize[2],(const uint8_t*)vData,vPerRowBytes,yPerRowBytes / 2,frameHeight);
... 保存起来
发现一个函数av_image_copy_plane,很是不明白。
/**
* Copy image plane from src to dst.
* That is, copy "height" number of lines of "bytewidth" bytes each.
* The first byte of each successive line is separated by *_linesize
* bytes.
*
* bytewidth must be contained by both absolute values of dst_linesize
* and src_linesize, otherwise the function behavior is undefined.
*
* @param dst_linesize linesize for the image plane in dst
* @param src_linesize linesize for the image plane in src
*/
void av_image_copy_plane(uint8_t *dst, int dst_linesize,
const uint8_t *src, int src_linesize,
int bytewidth, int height);
看了函数说明还是不太明白
后来,看了源代码,就知道了
void av_image_copy_plane(uint8_t *dst, int dst_linesize,
const uint8_t *src, int src_linesize,
int bytewidth, int height)
{
image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height);
}
******************************************
******************************************
static void image_copy_plane(uint8_t *dst, ptrdiff_t dst_linesize,
const uint8_t *src, ptrdiff_t src_linesize,
ptrdiff_t bytewidth, int height)
{
if (!dst || !src)
return;
av_assert0(abs(src_linesize) >= bytewidth);
av_assert0(abs(dst_linesize) >= bytewidth);
for (;height > 0; height--) {
memcpy(dst, src, bytewidth);
dst += dst_linesize;
src += src_linesize;
}
}
void av_image_copy_plane(uint8_t *dst, int dst_linesize,
const uint8_t *src, int src_linesize,
int bytewidth, int height)
其中 bytewidth 才是每次实际要复制的数据长度。
而 dst_linesize 和 src_linesize 则是为了内存对齐数据而存在的。
从这里可以看出,内存数据的循环复制还是免不了啊。^o^
总结
AVFrame 进化了这么些年,现在已经提供了更简洁的方式申请内存空间
av_image_copy_plane,提供了通道数据的复制功能。