利用ffmpeg截取视频播放文件数据并保存为yuv格式。
代码完全参考了这个链接的文章,很详细,在centos进行编译完全没有问题 。
看下面的代码吧:
/*File : testYuv.c
*Auth : sjin
*Date : 20141120
*Mail : 413977243@qq.com
*/
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/parseutils.h>
int main(int argc, char *argv[])
{
const char *szInfile = "BeatIt.mp4";
const char *szStartTime = "00:1:55.179";
const char *szEndTime = "00:4:20.110";
unsigned int i;
int j = 0, k = 0;
int width, height;
int videoStream = -1;
AVFormatContext *pFmtCtx = NULL;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVFrame *pFrame = NULL;
AVPacket packet;
int getframe;
AVRational avR, avTimeUint;
AVDictionary *optionsDict = NULL;
FILE *pFile;
char szFilename[32];
double lframeRate;
int64_t lStartTime, lEndTime; //millisecond(毫秒)=1/1000 s
int64_t pos;
int iStartFrame, iEndFrame;
int isFirst = 1;//is the first keyframe(the frame av_seek_frame finds)
av_register_all();
//convert time string "hh:mm:ss.xxx" to millisecond
if (av_parse_time(&lStartTime, szStartTime, 1) < 0) //lStartTime now in microsecond(1/1000 000 s)
{
printf("parse start time error!\n");
return -1;
}
pos = lStartTime;
lStartTime /= 1000;
if (av_parse_time(&lEndTime, szEndTime, 1) < 0)
{
printf("parse end time error!\n");
return -1;
}
lEndTime /= 1000;
if(avformat_open_input(&pFmtCtx, szInfile, NULL, NULL) != 0){
return -1;
}
if(avformat_find_stream_info(pFmtCtx, NULL) < 0){
return -1;
}
av_dump_format(pFmtCtx, 0, szInfile, 0);
for(i=0; i<pFmtCtx->nb_streams; i++){
if(pFmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
//帧率 分子/分母
lframeRate = pFmtCtx->streams[i]->avg_frame_rate.num / pFmtCtx->streams[i]->avg_frame_rate.den;
//时间基数
avTimeUint.den = pFmtCtx->streams[i]->time_base.den;
avTimeUint.num = pFmtCtx->streams[i]->time_base.num;
width = pFmtCtx->streams[i]->codec->width;
height = pFmtCtx->streams[i]->codec->height;
//calc start and end frame number
iStartFrame = (int)(lStartTime * lframeRate / 1000 + 0.5);
iEndFrame = (int)(lEndTime * lframeRate / 1000 + 0.5);
printf("avTimeUint.den:%d,avTimeUint.num:%d\n",avTimeUint.den,avTimeUint.num);
printf("lframeRate:%f,width:%d,height:%d,lStartTime:%d,lEndTime:%d,iStartFrame:%d,iEndFrame:%d\n",
lframeRate,width,height,lStartTime,lEndTime,iStartFrame,iEndFrame);
videoStream=i;
break;
}
}
if(videoStream==-1)
return -1;
//获得编解码器上下文句柄,
pCodecCtx = pFmtCtx->streams[videoStream]->codec;
// 查找音视频解码器
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec == NULL){
printf("Codec not found!\n");
return -1;
}
// 打开解码器
if(avcodec_open2(pCodecCtx, pCodec, &optionsDict) < 0)
return -1;
//保存解压后的帧数据
pFrame = avcodec_alloc_frame();
//打开保存YUV的文件
sprintf(szFilename, "output.yuv");//output file
pFile = fopen(szFilename, "wb");
if(pFile == NULL)
return -1;
avR.num = 1;
avR.den = AV_TIME_BASE;
//视频时间定位(DTS解码时间戳,PTS显示时间戳)
//返回定位到开始时间的时间基
pos = av_rescale_q(pos, avR, pFmtCtx->streams[videoStream]->time_base);
//跳转到指定时间的视频时刻
if(av_seek_frame(pFmtCtx, videoStream, pos, AVSEEK_FLAG_BACKWARD) < 0)
{
printf("seek failed!\n");
return -1;
}
//情况缓存
avcodec_flush_buffers(pFmtCtx->streams[videoStream]->codec);
while(av_read_frame(pFmtCtx, &packet)>=0)
{
if(packet.stream_index == videoStream)
{
//解码
avcodec_decode_video2(pCodecCtx, pFrame, &getframe, &packet);
if(getframe)
{
//save yuv to disk
if(isFirst)
{
k = lframeRate * pFrame->pkt_pts * avTimeUint.num / avTimeUint.den;
isFirst = 0;
if(pFrame->pict_type == AV_PICTURE_TYPE_SP){
printf("is P frame .........\n");
}
}
if(k >= iStartFrame && k<= iEndFrame)
{
for(j=0; j<height; j++)
fwrite(pFrame->data[0] + j * pFrame->linesize[0], 1, width, pFile);
for(j=0; j<height/2; j++)
fwrite(pFrame->data[1] + j * pFrame->linesize[1], 1, width/2, pFile);
for(j=0; j<height/2; j++)
fwrite(pFrame->data[2] + j * pFrame->linesize[2], 1, width/2, pFile);
}
}
k++;
if(k > iEndFrame)
break;
}
//Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}//while
printf("Resolution: %dx%d", width, height);
fflush(pFile);
fclose(pFile);
//Free the YUV frame
av_free(pFrame);
//Close the codec
avcodec_close(pCodecCtx);
//Close the video file
avformat_close_input(&pFmtCtx);
return 0;
}
参考资料: