I have posted this on StackOverflow already: http://stackoverflow.com/questions/42607004/avio-open-crashes-avcodec-copy-context-doesnt-work
I'm trying to port this example https://ffmpeg.org/doxygen/trunk/doc_2examples_2remuxing_8c-example.html to Java.
I have this so far:
av_register_all();
AVFormatContext inFmtCtx = new AVFormatContext(null);
if (avformat_open_input(inFmtCtx, "file.ts", null, null) != 0)
throw new Exception("Could not open input file");
if (avformat_find_stream_info(inFmtCtx, (PointerPointer)null) != 0)
throw new Exception("Failed to retrieve input stream information");
av_dump_format(inFmtCtx, 0, "file.ts", 0);
AVFormatContext outFmtCtx = new AVFormatContext(null);
avformat_alloc_output_context2(outFmtCtx, null, null, "file2.ts");
AVOutputFormat outFmt = outFmtCtx.oformat();
for (int i = 0; i < inFmtCtx.nb_streams(); i++) {
AVStream inStr = inFmtCtx.streams(i);
AVStream outStr = avformat_new_stream(outFmtCtx, inStr.codec().codec());
if (outStr.isNull()) throw new Exception("Failed allocating output stream");
if (avcodec_copy_context(outStr.codec(), inStr.codec()) != 0)
throw new Exception("Failed to copy context from input to"+
" output stream codec context");
if ((outFmtCtx.oformat().flags() & AVFMT_GLOBALHEADER) != 0)
outStr.codec().flags(outStr.codec().flags() | CODEC_FLAG_GLOBAL_HEADER);
}
av_dump_format(outFmtCtx, 0, "file2.ts", 1);
if ((outFmt.flags() & AVFMT_NOFILE) == 0)
if (avio_open(outFmtCtx.pb(), "file2.ts", AVIO_FLAG_WRITE) != 0)
throw new Exception("Could not open output file");
The problem is, that the avio_open call causes the JVM to crash with an access violation.
Stack: [0x00000000037e0000,0x00000000038e0000], sp=0x00000000038df6d0, free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [avformat-57.dll+0x28877]
C [jniavformat.dll+0x383cb]
C 0x0000000003bcdfcc
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j org.bytedeco.javacpp.avformat.avio_open(Lorg/bytedeco/javacpp/avformat$AVIOContext;Ljava/lang/String;I)I+0
j TestRemuxer.main([Ljava/lang/String;)V+226
v ~StubRoutines::call_stub
This is the output (without the crash message):
Input #0, mpegts, from 'file.ts':
Duration: 00:00:17.60, start: 0.000000, bitrate: 1016 kb/s
Program 1
Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(progressive), 636x480 [SAR 900:901 DAR 45:34], 23.98 fps, 23.98 tbr, 90k tbn, 47.95 tbc
Stream #0:1[0x101]: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 194 kb/s
Output #0, mpegts, to 'file2.ts':
Stream #0:0: Unknown: none
Stream #0:1: Unknown: none
I suspect the cause of the access violation is the same as what causes the output streams to be unknown. However, if I pause debugging on the second av_dump_format call, I can use Evaluate to verify, that the codecs were copied properly. (I checked the FFmpeg sources, and I know that a stream is dumped as Unknown, if and only if its codec_type is set to an invalid value, however the value is correctly 0 for the first stream and 1 for the second stream.)
Because of the way JavaCPP tries to deal with how the C language works, we're not able to set the AVIOContext.pb field that way. We need to do it this way, as per https://github.com/bytedeco/javacv/blob/master/src/main/java/org/bytedeco/javacv/FFmpegFrameRecorder.java#L796 :
AVIOContext pb = new AVIOContext(null);
avio_open(pb, ...);
outFmtCtx.pb(pb);
That does fix the crash, thank you.
Is there a similar problem with shown by the av_dump_format call or is Stream: Unknown an expected output?
This is the new output:
Input #0, mpegts, from 'file1.ts':
Duration: 00:00:17.60, start: 0.000000, bitrate: 1016 kb/s
Program 1
Stream #0:0[0x100]: Video: h264 (High) ([27][0][0][0] / 0x001B), yuv420p(progressive), 636x480 [SAR 900:901 DAR 45:34], 23.98 fps, 23.98 tbr, 90k tbn, 47.95 tbc
Stream #0:1[0x101]: Audio: aac (LC) ([15][0][0][0] / 0x000F), 44100 Hz, stereo, fltp, 194 kb/s
Output #0, mpegts, to 'file2.ts':
Stream #0:0: Unknown: none
Stream #0:1: Unknown: none
[mpegts @ 0000000029ad5800] Using AVStream.codec.time_base as a timebase hint to the muxer is deprecated. Set AVStream.time_base instead.
[mpegts @ 0000000029ad5800] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
[mpegts @ 0000000029ad5800] Using AVStream.codec.time_base as a timebase hint to the muxer is deprecated. Set AVStream.time_base instead.
Ignoring attempt to set invalid timebase 1/0 for st:1
[mpegts @ 0000000029ad5800] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
Most helpful comment
Because of the way JavaCPP tries to deal with how the C language works, we're not able to set the
AVIOContext.pbfield that way. We need to do it this way, as per https://github.com/bytedeco/javacv/blob/master/src/main/java/org/bytedeco/javacv/FFmpegFrameRecorder.java#L796 :