做编解码过程中最常见的视频格式是yuv420p
下面对yuv420p做一些介绍
420p中的p代表planar,也就是扁平的意思。所以这里引出yuv有两种布局方式,分别是planar和packed。
- 对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。
- 对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。
YUV,分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
yuv420p表示:
YUV 4:2:0采样,每四个Y共用一组UV分量。
在ffmpeg中怎么分别获取yuv420p的yuv数据?使用如下代码
1 先使用avcodec_decode_video2 解码获取AVFrame
avcodec_decode_video2(videoCodecCtx, videoFrame, &gotframe, &packet);
2 分别获取yuv数据
// 1 获取y数据(Luma) videoFrame为AVFrame指针,是解码后获取的//其中videoFrame->linesize[0]对应每行包含的y数据个数,videoCodecCtx->height则为数据的列数,videoFrame->data[0]则为真正的y数据int width = MIN(videoFrame->linesize[0], videoCodecCtx->width);int height = videoCodecCtx->height;int lumaLength = width * height;uint8_t * luma = new uint8_t[lumaLength];copyFrameData(luma, videoFrame->data[0], width, height, videoFrame->linesize[0]);// 2 获取u数据(Chroma) videoFrame为AVFrame指针,是解码后获取的//其中videoFrame->linesize[1]对应每行包含的u数据个数,videoCodecCtx->height则为数据的列数,videoFrame->data[1]则为真正的u数据。 这里videoCodecCtx->height要除以2是因为两行y数据共用一行u数据width = MIN(videoFrame->linesize[1], videoCodecCtx->width / 2);height = videoCodecCtx->height / 2;int chromaBLength = width * height;uint8_t * chromaB = new uint8_t[chromaBLength];copyFrameData(chromaB, videoFrame->data[1], width, height, videoFrame->linesize[1]);// 2 获取v数据(Chroma) videoFrame为AVFrame指针,是解码后获取的//其中videoFrame->linesize[2]对应每行包含的v数据个数,videoCodecCtx->height则为数据的列数,videoFrame->data[2]则为真正的v数据。 这里videoCodecCtx->height要除以2是因为两行y数据共用一行v数据width = MIN(videoFrame->linesize[2], videoCodecCtx->width / 2);height = videoCodecCtx->height / 2;int chromaRLength = width * height;uint8_t * chromaR = new uint8_t[chromaRLength];copyFrameData(chromaR, videoFrame->data[2], width, height, videoFrame->linesize[2]);
void VideoDecoder::copyFrameData(uint8_t * dst, uint8_t * src, int width, int height, int linesize) {for (int i = 0; i < height; ++i) {memcpy(dst, src, width);dst += width;src += linesize;}
}