http://www.cnblogs.com/mlj318/archive/2013/05/03/3057305.html
ffmpeg对avs编解码的支持
输出的avs码流是.cavs格式的。
编码:ffmpeg -s 640x480 -i test.yuv -b 300k -vcodec libxavs test.cavs
解码:ffmpeg -i test.cavs test.yuv
http://xavs.sourceforge.net/xavs_ffmpeg.html
http://ffmpeg.zeranoe.com/builds/
ffmpeg提供的encoding-example有不少问题,解码正确的h264比特流文件时,报错信息如下:
error while decoding MB 5 4, bytestream (-11).
原因是avcodec_decode_video2传进来的是要完整的一帧,在此之前调用av_parser_parse2来取一帧。 之前低版本的avcodec_decode_video不需要传进来完整的一帧,升级之后还不如以前了。。。
参考http://bbs.chinavideo.org/viewthread.php?tid=14008&extra=page%3D1 的解码过程,以下代码可以正确解码264和avs码流了。
使用的是zeranoe 提供的共享库,ffmpeg版本应该是 ffmpeg-1.2-win32-shared.7z 。
avs编码使用-vcodec libxavs 选项,解码的AVCodecID 是 AV_CODEC_ID_CAVS.
解码的结果与ffmpeg-1.2-win32-static.7z 静态版ffmpeg.exe解码的结果基本一样,中间会有几帧有区别。
#include <math.h>
#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
#define INBUF_SIZE 4096
FILE
*fp = NULL;
AVFrame * m_pFrame;
//AVFormatContext *m_pFormatCtx;
AVCodecParserContext * m_parser;
AVCodec *m_pCodec;
AVCodecContext *m_pCodecContext;
//初始化
int
Decode_init(unsigned
int
width,unsigned
int
height)
{
int
iRet ;
/* register all the codecs */
avcodec_register_all();
m_pCodec=avcodec_find_decoder(AV_CODEC_ID_CAVS);
if
(m_pCodec==NULL)
{
printf
(
"Error avcodec_find_decoder"
);
return
0;
}
m_pCodecContext=avcodec_alloc_context3(m_pCodec);
if
(m_pCodecContext==NULL)
{
printf
(
"Error avcodec_alloc_context"
);
return
0;
}
//m_pCodecContext->width = width; //不用初始化图像尺寸一样可以解
// m_pCodecContext->height = height;
//m_pCodecContext->codec_id = CODEC_ID_H264;
m_pCodecContext->pix_fmt = PIX_FMT_YUV420P;
iRet = avcodec_open2(m_pCodecContext,m_pCodec,NULL);
if
(iRet<0)
{
printf
(
"Error avcodec_open"
);
return
0;
}
m_pFrame=avcodec_alloc_frame();
if
(m_pFrame==NULL)
{
printf
(
"Error avcodec_alloc_frame"
);
return
0;
}
//下面的内容,示例中没有
//m_pFormatCtx=avformat_alloc_context();
//if (!m_pFormatCtx)//分配内存失败
//{
// printf("avformat_alloc_context error\n");
// return 0;
//}
m_parser = av_parser_init(AV_CODEC_ID_CAVS);
if
(!m_parser)
return
0;
return
1;
}
//释放
int
Decode_uninit()
{
av_free(m_pFrame);
avcodec_close(m_pCodecContext);
av_free(m_pCodecContext);
return
1;
}
static
int
DecodeFrame(uint8_t *data ,
int
size,unsigned
char
*yuvOutBuffer)
{
int
got_picture=0;
int
iRet;
AVPacket avp;
av_init_packet(&avp);
avp.data=data;
avp.size=size;
iRet = avcodec_decode_video2(m_pCodecContext,m_pFrame,&got_picture,&avp);
if
(iRet>=0)
{
if
(got_picture)
{
int
i;
for
( i=0; i<m_pCodecContext->height; i++)
fwrite
(m_pFrame->data[0] + i * m_pFrame->linesize[0], 1, m_pCodecContext->width, fp);
for
( i=0; i<m_pCodecContext->height/2; i++)
fwrite
(m_pFrame->data[1] + i * m_pFrame->linesize[1], 1, m_pCodecContext->width/2, fp);
for
( i=0; i<m_pCodecContext->height/2; i++)
fwrite
(m_pFrame->data[2] + i * m_pFrame->linesize[2], 1, m_pCodecContext->width/2, fp);
}
}
return
got_picture;
}
//调用入口函数
void
DecodeVideo(uint8_t * pInBuffer,
int
size,unsigned
char
*yuvOutBuffer)
{
int
pos=0;
int64_t pts=AV_NOPTS_VALUE;
int64_t dts=AV_NOPTS_VALUE;
do
{
uint8_t *pout;
int
pout_len;
int
len= av_parser_parse2(m_parser,m_pCodecContext,&pout,&pout_len, pInBuffer+pos,size-pos,pts,dts,AV_NOPTS_VALUE);
pos +=len;
if
(pout_len >0 )
{
DecodeFrame(pout,pout_len,yuvOutBuffer);
}
}
while
(pos<size);
if
(size<=0)
{
while
(DecodeFrame(NULL,0,yuvOutBuffer));
}
}
int
main(
int
argc,
char
**argv)
{
const
char
*output_type;
FILE
*f;
f =
fopen
(
"test.cavs"
,
"rb"
);
if
(!f) {
fprintf
(stderr,
"Could not open %s\n"
,
"test.264"
);
exit
(1);
}
fp=
fopen
(
"out.yuv"
,
"wb"
);
Decode_init(704,480);
{
uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
/* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
memset
(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
for
(;;) {
int
size =
fread
(inbuf, 1, INBUF_SIZE, f);
if
(size== 0)
break
;
DecodeVideo(inbuf,size,NULL);
}
}
fclose
(f);
fclose
(fp);
Decode_uninit();
return
0;
}
|