本文记录了使用ffmpeg进行视频解码的最小解码器代码,通过这个小程序可以理解ffmpeg的解码过程及用到的api。这里将解码码后得到的YUV格式的视频保存到文件中,可以使用YUV Playe播放。代码已上传git,
https://github.com/beijixing/ffmpegStudy
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
void devoder()
{
//注册编解码器
av_register_all();
AVFormatContext *pAVFormatCtx = NULL;
int ret = avformat_open_input(&pAVFormatCtx,"Titanic.mkv",NULL, NULL);
if(ret != 0)
{
printf("avformat_open_input failed!");
return;
}
//查找流信息
ret = avformat_find_stream_info(pAVFormatCtx, NULL);
if(ret != 0)
{
printf("avformat_find_stream_info failed!");
return;
}
//查找视频流索引
int videoIndex = -1;
videoIndex = av_find_best_stream(pAVFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, NULL);
if(videoIndex < 0)
{
printf("av_find_best_stream failed!");
return;
}
//查找解码器上下文
AVCodecContext *pAVCodecCtx = pAVFormatCtx->streams[videoIndex]->codec;
//查找解码器
AVCodec *pAVCodec = avcodec_find_decoder(pAVCodecCtx->codec_id);
if(pAVCodec == NULL)
{
printf("Codec not found.\n");
return;
}
//打开解码器
ret = avcodec_open2(pAVCodecCtx, pAVCodec, NULL);
if(ret < 0)
{
printf("avcodec_open2 failed !\n");
return;
}
//解码视频
AVFrame *pAVFrame = av_frame_alloc();
AVFrame *pAVFrameYUV = av_frame_alloc();
//创建缓存
int nBuffSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pAVCodecCtx->width, pAVCodecCtx->height, 1);
unsigned char* buffer = (unsigned char *)av_malloc(nBuffSize);
//设置缓存
av_image_fill_arrays(pAVFrameYUV->data, pAVFrameYUV->linesize, buffer,
AV_PIX_FMT_YUV420P, pAVCodecCtx->width,
pAVCodecCtx->height, 1);
//创建AVPacket
AVPacket *pAVPacket = (AVPacket *)av_malloc(sizeof (AVPacket));
//创建图像转换上下文
SwsContext *pSwsCtx = sws_getContext(pAVCodecCtx->width, pAVCodecCtx->height,
pAVCodecCtx->pix_fmt, pAVCodecCtx->width, pAVCodecCtx->height,
AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
int gotPicture = 0;
FILE* pYuvFile = fopen("test.yuv", "wb");
if(!pYuvFile)
{
printf("fopen test.yuv failed !\n");
return;
}
int frameCnt = 0;
while (av_read_frame(pAVFormatCtx, pAVPacket) >= 0)
{
//只解码视频
if(pAVPacket->stream_index == videoIndex)
{
ret = avcodec_decode_video2(pAVCodecCtx, pAVFrame, &gotPicture, pAVPacket);
if(ret < 0)
{
printf("avcodec_decode_video2 failed !\n");
break;
}
if(gotPicture)
{
//格式转换
sws_scale(pSwsCtx, pAVFrame->data,
pAVFrame->linesize,
0,
pAVCodecCtx->height,
pAVFrameYUV->data,
pAVFrameYUV->linesize);
fwrite(pAVFrameYUV->data[0],1,pAVCodecCtx->width*pAVCodecCtx->height, pYuvFile);
fwrite(pAVFrameYUV->data[1],1,pAVCodecCtx->width*pAVCodecCtx->height/4, pYuvFile);
fwrite(pAVFrameYUV->data[2],1,pAVCodecCtx->width*pAVCodecCtx->height/4, pYuvFile);
frameCnt++;
printf("frameCnt = %d !\n", frameCnt);
}
}
}
//释放指针
fclose(pYuvFile);
sws_freeContext(pSwsCtx);
av_frame_free(&pAVFrame);
av_frame_free(&pAVFrameYUV);
av_packet_free(&pAVPacket);
avformat_close_input(&pAVFormatCtx);
}
int main(int argc, char *argv[])
{
devoder();
return 0;
}