书接上文,发现 YUV420p各个通道不一致的问题后。就猜测FFmpeg里面应该对这点做了处理了吧
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; } }其中 bytewidth 才是每次实际要复制的数据长度。 而 dst_linesize 和 src_linesize 则是为了内存对齐数据而存在的。 从这里可以看出,内存数据的循环复制还是免不了啊。^o^
AVFrame 进化了这么些年,现在已经提供了更简洁的方式申请内存空间 av_image_copy_plane,提供了通道数据的复制功能。