ffmpegstatic-librariescodecavcodec

avcodec_open only works with uncompressed format


Context: I have a file called libffmpeg.so, that I took from the APK of an Android application that is using FFMPEG to encode and decode files between several Codecs. Thus, I take for grant that this is compiled with encoding options enable and that this .so file is containing all the codecs somewhere. This file is compiled for ARM (what we call ARMEABI profile on Android).

I also have a very complete class with interops to call API from ffmpeg. Whatever is the origin of this static library, all call responses are good and most endpoints exist. If not I add them or fix deprecated one.

When I want to create an ffmpeg Encoder, the returned encoder is correct.

var thisIsSuccessful = avcodec_find_encoder(myAVCodec.id);

Now, I have a problem with Codecs. The problem is that - let's say that out of curiosity - I iterate through the list of all the codecs to see which one I'm able to open with the avcodec_open call ...

        AVCodec codec;

        var res = FFmpeg.av_codec_next(&codec);
        while((res = FFmpeg.av_codec_next(res)) != null)
        {
            var name = res->longname;


            AVCodec* encoder = FFmpeg.avcodec_find_encoder(res->id);
            if (encoder != null) {
                AVCodecContext c = new AVCodecContext ();       

                /* put sample parameters */
                c.bit_rate = 64000;
                c.sample_rate = 22050;
                c.channels = 1;

                if (FFmpeg.avcodec_open (ref c, encoder) >= 0) {
                    System.Diagnostics.Debug.WriteLine ("[YES] - " + name);
                }
            } else {
                System.Diagnostics.Debug.WriteLine ("[NO ] - " + name);
            }
        }

... then only uncompressed codecs are working. (YUV, FFmpeg Video 1, etc)

My hypothesis are these one:

I'm really curious about why only a minimum set of uncompressed codecs are returned?

[EDIT]

@ronald-s-bultje answer led me to read AVCodecContext API description, and there are a lot of mendatory fileds with "MUST be set by user" when used on an encoder. Setting a value for these parameters on AVCodecContext made most of the nice codecs available:

c.time_base = new AVRational (); // Output framerate. Here, 30fps
c.time_base.num = 1;
c.time_base.den = 30;
c.me_method = 1; // Motion-estimation mode on compression -> 1 is none
c.width = 640; // Source width
c.height = 480; // Source height
c.gop_size = 30; // Used by h264. Just here for test purposes.
c.bit_rate = c.width * c.height * 4; // Randomly set to that...
c.pix_fmt = FFmpegSharp.Interop.Util.PixelFormat.PIX_FMT_YUV420P; // Source pixel format

Solution

  • The av_open_codec calls is acting depending on the properties of the AVCodecContext I've referenced in the call.

    It's basically that. I mean, for the video encoders, you didn't even set width/height, so most encoders really can't be expected to do anything useful like this, and are right to error right out.

    You can set default parameters using e.g. avcodec_get_context_defaults3(), which should help you a long way to getting some useful settings in the AVCodecContext. After that, set typical ones like width/height/pix_fmt to the ones describing your input format (if you want to do audio encoding - which is actually surprisingly unclear from your question, you'll need to set some different ones like sample_fmt/sample_rate/channels, but same idea). And then you should be relatively good to go.