Javacpp-presets: ffmpeg transcoding copy_context and avio_open JVM crash

Created on 4 Apr 2017  路  3Comments  路  Source: bytedeco/javacpp-presets

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.)

question

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.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);

All 3 comments

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.
Was this page helpful?
0 / 5 - 0 ratings