Ffmpeg抽取音频、视频、格式转换

最近闲着无聊研究了一下ffmpeg,详细过程不说了,主要是上点干货,当然可能研究的不透彻勿喷,谢谢。我的环境是基于QT的,所以有QString字串,QtDebug日志,QMessageBox提示用的,QWidget,首先这些内容都不重要。

QString 转char*:

//因ffmpeg是c风格字符串,所以需要将QString转c风格字符,所但凡看到inTmp.data(),outTmp.data()就是获取c风格字符;
//转换操作如下:
QString in("d:/1.mp4");
QByteArray inTmp;
inTmp.append(in);
const char* in_file = inTmp.data();

直接上货:抽取mp4音频并输出为aac格式,qDebug()理解为cout就可以

//in输入mp4文件如:d:/1.mp4,out输出h264文件:d:/2.aac
void extraAudio(QString in,QString out){
    QByteArray inTmp;
    inTmp.append(in);
    QByteArray outTmp;
    outTmp.append(out);


    //定义上下文
    AVFormatContext *ifmt_ctx = NULL;
    AVFormatContext *ofmt_ctx = NULL;
    AVOutputFormat *out_fmt = NULL;

    //输入流
    AVStream *in_stream = NULL;
    //输出流
    AVStream *out_stream = NULL;

    //存储数据包
    AVPacket packet;

    //需要拷贝的流索引
    int audio_stream_index = -1;

    int err_code;

///打开输入文件//
    err_code = avformat_open_input(&ifmt_ctx,inTmp.data(),NULL,NULL);
    if(err_code < 0){
        avformat_close_input(&ifmt_ctx);
         qDebug()<<"avformat_open_input error: ";
        return;
    }

    if(ifmt_ctx->nb_streams < 2){
         qDebug()<<"nb_streams error: ";
         avformat_close_input(&ifmt_ctx);
        return;
    }



    audio_stream_index = av_find_best_stream(ifmt_ctx,AVMEDIA_TYPE_AUDIO,-1,-1,NULL,0);
    if(audio_stream_index < 0){
        qDebug()<<"寻找最好音频流失败,请检查输入文件!";
        avformat_close_input(&ifmt_ctx);
        return;
    }
    in_stream = ifmt_ctx->streams[audio_stream_index];
    AVCodecParameters *in_parameter = in_stream->codecpar;
///打开输出文件///
    // 输出上下文
    ofmt_ctx = avformat_alloc_context();
    out_fmt = av_guess_format(NULL,outTmp.data(),NULL);
    if(!out_fmt){
        qDebug()<<"avcodec_parameters_copy error:out_fmt ";
        avformat_close_input(&ifmt_ctx);
       avformat_close_input(&ofmt_ctx);
       return ;
    }
    ofmt_ctx->oformat = out_fmt;
    //新建输出流
    out_stream = avformat_new_stream(ofmt_ctx, NULL);
     if(!out_stream){
           qDebug()<<"创建输出流失败! ";
           avformat_close_input(&ifmt_ctx);
          avformat_free_context(ofmt_ctx);
           return;
     }
初始化各种配置//
     // 将参数信息拷贝到输出流中,我们只是抽取音频流,并不做音频处理,所以这里只是Copy
     if((err_code = avcodec_parameters_copy(out_stream->codecpar, in_parameter)) < 0 ){
         avformat_close_input(&ifmt_ctx);
        avformat_free_context(ofmt_ctx);
         qDebug()<<"avcodec_parameters_copy error: ";
         return;
     }

     //初始化AVIOContext,文件操作由它完成
     if((err_code = avio_open(&ofmt_ctx->pb, outTmp.data(), AVIO_FLAG_WRITE)) < 0) {
         qDebug()<<"avio_open error: ";
         avformat_close_input(&ifmt_ctx);
        avformat_free_context(ofmt_ctx);
         return;
     }
     av_init_packet(&packet);
     packet.data = NULL;
     packet.size = 0;

     if (avformat_write_header(ofmt_ctx, NULL) < 0) {
         qDebug()<<"Error occurred when opening output file";
         avformat_close_input(&ifmt_ctx);
        avformat_free_context(ofmt_ctx);
         return;
     }
     while(av_read_frame(ifmt_ctx, &packet) >=0 ){
         if(packet.stream_index == audio_stream_index){
                 //时间基计算,音频pts和dts一致
                 packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
                 //packet.dts = packet.pts;
                 packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, (AVRounding) (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
                 packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
                 packet.pos = -1;
                 packet.stream_index = 0;
                 //将包写到输出媒体文件
                 av_interleaved_write_frame(ofmt_ctx, &packet);
                 //减少引用计数,避免内存泄漏
                 av_packet_unref(&packet);
             }
     }
      av_write_trailer(ofmt_ctx);

     avformat_close_input(&ifmt_ctx);
     avio_close(ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);
}

 

直接上货:抽取mp4音频并输出为h264格式

//in输入mp4文件如:d:/1.mp4,out输出h264文件:d:/2.h264
void extraVideo(QString in,QString out,QWidget* _this){
    QByteArray inTmp;
    inTmp.append(in);
    QByteArray outTmp;
    outTmp.append(out);

    AVFormatContext *ifmt_ctx = NULL,*ofmt_ctx = NULL;
    AVOutputFormat *out_fmt = NULL;

    AVStream *in_stream = NULL,*out_stream = NULL;

    AVPacket packet;

    int video_stream_idx = -1;

    int error_code;
    char* error = {};
    size_t buff_size = 200;
//打开输入
    error_code = avformat_open_input(&ifmt_ctx,inTmp.data(),NULL,NULL);
    if(error_code<0){
        av_strerror(error_code, error, buff_size);
        QString error_str(error);
        QMessageBox::warning(_this,"错误",error_str);
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        return;
    }

    if(ifmt_ctx->nb_streams < 2){
        QMessageBox::warning(_this,"错误","文件异常,无法打开");
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        return;
    }

    video_stream_idx = av_find_best_stream(ifmt_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
    if(video_stream_idx < 0){
        QMessageBox::warning(_this,"错误","未找到视频流");
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        if(ofmt_ctx)
            avformat_free_context(ofmt_ctx);
        return;
    }
    in_stream = ifmt_ctx->streams[video_stream_idx];

    AVCodecParameters *in_codec_parameters = in_stream->codecpar;

//打开输出
    ofmt_ctx = avformat_alloc_context();
    out_fmt = av_guess_format(NULL,outTmp.data(),NULL);

    ofmt_ctx->oformat = out_fmt;

    out_stream = avformat_new_stream(ofmt_ctx,NULL);
    if(!out_stream){
        QMessageBox::warning(_this,"错误","创建新流异常");
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        if(ofmt_ctx)
            avformat_free_context(ofmt_ctx);
        return;
    }

    error_code = avcodec_parameters_copy(out_stream->codecpar,in_codec_parameters);
    if(error_code<0){
        av_strerror(error_code, error, buff_size);
        QString error_str(error);
        QMessageBox::warning(_this,"错误",error_str);
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        if(ofmt_ctx)
            avformat_free_context(ofmt_ctx);
        return;
    }
    if((error_code = avio_open(&ofmt_ctx->pb, outTmp.data(), AVIO_FLAG_WRITE)) < 0) {
        av_strerror(error_code, error, buff_size);
        QString error_str(error);
        QMessageBox::warning(_this,"错误",error_str);
        if(ofmt_ctx->pb)
            avio_close(ofmt_ctx->pb);
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        if(ofmt_ctx)
            avformat_free_context(ofmt_ctx);
        return;
    }

    av_init_packet(&packet);
    packet.data = NULL;
    packet.size = 0;

    if ((error_code = avformat_write_header(ofmt_ctx, NULL)) < 0) {
        av_strerror(error_code, error, buff_size);
        QString error_str(error);
        QMessageBox::warning(_this,"错误",error_str);
        if(ofmt_ctx->pb)
            avio_close(ofmt_ctx->pb);
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        if(ofmt_ctx)
            avformat_free_context(ofmt_ctx);
        return;
    }
    while(av_read_frame(ifmt_ctx, &packet) >=0 ){
        if(packet.stream_index == video_stream_idx){
            //时间基计算,音频pts和dts一致
            packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
            //packet.dts = packet.pts;
            packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, (AVRounding) (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
            packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
            packet.pos = -1;
            packet.stream_index = 0;
            av_interleaved_write_frame(ofmt_ctx, &packet);
        }
        av_packet_unref(&packet);
    }
    av_write_trailer(ofmt_ctx);

    if(ofmt_ctx->pb)
        avio_close(ofmt_ctx->pb);
    if(ifmt_ctx)
        avformat_close_input(&ifmt_ctx);
    if(ofmt_ctx)
        avformat_free_context(ofmt_ctx);
}

 

格式转换:这里需要说明一下 因为QMessageBox需要父窗口所以这里再方法处加了一个QWidget* _this,分别将QWidget* _this,QMessageBox去掉,将qDebug换成cout,就是一个普通的函数


void converson_format(QString in,QString extend,QWidget* _this){
    QByteArray inTmp;
    inTmp.append(in);
    QByteArray outTmp;
    outTmp.append(extend);

    AVFormatContext *ifmt_ctx = NULL,*ofmt_ctx = NULL;
    AVOutputFormat *ofmt = NULL;
    AVPacket pkt;

    int error_code;
    char* error;
    int buff_size = 200;
    int *stream_idx_map;
    int stream_length = 0;
    int idx = 0;

    error_code = avformat_open_input(&ifmt_ctx,inTmp.data(),NULL,NULL);
    if(error_code < 0){
        av_strerror(error_code, error, buff_size);
        QString error_str(error);
        QMessageBox::warning(_this,"错误",error_str);
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
    }

    error_code = avformat_find_stream_info(ifmt_ctx,NULL);
    if(error_code<0){
        av_strerror(error_code, error, buff_size);
        QString error_str(error);
        QMessageBox::warning(_this,"错误",error_str);
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
    }

    error_code = avformat_alloc_output_context2(&ofmt_ctx,NULL,NULL,outTmp.data());
    if(error_code < 0){
        av_strerror(error_code, error, buff_size);
        QString error_str(error);
        QMessageBox::warning(_this,"错误",error_str);
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        if(ofmt_ctx)
            avformat_free_context(ofmt_ctx);
    }
    stream_length = ifmt_ctx->nb_streams;
    stream_idx_map = (int*)av_mallocz_array(stream_length,sizeof(*stream_idx_map));
    if(!stream_idx_map){
        QMessageBox::warning(_this,"错误","系统异常");
        if(ifmt_ctx)
            avformat_close_input(&ifmt_ctx);
        if(ofmt_ctx)
            avformat_free_context(ofmt_ctx);
        if(stream_idx_map)
            av_freep(stream_idx_map);
        return;
    }
//5
    ofmt = ofmt_ctx->oformat;
    //qDebug() <<"stream_length for";
    for(int i=0;i<stream_length;i++){
        AVStream *out_stream = NULL,*in_stream = NULL;
        in_stream = ifmt_ctx->streams[i];
        AVCodecParameters *in_codecParameters = in_stream->codecpar;
        if (in_codecParameters->codec_type != AVMEDIA_TYPE_AUDIO &&
                    in_codecParameters->codec_type != AVMEDIA_TYPE_VIDEO &&
                    in_codecParameters->codec_type != AVMEDIA_TYPE_SUBTITLE) {
                    stream_idx_map[i] = -1;
                    continue;
                }

        stream_idx_map[i] = idx++;

        out_stream = avformat_new_stream(ofmt_ctx,NULL);
        if (!out_stream) {
                    avformat_free_context(ofmt_ctx);
                    avformat_close_input(&ifmt_ctx);
                    av_freep(&stream_idx_map);
          QMessageBox::warning(_this,"错误","avformat_new_stream");
          return;
        }
        //qDebug() <<"stream_idx_map:"<<stream_idx_map;
       error_code =  avcodec_parameters_copy(out_stream->codecpar, in_codecParameters);
       if(error_code < 0 ){
           avformat_free_context(ofmt_ctx);
           avformat_close_input(&ifmt_ctx);
           av_freep(&stream_idx_map);
           QMessageBox::warning(_this,"错误","avcodec_parameters_copy");
           return;
       }
       out_stream->codecpar->codec_tag = 0;
    }


    if (!(ofmt->flags & AVFMT_NOFILE)) {
        if (avio_open(&ofmt_ctx->pb, outTmp.data(), AVIO_FLAG_WRITE) < 0) {
            avio_closep(&ofmt_ctx->pb);
            avformat_free_context(ofmt_ctx);
            avformat_close_input(&ifmt_ctx);
            av_freep(&stream_idx_map);
            QMessageBox::warning(_this,"错误","avio_open");
            return;
        }
    }
//qDebug() <<"avformat_write_header";
    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        avio_closep(&ofmt_ctx->pb);
        avformat_free_context(ofmt_ctx);
        avformat_close_input(&ifmt_ctx);
        av_freep(&stream_idx_map);
        QMessageBox::warning(_this,"错误","avformat_write_header");
        return;
    }

    av_init_packet(&pkt);
    //av_dump_format(ofmt_ctx,NULL,outTmp.data(),NULL);
    //qDebug() <<"while";
    while (true){
        AVStream* in_stream, * out_stream;
        //循环读取每一帧数据
        if (av_read_frame(ifmt_ctx, &pkt) < 0) //读取完后退出循环
            break;
        in_stream = ifmt_ctx->streams[pkt.stream_index];
        if (pkt.stream_index >= stream_length ||
            stream_idx_map[pkt.stream_index] < 0) {
            av_packet_unref(&pkt);
            continue;
        }

        pkt.stream_index = stream_idx_map[pkt.stream_index]; // 按照输出流的index给pkt重新编号
        out_stream = ofmt_ctx->streams[pkt.stream_index]; // 根据pkt的stream_index获取对应的输出流

        // 对pts、dts、duration进行时间基转换,不同格式时间基都不一样,不转换会导致音视频同步问题
        pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base,(AVRounding) (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding) (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
        pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
        pkt.pos = -1;

        // 将处理好的pkt写入输出文件
        av_interleaved_write_frame(ofmt_ctx, &pkt);

        av_packet_unref(&pkt);
    }
    av_write_trailer(ofmt_ctx);

    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
            avio_closep(&ofmt_ctx->pb);

        av_freep(&stream_idx_map);
        avformat_free_context(ofmt_ctx);
        avformat_close_input(&ifmt_ctx);
}

源码地址:https://download.csdn.net/download/tiyager/12716353

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值