FFMPEG

//param splitSeconds 为视频分割的时长 
bool executeSplit(unsigned int splitSeconds)
{
    AVPacket readPkt, splitKeyPacket;
    int ret;
    av_register_all();
    if ((ret = avformat_open_input(&ifmtCtx, inputFileName.c_str(), 0, 0)) < 0) {
        return false;
    }

    if ((ret = avformat_find_stream_info(ifmtCtx, 0)) < 0) {
        return false;
    }
    for (int i = 0; i < ifmtCtx->nb_streams; i++) {

        AVStream *in_stream = ifmtCtx->streams[i];
        if (in_stream->codec->codec_type == AVMEDIA_TYPE_VIDEO){
            video_index = i;
        }

    }
    int den = ifmtCtx->streams[video_index]->r_frame_rate.den;
    int num = ifmtCtx->streams[video_index]->r_frame_rate.num;
    float fps = (float)num / den;
    unsigned int splitVideoSize = fps*splitSeconds;
    string save_name;
    save_name = outputFileName.substr(0, outputFileName.find_last_of("."));
    string temp_name = save_name + "0"+suffixName;
    avformat_alloc_output_context2(&ofmtCtx, NULL, NULL, temp_name.c_str());
    if (!ofmtCtx) {
        return false;
    }
    if (!writeVideoHeader(ifmtCtx, ofmtCtx, temp_name))
    {
        return false;
    }
    vector<uint64_t> vecKeyFramePos;
    uint64_t frame_index = 0;
    uint64_t keyFrame_index = 0;
    int frameCount = 0;
    //读取分割点附近的关键帧位置
    while (1)
    {
        ++frame_index;
        ret = av_read_frame(ifmtCtx, &readPkt);
        if (ret < 0)
        {
            break;
        }
        //过滤,只处理视频流
        if (readPkt.stream_index == video_index){

            ++frameCount;
            if (readPkt.flags&AV_PKT_FLAG_KEY)
            {
                keyFrame_index = frame_index;
            }
            if (frameCount>splitVideoSize)
            {
                vecKeyFramePos.push_back(keyFrame_index);
                frameCount = 0;
            }
        }
        av_packet_unref(&readPkt);
    }

    avformat_close_input(&ifmtCtx);
    ifmtCtx = NULL;
    //为了重新获取avformatcontext
    if ((ret = avformat_open_input(&ifmtCtx, inputFileName.c_str(), 0, 0)) < 0) {
        return -1;
    }

    if ((ret = avformat_find_stream_info(ifmtCtx, 0)) < 0) {
        return -1;
    }
    int number = 0;
    av_init_packet(&splitKeyPacket);
    splitKeyPacket.data = NULL;
    splitKeyPacket.size = 0;
    //时长对应的帧数超过视频的总视频帧数,则拷贝完整视频
    if (vecKeyFramePos.empty()){
        vecKeyFramePos.push_back(frame_index);
    }
    vector<uint64_t>::iterator keyFrameIter = vecKeyFramePos.begin();

    keyFrame_index = *keyFrameIter;
    ++keyFrameIter;
    frame_index = 0;
    int64_t lastPts = 0;
    int64_t lastDts = 0;
    int64_t prePts = 0;
    int64_t preDts = 0;
    while (1)
    {
        ++frame_index;
        ret = av_read_frame(ifmtCtx, &readPkt);
        if (ret < 0)
        {
            break;
        }

        av_packet_rescale_ts(&readPkt, ifmtCtx->streams[readPkt.stream_index]->time_base, ofmtCtx->streams[readPkt.stream_index]->time_base);
        prePts = readPkt.pts;
        preDts = readPkt.dts;
        readPkt.pts -= lastPts;
        readPkt.dts -= lastDts;
        if (readPkt.pts < readPkt.dts)
        {
            readPkt.pts = readPkt.dts + 1;
        }
        //为分割点处的关键帧要进行拷贝
        if (readPkt.flags&AV_PKT_FLAG_KEY&&frame_index == keyFrame_index)
        {
            av_copy_packet(&splitKeyPacket, &readPkt);
        }
        else{
            ret = av_interleaved_write_frame(ofmtCtx, &readPkt);
            if (ret < 0) {
                //break;

            }
        }

        if (frame_index == keyFrame_index)
        {
            lastDts = preDts;
            lastPts = prePts;
            if (keyFrameIter != vecKeyFramePos.end())
            {
                keyFrame_index = *keyFrameIter;
                ++keyFrameIter;
            }
            av_write_trailer(ofmtCtx);
            avio_close(ofmtCtx->pb);
            avformat_free_context(ofmtCtx);
            ++number;
            char num[10];
            _itoa_s(number, num, 10);
            temp_name = save_name + num + suffixName;
            avformat_alloc_output_context2(&ofmtCtx, NULL, NULL, temp_name.c_str());
            if (!ofmtCtx) {
                return false;
            }
            if (!writeVideoHeader(ifmtCtx, ofmtCtx, save_name + num + suffixName))
            {
                return false;
            }
            splitKeyPacket.pts = 0;
            splitKeyPacket.dts = 0;
            //把上一个分片处的关键帧写入到下一个分片的起始处,保证下一个分片的开头为I帧
            ret = av_interleaved_write_frame(ofmtCtx, &splitKeyPacket);
        }


        av_packet_unref(&readPkt);

    }
    av_packet_unref(&splitKeyPacket);
    av_write_trailer(ofmtCtx);
    avformat_close_input(&ifmtCtx);
    avio_close(ofmtCtx->pb);
    avformat_free_context(ofmtCtx);

    return true;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值