您的位置:首页 > 其它

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

2014-11-24 10:28 387 查看

利用ffmpeg截取视频播放文件数据并保存为yuv格式。

代码完全参考了这个链接的文章,很详细,在centos进行编译完全没有问题 。

看下面的代码吧:

[cpp] view
plaincopyprint?





/*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;  

}  

参考资料:
1、关于视频显示时间及PTS相关的知识
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: