我们可以用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;
}