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; }