Page 1 of 1

Problem with AAC Encoder after Updating to 4.0.2

Posted: Fri Aug 17, 2018 11:41 am
by SteveH
Hi,

I work with a system that has been using libav version 2.8 for several years, and for various reasons I'm trying to update to the 4.0.2 release. One of the things my system needs to do is encode audio to AAC, and I'm struggling to get it to work. My code was using methods that have been removed now (avcodec_encode_audio), so I followed the example shipped with the source (avcodec_send_frame/avcodec_receive_packet) and got everything building. The encode methods are not returning any errors, but when I pass that audio to another part of my software, the decode is failing constantly.

I figured I was probably not following the example properly, so I built and ran that, and it worked fine as shipped. I then changed it to encode to AAC, and I found that while it still wrote out a file, I couldn't play that file in VLC. There must be something that the example is missing that needs to happen for the AAC encoder to work, but I can't find anything. I'd very much appreciate any guidance that anyone can offer!

Here's the modified example code I'm using to try and write out the AAC encoded audio. I've put a comment saying MODIFIED on each line that I've changed from the original.

Code: Select all

int main(int argc, char **argv)
{
    const char *filename;
    const AVCodec *codec;
    AVCodecContext *c= NULL;
    AVFrame *frame;
    AVPacket *pkt;
    int i, j, k, ret;
    FILE *f;
    float *samples; // MODIFIED, was uint16_t*
    float t, tincr;

    if (argc <= 1) {
        fprintf(stderr, "Usage: %s <output file>\n", argv[0]);
        return 0;
    }
    filename = argv[1];

    /* find the MP2 encoder */
    codec = avcodec_find_encoder(AV_CODEC_ID_AAC);	// MODIFIED, was AV_CODEC_ID_MP2
    if (!codec) {
        fprintf(stderr, "Codec not found\n");
        exit(1);
    }

    c = avcodec_alloc_context3(codec);
    if (!c) {
        fprintf(stderr, "Could not allocate audio codec context\n");
        exit(1);
    }

    /* put sample parameters */
    c->bit_rate = 64000;

    /* check that the encoder supports s16 pcm input */
    c->sample_fmt = AV_SAMPLE_FMT_FLTP;	// MODIFIED, was AV_SAMPLE_FMT_S16
    if (!check_sample_fmt(codec, c->sample_fmt)) {
        fprintf(stderr, "Encoder does not support sample format %s",
                av_get_sample_fmt_name(c->sample_fmt));
        exit(1);
    }

    /* select other audio parameters supported by the encoder */
    c->sample_rate    = select_sample_rate(codec);
    c->channel_layout = select_channel_layout(codec);
    c->channels       = av_get_channel_layout_nb_channels(c->channel_layout);

    /* open it */
    if (avcodec_open2(c, codec, NULL) < 0) {
        fprintf(stderr, "Could not open codec\n");
        exit(1);
    }

    f = fopen(filename, "wb");
    if (!f) {
        fprintf(stderr, "Could not open %s\n", filename);
        exit(1);
    }

    /* packet for holding encoded output */
    pkt = av_packet_alloc();
    if (!pkt) {
        fprintf(stderr, "could not allocate the packet\n");
        exit(1);
    }

    /* frame containing input raw audio */
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Could not allocate audio frame\n");
        exit(1);
    }

    frame->nb_samples     = c->frame_size;
    frame->format         = c->sample_fmt;
    frame->channel_layout = c->channel_layout;

    /* allocate the data buffers */
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0) {
        fprintf(stderr, "Could not allocate audio data buffers\n");
        exit(1);
    }

    /* encode a single tone sound */
    t = 0;
    tincr = 2 * M_PI * 440.0 / c->sample_rate;
    for (i = 0; i < 200; i++) {
        /* make sure the frame is writable -- makes a copy if the encoder
         * kept a reference internally */
        ret = av_frame_make_writable(frame);
        if (ret < 0)
            exit(1);
        samples = (float*)frame->data[0];	// MODIFIED, was uint16_t*

        for (j = 0; j < c->frame_size; j++) {
            samples[j] = sin(t);	// MODIFIED, was samples[2*j] = (int)(sin(t) * 10000);

            for (k = 1; k < c->channels; k++)
                ((float*)frame->data[k])[j] = samples[j];	// MODIFIED, was samples[2*j + k] = samples[2*j];
            t += tincr;
        }
        encode(c, frame, pkt, f);
    }

    /* flush the encoder */
    encode(c, NULL, pkt, f);

    fclose(f);

    av_frame_free(&frame);
    av_packet_free(&pkt);
    avcodec_free_context(&c);

    return 0;
}