利用FFmpeg完成 mp4格式转avi格式

我们可以用ffmpeg来完成一些很有用的功能。这篇文章就来说说,怎样用ffmpeg来完成视频格式的转换。

首先在我们搭建好ffmpeg环境的基础上,如下链接所示

https://blog.csdn.net/laibowon/article/details/103746594

我们需要把输入的MP4视频文件转换为.avi格式的文件

主要是有两方面的问题:1.如何将输入文件传入给ffmpeg

2.如何调用ffmpeg进行格式转换

首先是第一个问题,在取得读写磁盘的权限以后,c++可以通过JNIEnv取得java层传递过来的绝对路径。

const char *in_filename;
in_filename =  env->GetStringUTFChars(str, &b);

通过传入两个地址,写入地址和写出地址,来告诉C层写入路径和输出路径分别是什么。

然后是第二步骤

需要引入的头文件有

jint _tmain(JNIEnv *env, int argc,jstring str,jstring output){

    const char* testfilepath =env->GetStringUTFChars(str,0);

    if(testfilepath == NULL){
        return -1;
    }
    env->ReleaseStringUTFChars(str, testfilepath);

    AVOutputFormat * ofmt = NULL;
    AVBitStreamFilterContext * vbsf = NULL;
    //定义输入、输出AVFormatContext
    AVFormatContext * ifmt_ctx = NULL, * ofmt_ctx = NULL;
    AVPacket pkt;
    const char *in_filename, *out_filename;
    int ret,i;
    int frame_index = 0;
    jboolean b=false;

    in_filename =  env->GetStringUTFChars(str, &b);
    //in_filename = "C:\\tst\\test.mp4";//input file URL
    int len = strlen(in_filename);

    out_filename = env->GetStringUTFChars(output, &b);
    av_register_all();
    //输入
    if((ret = avformat_open_input(&ifmt_ctx, in_filename,0,0)) < 0 )
    //打开媒体文件
    {
        char *buf;
        printf("Could not open input file.");
        goto end;
    }
    if((ret = avformat_find_stream_info(ifmt_ctx, 0 ))< 0 ){
        printf("Failed to go retrieve input stream information");
        goto end;
    }
    //MP4中使用的是H264编码,而H264编码有两种封装格式
    //一种是annexb模式,它是传统模式,有startcode,SPS和PPS在Element Stream中;
    //另一种是MP4模式,一般mp4、MKV、AVI都没有startcode,SPS和PPS以及其他信息被封装在容器中
    //每一帧前面都是这一帧的长度值,很多解码器只支持annexb模式,因此需要对MP4模式做转换
    //在ffmpeg中用h264_+mp4toannexb_fllter可以进行模式转换;使用-bsf h264_mp4toannexb就可以实现转换

    vbsf  = av_bitstream_filter_init("h264_mp4toannexb");
    av_dump_format(ifmt_ctx, 0, in_filename, 0);
    //初始化输出视频码流的AVFormatContext
    avformat_alloc_output_context2(&ofmt_ctx, NULL,NULL,out_filename);
    if (!ofmt_ctx) {
        printf("Could not create output contrxt\n");
        ret = AVERROR_UNKNOWN;
        goto end;
    }
    ofmt = ofmt_ctx -> oformat;

    for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
        //通过输入的AVStream创建输出的AVStream
        AVStream *in_stream = ifmt_ctx->streams[i];
        AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
        if (!out_stream) {
            printf("Failed allocating out stream\n");
            ret = AVERROR_UNKNOWN;
            goto end;
        }
        //复制AVCodecContext的设置属性
        if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) {
            printf("Faield to copy context from input to output \n");
            goto end;
        }


        out_stream->codec->codec_tag = 0;
        if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
            out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
    }

    //输出信息
    av_dump_format(ofmt_ctx, 0, out_filename, 1);

    if (!(ofmt->flags & AVFMT_NOFILE)) {
        ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            printf("Could not open output file'%s'", out_filename);
            goto end;
        }
    }
    //写文件头
    if (avformat_write_header(ofmt_ctx, NULL) < 0) {
        printf("Error occureed when opening output file\n");
        goto end;
    }

    while (1) {
        AVStream *in_stream, *out_stream;
        //       得到一个AVPacket
        ret = av_read_frame(ifmt_ctx, &pkt);
        if (ret < 0) {
            break;
        }
        in_stream = ifmt_ctx->streams[pkt.stream_index];
        out_stream = ofmt_ctx->streams[pkt.stream_index];

        // 转换PTS/DTS
        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;

        if (pkt.stream_index == 0) {
            AVPacket fpkt = pkt;
            int a = av_bitstream_filter_filter(vbsf, out_stream->codec, NULL, &fpkt.data,
                                               &fpkt.size,
                                               pkt.data, pkt.size, pkt.flags & AV_PKT_FLAG_KEY
            );
            pkt.data = fpkt.data;
            pkt.size = fpkt.size;
        }

        //写Avpacket
        if (av_write_frame(ofmt_ctx, &pkt) < 0) {
            printf("Eroor mixing packet\n");
            break;
        }

        printf("Write %8d frames to output file\n", frame_index);
        av_packet_unref(&pkt);
        frame_index++;
    }

    av_write_trailer(ofmt_ctx);

    printf("succcess");
    end:
    avformat_close_input(&ifmt_ctx);
    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) {
        avio_close(ofmt_ctx->pb);
    };

    avformat_free_context(ofmt_ctx);
    //clos out put

    printf("end");
    return 0;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值