本文記錄了使用ffmpeg進(jìn)行視頻解碼的最小解碼器代碼莽红,通過這個(gè)小程序可以理解ffmpeg的解碼過程及用到的api。這里將解碼碼后得到的YUV格式的視頻保存到文件中船老,可以使用YUV Playe播放。代碼已上傳git圃酵,
https://github.com/beijixing/ffmpegStudy
流程圖.jpg
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
void devoder()
{
//注冊(cè)編解碼器
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();
//創(chuàng)建緩存
int nBuffSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pAVCodecCtx->width, pAVCodecCtx->height, 1);
unsigned char* buffer = (unsigned char *)av_malloc(nBuffSize);
//設(shè)置緩存
av_image_fill_arrays(pAVFrameYUV->data, pAVFrameYUV->linesize, buffer,
AV_PIX_FMT_YUV420P, pAVCodecCtx->width,
pAVCodecCtx->height, 1);
//創(chuàng)建AVPacket
AVPacket *pAVPacket = (AVPacket *)av_malloc(sizeof (AVPacket));
//創(chuàng)建圖像轉(zhuǎn)換上下文
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)
{
//格式轉(zhuǎn)換
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;
}