FFmpeg 音视频裁剪demo

void media_cut() {
    //1.处理一些参数
    char* src = "/Users/king/Desktop/ffmpeg/audio/cpptest.mp4";
    char* dst = "/Users/king/Desktop/ffmpeg/audio/cut.mp4";;
    double startTime = 60.0;
    double endTime = 180.0;/// 这里是秒
    
    av_log_set_level(AV_LOG_DEBUG);
    //2.打开多媒体文件
    int ret = 0;
    AVFormatContext *context = NULL;
    ret = avformat_open_input(&context, src, NULL, NULL);
    if  (ret < 0) {
        av_log(NULL, AV_LOG_DEBUG, "format mmedia = %s\n",av_err2str(ret));
        goto __ERROR;
    }
    //4.打开目的文件的上下文
    AVFormatContext *o_context = NULL;
    avformat_alloc_output_context2(&o_context, NULL, NULL, dst);
    if (!o_context) {
        av_log(NULL, AV_LOG_DEBUG, "o_context = null \n");

        goto __ERROR;
    }
    int *stream_map = NULL;
    
    stream_map = av_calloc(context->nb_streams, sizeof(int));
    if (stream_map == NULL) {
        av_log(NULL, AV_LOG_DEBUG, "stream_map == null\n");

        goto __ERROR;
    }
    int streamIndex = 0;
    for (int i = 0; i < context->nb_streams; i++) {
        AVStream *outStream = NULL;
        AVStream *instream = context->streams[i];
        AVCodecParameters *inCodecPar = instream->codecpar;
        if (inCodecPar->codec_type != AVMEDIA_TYPE_AUDIO && inCodecPar->codec_type != AVMEDIA_TYPE_VIDEO && inCodecPar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
            stream_map[i] = -1;
            continue;
        }
        stream_map[i] = streamIndex++;
        outStream = avformat_new_stream(o_context, NULL);
        if (!outStream) {
            av_log(o_context, AV_LOG_DEBUG, "outStream create failed\n");
            goto __ERROR;
        }
        avcodec_parameters_copy(outStream->codecpar, instream->codecpar);
        //codec_tag 设置成0会根据多媒体文件自动适配编解码器 不适特别了解建议写成0 了解的话可以写成一个固定的值
        outStream->codecpar->codec_tag = 0;

    }
    
    /// 绑定
    ret = avio_open2(&o_context->pb, dst, AVIO_FLAG_WRITE, NULL, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_DEBUG, "ret bind = %s\n",av_err2str(ret));
        goto __ERROR;
    }
    
    //7.写多媒体文件头到目的文件
    ret = avformat_write_header(o_context, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_DEBUG, "ret avformat_write_header = %s\n",av_err2str(ret));
        goto __ERROR;
    }
    //8.从源多媒体文件中读到音频/视频/字幕数据到目的文件中
    ///   第二个参数-1会选择一个默认的流 第三个参数 就是截取开始的时间戳 第四个参数 对于视频来说并不能从具体时间戳开始而是从最近的I帧处开始
   ret =  av_seek_frame(context, -1, startTime * AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
    if (ret < 0) {
        av_log(NULL, AV_LOG_DEBUG, "seek error  = %s\n",av_err2str(ret));
        goto __ERROR;

    }
    /// 初始化时间基 用于后边数据组装时候计算时间基
    int64_t *dts_start_time = av_calloc(context->nb_streams, sizeof(int64_t));
    for (int i = 0; i < context->nb_streams; i++) {
        dts_start_time[i] = -1;
    }
    
    int64_t *pts_start_time = av_calloc(context->nb_streams, sizeof(int64_t));
    for (int i = 0; i < context->nb_streams; i++) {
        pts_start_time[i] = -1;
    }

    AVPacket pkt;
    while (av_read_frame(context, &pkt) >= 0) {
        AVStream *instream, *outstream;
        if(dts_start_time[pkt.stream_index] == -1 && pkt.dts > 0) {
            dts_start_time[pkt.stream_index] = pkt.dts;
        }
        if (pts_start_time[pkt.stream_index] == -1 && pkt.pts > 0) {
            pts_start_time[pkt.stream_index] = pkt.pts;
        }
        
        if (stream_map[pkt.stream_index] < 0) {
            av_packet_unref(&pkt);
            continue;
        }
        /// 音频的pts和dts都是一样的 对于视频来说 pts时间一定是大于dts时间的
        pkt.pts = pkt.pts - pts_start_time[pkt.stream_index];
        pkt.dts = pkt.dts - dts_start_time[pkt.stream_index];
//        if (pkt.dts > pkt.pts) {  我做实验加上这一句 视频会抖动不顺滑pts (16117453) < dts (16123453) in stream 0
//            pkt.pts = pkt.dts;
//        }
        instream = context->streams[pkt.stream_index];
        if (av_q2d(instream->time_base) * pkt.pts > endTime) {
            av_log(NULL, AV_LOG_DEBUG, "out of end time\n");
            break;
        }
        
        pkt.stream_index = stream_map[pkt.stream_index];
        outstream = o_context->streams[pkt.stream_index];
        av_packet_rescale_ts(&pkt, instream->time_base, outstream->time_base);
        pkt.pos = -1;
        av_interleaved_write_frame(o_context, &pkt);
        av_packet_unref(&pkt);
    }
    //9.写多媒体文件尾到文件中
    av_write_trailer(o_context);
    //10.将申请的资源释放掉

    
__ERROR:
    
    
    if (context != NULL) {
        avformat_close_input(&context);
        context = NULL;
    }
    
    if (o_context->pb != NULL) {
        avio_close(o_context->pb);
    }

    if (o_context != NULL) {
        avformat_free_context(o_context);
        o_context = NULL;
    }
    if (stream_map) {
        av_free(stream_map);
    }
    
    if (dts_start_time != NULL) {
        av_free(dts_start_time);
    }
    
    if (pts_start_time != NULL) {
        av_free(pts_start_time);
    }
    
}

音视频裁剪demo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值