利用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;
- }
参考资料: