YUV转H264
代码如下:
#define _WIDTH 352
#define _HEIGHT 288
void CEncodeYUVDlg::OnButEncode()
{
// TODO: Add your control notification handler code here
uint8_t *video_outbuf;
int video_outbuf_size, out_size;
/* alloc image and output buffer */
video_outbuf_size = 10000000;
video_outbuf = (unsigned char *)malloc(video_outbuf_size);
av_register_all();
avcodec_init();
unsigned char sYUV_data[_WIDTH*_HEIGHT*3/2];
AVCodecContext *pContext = avcodec_alloc_context();
/* put sample parameters */
pContext->codec_id = CODEC_ID_H264; //也可设其他类型,如:CODEC_ID_MPEG1VIDEO,但参数需更改,如:400K码率,10的帧率,就会崩溃。
pContext->codec_type = CODEC_TYPE_VIDEO;
pContext->bit_rate = 400000;
pContext->width = _WIDTH;
pContext->height = _HEIGHT;
pContext->time_base.den = 25;
pContext->time_base.num = 1;
pContext->gop_size = 25;
pContext->pix_fmt = PIX_FMT_YUV420P;
pContext->dct_algo = 0;
pContext->me_pre_cmp=2;
pContext->cqp = 26;
pContext->me_method =7;
pContext->qmin = 3;
pContext->qmax = 31;
pContext->max_qdiff = 3;
pContext->qcompress = 0.5;
pContext->qblur = 0.5;
pContext->nsse_weight = 8;
pContext->i_quant_factor = (float)0.8;
pContext->b_quant_factor = 1.25;
pContext->b_quant_offset = 1.25;
/* find the mpeg1 video encoder */
AVCodec* codec = avcodec_find_encoder(pContext->codec_id);
avcodec_open(pContext, codec);
AVFrame* g_pInFrame = avcodec_alloc_frame();
int isize = pContext->width * pContext->height;
g_pInFrame->data[0] = sYUV_data;
g_pInFrame->data[1] = g_pInFrame->data[0] + isize;
g_pInFrame->data[2] = g_pInFrame->data[1] + isize / 4;
g_pInFrame->linesize[0] = pContext->width;
g_pInFrame->linesize[1] = pContext->width / 2;
g_pInFrame->linesize[2] = pContext->width / 2;
FILE* fp = fopen("01.mov","rb");
int nread = -1;
if (fp!=NULL)
{
while(nread!=0)
{
nread = fread(sYUV_data,1,_WIDTH*_HEIGHT*3/2,fp);
out_size = avcodec_encode_video(pContext, video_outbuf, video_outbuf_size, g_pInFrame);
if (out_size>0)
{
FILE* ff = fopen("1.mov","ab");
if (ff!=NULL)
{
fwrite(video_outbuf,1,out_size,ff);
fclose(ff);
}
}
}
fclose(fp);
AfxMessageBox("Encode Over!");
}
}
H264转YUV
有一帧H264码流,如何变成YUV数据。
ffmpeg解码
代码如下:
avcodec_init();
av_register_all();
AVCodec* m_pCodec=avcodec_find_decoder(CODEC_ID_H264);
if(NULL==m_pCodec)
return FALSE;
AVCodecContext* m_pContext = avcodec_alloc_context();
AVFrame* m_pFrame = avcodec_alloc_frame();
if(NULL==m_pContext ||NULL==m_pFrame)
return FALSE;
if (avcodec_open(m_pContext, m_pCodec) < 0)
{
return FALSE;
}
int nWidth = 352;
int nHeight = 288;
int uSize;
int iLen=avcodec_decode_video(m_pContext,m_pFrame,&uSize,pInBuffer,iBufferSize);
if((uSize>0) &&(iLen>0))
{
LPBYTE PtrY = m_pFrame->data[0];
LPBYTE PtrU = m_pFrame->data[1];
LPBYTE PtrV = m_pFrame->data[2];
int iSizeY = m_pFrame->linesize[0];
int iSizeU = m_pFrame->linesize[1];
int iSizeV = m_pFrame->linesize[2];
FILE*fp = fopen("1.yuv","ab");
if (fp!=NULL)
{
//copy y
for (int i =0;i<nHeight;i++)
{
fwrite(PtrY,1,nWidth,fp);
PtrY+=iSizeY;
}
//copy u
for (int i =0;i<nHeight/2;i++)
{
fwrite(PtrU,1,nWidth/2,fp);
PtrU+=iSizeU;
}
//copy v
for (int i =0;i<nHeight/2;i++)
{
fwrite(PtrV,1,nWidth/2,fp);
PtrV+=iSizeV;
}
copy to file
fclose(fp);
}
}
注:
AVPicture
对应AVPicture里面有data[4]和linesize[4]其中data是一个指向指针的指针(二级、二维指针),也就是指向视频数据缓冲区的首地址,而data[0]~data[3]是一级指针,可以用如下的图来表示:
data -->xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
^ ^ ^
| | |
data[0] data[1] data[2]
比如说,当pix_fmt=PIX_FMT_YUV420P时,data中的数据是按照YUV的格式存储的,也就是:
data -->YYYYYYYYYYYYYYUUUUUUUUUUUUUVVVVVVVVVVVV ^ ^ ^ | | | data[0] data[1] data[2]linesize是指对应于每一行的大小,为什么需要这个变量,是因为在 YUV格式和RGB格式时,每行的大小不一定等于图像的宽度,对于RGB格式输出时,只有一个通道(bgrbgrbgr......)可用,即 linesize[0],和data[0],so RGB24 : data[0] = packet rgb//bgrbgrbgr......
linesize[0] = width*3其他的如data[1][2][3]与linesize[1][2][3]无任何意义.
而对于YUV格式输出时,有三个通道可用,即data[0][1][2],与linesize[0][1][2],而yuv格式对于运动估计时,需要填充padding(right, bottom),故:linesize=width+padding size(16+16).