ffmprg Api 示例1--保存指定时间段的视频数据为yuv格式

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

参考资料:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值