cffmpeglibavlibavcodecflac

Libav* encoding to FLAC results in MD5 Signature Mismatch


I am trying to learn how to use the FFmpeg libav* libraries but have encountered an issue when encoding to FLAC audio.

Running FFmpeg 5.1.7

I have copied the transcoding.c example from https://www.ffmpeg.org/doxygen/5.1/transcoding_8c-example.html, but made a slight modification in open_output_file() , where I change line 151 from:

encoder = avcodec_find_encoder(dec_ctx->codec_id); 

to:

encoder = avcodec_find_encoder(AV_CODEC_ID_FLAC); 

Otherwise, I would get the error:

Invalid audio stream. Exactly one FLAC audio stream is required.

I ran this to convert an MP3 file to a FLAC file, but it wouldn't be played by VLC. The ffplay command would play it just fine though, and sounds just the same as the source file. I then ran it with the flac -t and flac -a command, and would get the error:

ERROR, MD5 signature mismatch

When I convert the file using just the regular ffmpeg command instead, the resulting output file does not have the MD5 signature mismatch.

I have also tried:

Nothing seems to resolve the issue.

Question: What might be causing the MD5 signature mismatch error?


Example that reproduces the error when converting S16 WAV to FLAC:

transcode.c:

#include <libavcodec/avcodec.h>
#include <libavcodec/codec.h>
#include <libavcodec/codec_id.h>
#include <libavcodec/codec_par.h>
#include <libavcodec/packet.h>
#include <libavformat/avformat.h>
#include <libavutil/frame.h>
#include <libavutil/log.h>
#include <libavutil/samplefmt.h>
#include <libavutil/channel_layout.h>


int ret;

int main(int argc, char **argv) {
    int error_code = 0;
    
    if (argc != 3) {
        av_log(NULL, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);
        return 1;
    }
    
    const char *in_file = argv[1];
    const char *out_file = argv[2];
    
    AVFormatContext *decoder_format_context = avformat_alloc_context();
    AVFormatContext *encoder_format_context = avformat_alloc_context();
    AVStream *input_stream, *output_stream;
    const AVCodec *decoder_codec, *encoder_codec;
    AVCodecContext *decoder_codec_context, *encoder_codec_context;
    AVFrame *decoded_frame;
    AVPacket *input_packet, *output_packet;
    
    ret = avformat_open_input(&decoder_format_context, in_file, NULL, NULL);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to open input file \"%s\", error code %d\n", in_file, ret);
        error_code = 1;
        goto end;
    }
    
    ret = avformat_alloc_output_context2(&encoder_format_context, NULL, NULL, out_file);
    if (!encoder_format_context) {
        av_log(NULL, AV_LOG_ERROR, "Failed to allocate encoder format context, error code %d\n", ret);
        error_code = 1;
        goto end;
    }
    
    av_dump_format(decoder_format_context, 0, in_file, 0);
    
    input_stream = decoder_format_context->streams[0];
    
    decoder_codec = avcodec_find_decoder(input_stream->codecpar->codec_id);
    decoder_codec_context = avcodec_alloc_context3(decoder_codec);
    avcodec_parameters_to_context(decoder_codec_context, input_stream->codecpar);
    avcodec_open2(decoder_codec_context, decoder_codec, NULL);
    
    
    encoder_codec = avcodec_find_encoder(AV_CODEC_ID_FLAC);
    encoder_codec_context = avcodec_alloc_context3(encoder_codec);
    
    output_stream = avformat_new_stream(encoder_format_context, NULL);
    if (!output_stream) {
        av_log(NULL, AV_LOG_ERROR, "Failed to create output stream");
        error_code = 1;
        goto end2;
    }
    
    encoder_codec_context->sample_fmt = AV_SAMPLE_FMT_S16;
    encoder_codec_context->bits_per_raw_sample = 16;
    
    encoder_codec_context->sample_rate = input_stream->codecpar->sample_rate;
    encoder_codec_context->time_base = input_stream->time_base;
    
    av_channel_layout_copy(&encoder_codec_context->ch_layout, &input_stream->codecpar->ch_layout);
    
    if (encoder_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
        encoder_codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    }
    
    avcodec_open2(encoder_codec_context, encoder_codec, NULL);
    avcodec_parameters_from_context(output_stream->codecpar, encoder_codec_context);
    
    av_dump_format(encoder_format_context, 0, out_file, 1);
    
    ret = avio_open(&encoder_format_context->pb, out_file, AVIO_FLAG_WRITE);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Failed to open output file, error code %d\n", ret);
        error_code = 1;
        goto end2;
    }
    
    ret = avformat_write_header(encoder_format_context, NULL);
    if (ret != AVSTREAM_INIT_IN_WRITE_HEADER && ret != AVSTREAM_INIT_IN_INIT_OUTPUT) {
        av_log(NULL, AV_LOG_ERROR, "Failed to write output file header, error code %d\n", ret);
        error_code = 1;
        goto end2;
    }
    
    decoded_frame = av_frame_alloc();
    input_packet = av_packet_alloc();
    output_packet = av_packet_alloc();
    
    while(av_read_frame(decoder_format_context, input_packet) >= 0) {
        ret = avcodec_send_packet(decoder_codec_context, input_packet);
        
        // For all frames in input packet
        while (ret >= 0) {
            ret = avcodec_receive_frame(decoder_codec_context, decoded_frame);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                av_frame_unref(decoded_frame);
                break;
            } else if (ret < 0) {
                av_log(NULL, AV_LOG_ERROR, "Error receiving frame, error code %d\n", ret);
                av_frame_unref(decoded_frame);
                av_packet_unref(input_packet);
                error_code = 1;
                goto end3;
            }
            
            int ret2 = avcodec_send_frame(encoder_codec_context, decoded_frame);
            
            // For all output packets from frame
            while (ret2 >= 0) {
                ret2 = avcodec_receive_packet(encoder_codec_context, output_packet);
                if (ret2 == AVERROR(EAGAIN) || ret2 == AVERROR_EOF) {
                    av_packet_unref(output_packet);
                    break;
                } else if (ret2 < 0) {
                    av_log(NULL, AV_LOG_ERROR, "Error receiving packet, error code %d\n", ret2);
                    av_packet_unref(output_packet);
                    av_frame_unref(decoded_frame);
                    av_packet_unref(input_packet);
                    error_code = 1;
                    goto end3;
                }
                
                output_packet->stream_index = 0;
                
                ret2 = av_interleaved_write_frame(encoder_format_context, output_packet);
                if (ret2 < 0) {
                    av_log(NULL, AV_LOG_ERROR, "Error writing frame, error code %d\n", ret2);
                    av_packet_unref(output_packet);
                    av_frame_unref(decoded_frame);
                    av_packet_unref(input_packet);
                    error_code = 1;
                    goto end3;
                }
                
                av_packet_unref(output_packet);
            }
            
            
            av_frame_unref(decoded_frame);
        }
        
        av_packet_unref(input_packet);
    }
    
    // Flushing encoder
    ret = avcodec_send_frame(encoder_codec_context, NULL);
    while (ret >= 0) {
        ret = avcodec_receive_packet(encoder_codec_context, output_packet);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            av_packet_unref(output_packet);
            break;
        } else if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Error receiving packet, error code %d\n", ret);
            av_packet_unref(output_packet);
            error_code = 1;
            goto end3;
        }
        
        output_packet->stream_index = 0;
        
        ret = av_interleaved_write_frame(encoder_format_context, output_packet);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Error writing frame, error code %d\n", ret);
            av_packet_unref(output_packet);
            error_code = 1;
            goto end3;
        }
        
        av_packet_unref(output_packet);
    }
    
    ret = av_write_trailer(encoder_format_context);
    if (ret != AVSTREAM_INIT_IN_WRITE_HEADER && ret != AVSTREAM_INIT_IN_INIT_OUTPUT) {
        av_log(NULL, AV_LOG_ERROR, "Failed to write output file trailer, error code %d\n", ret);
        error_code = 1;
        goto end3;
    }
    
end3:
    av_frame_free(&decoded_frame);
    av_packet_free(&input_packet);
    av_packet_free(&output_packet);
    
end2:
    avcodec_free_context(&decoder_codec_context);
    avcodec_free_context(&encoder_codec_context);
    
end:
    avformat_free_context(decoder_format_context);
    avformat_free_context(encoder_format_context);
    
    return error_code;
}

Compiled with:

gcc transcode.c -lavcodec -lavformat -lavfilter -l avutil -std=c99 -o transcode

Ran with:

./transcode INPUT.wav OUTPUT.flac

Solution

  • example: flac header says 4608/frame, but each decoded_frame gives 4096

    based on samplerate = 44100 and compression_level = 5,
    flacenc.c determined that frame_size = 4608 was optimal for my wav -> flac,
    but you can manually set this to match every decoded_frame->nb_samples (else: resampling needed)
    example: encoder_codec_context->frame_size = 4096; since it was always 4096

    this needs to be set before avcodec_open2(encoder_codec_context, encoder_codec, NULL);
    or else you'd have to edit FlacEncodeContext *s = avctx->priv_data; (can't really)

    since I cannot know the nb_samples beforehand, I'll delay avcodec_open2 until the first decoded_frame, crude workaround

    for more information, s->max_blocksize gets written to the header, and it won't match what the individual flac frames report about their block_size
    https://datatracker.ietf.org/doc/html/rfc9639#name-block-size-bits

    detecting a change of block size during a stream if a decoder did not receive a streaminfo metadata block

    based on this, it might be possible that headers are not needed to play/decode FLAC frames
    https://datatracker.ietf.org/doc/html/rfc9639#appendix-B.1

    why am I talking about block_size instead of MD5 ? Because if you run the latest version of flac CLI, flac git-9547dbc 20250820, you will run into FLAC__STREAM_DECODER_ERROR_STATUS_MISSING_FRAME before reaching MD5 check (and the program exits)
    (this check took into account the header's max_blocksize, and each frame's individual block_size)

    flac git-9547dbc 20250820
    Copyright (C) 2000-2009  Josh Coalson, 2011-2025  Xiph.Org Foundation
    flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are
    welcome to redistribute it under certain conditions.  Type `flac' for details.
    
    OUTPUT.flac: *** Got error code 6:FLAC__STREAM_DECODER_ERROR_STATUS_MISSING_FRAME after processing 1024 samples
    
    
    OUTPUT.flac: ERROR while decoding data
                 state = FLAC__STREAM_DECODER_ABORTED
    

    and if you use transcode_aac.c instead of transcode.c, all you have to do is change AV_CODEC_ID_AAC to AV_CODEC_ID_FLAC, since this example includes <libswresample/swresample.h>:
    https://github.com/FFmpeg/FFmpeg/blob/e096a592cb7531486cb7c3fd5204299c0fab0733/doc/examples/transcode_aac.c


    below is transcode.c "adapted" (with the crude fix)

    #include <libavcodec/avcodec.h>
    #include <libavcodec/codec.h>
    #include <libavcodec/codec_id.h>
    #include <libavcodec/codec_par.h>
    #include <libavcodec/packet.h>
    #include <libavformat/avformat.h>
    #include <libavutil/frame.h>
    #include <libavutil/log.h>
    #include <libavutil/samplefmt.h>
    #include <libavutil/channel_layout.h>
    
    
    int ret;
    
    int main(int argc, char **argv) {
        int error_code = 0;
    
        if (argc != 3) {
            av_log(NULL, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);
            return 1;
        }
    
        const char *in_file = argv[1];
        const char *out_file = argv[2];
    
        AVFormatContext *decoder_format_context = avformat_alloc_context();
        AVFormatContext *encoder_format_context = avformat_alloc_context();
        AVStream *input_stream, *output_stream;
        const AVCodec *decoder_codec, *encoder_codec;
        AVCodecContext *decoder_codec_context, *encoder_codec_context;
        AVFrame *decoded_frame;
        AVPacket *input_packet, *output_packet;
    
        ret = avformat_open_input(&decoder_format_context, in_file, NULL, NULL);
        if (ret < 0) {
            av_log(NULL, AV_LOG_ERROR, "Failed to open input file \"%s\", error code %d\n", in_file, ret);
            error_code = 1;
            goto end;
        }
    
        ret = avformat_alloc_output_context2(&encoder_format_context, NULL, NULL, out_file);
        if (!encoder_format_context) {
            av_log(NULL, AV_LOG_ERROR, "Failed to allocate encoder format context, error code %d\n", ret);
            error_code = 1;
            goto end;
        }
    
        av_dump_format(decoder_format_context, 0, in_file, 0);
    
        input_stream = decoder_format_context->streams[0];
    
        decoder_codec = avcodec_find_decoder(input_stream->codecpar->codec_id);
        decoder_codec_context = avcodec_alloc_context3(decoder_codec);
        avcodec_parameters_to_context(decoder_codec_context, input_stream->codecpar);
        avcodec_open2(decoder_codec_context, decoder_codec, NULL);
    
    
        encoder_codec = avcodec_find_encoder(AV_CODEC_ID_FLAC);
        encoder_codec_context = avcodec_alloc_context3(encoder_codec);
    
        output_stream = avformat_new_stream(encoder_format_context, NULL);
        if (!output_stream) {
            av_log(NULL, AV_LOG_ERROR, "Failed to create output stream");
            error_code = 1;
            goto end2;
        }
    
        encoder_codec_context->sample_fmt = AV_SAMPLE_FMT_S16;
        encoder_codec_context->bits_per_raw_sample = 16;
    
        encoder_codec_context->sample_rate = input_stream->codecpar->sample_rate;
        encoder_codec_context->time_base = input_stream->time_base;
    
        av_channel_layout_copy(&encoder_codec_context->ch_layout, &input_stream->codecpar->ch_layout);
    
        if (encoder_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
            encoder_codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
        }
    
        int first_frame = 1;
    
        decoded_frame = av_frame_alloc();
        input_packet = av_packet_alloc();
        output_packet = av_packet_alloc();
    
        while(av_read_frame(decoder_format_context, input_packet) >= 0) {
            ret = avcodec_send_packet(decoder_codec_context, input_packet);
    
            // For all frames in input packet
            while (ret >= 0) {
                ret = avcodec_receive_frame(decoder_codec_context, decoded_frame);
                if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                    av_frame_unref(decoded_frame);
                    break;
                } else if (ret < 0) {
                    av_log(NULL, AV_LOG_ERROR, "Error receiving frame, error code %d\n", ret);
                    av_frame_unref(decoded_frame);
                    av_packet_unref(input_packet);
                    error_code = 1;
                    goto end3;
                }
    
                if (first_frame) {
                    first_frame = 0;
                    encoder_codec_context->frame_size = decoded_frame->nb_samples;
    
                    avcodec_open2(encoder_codec_context, encoder_codec, NULL);
                    avcodec_parameters_from_context(output_stream->codecpar, encoder_codec_context);
    
                    av_dump_format(encoder_format_context, 0, out_file, 1);
    
                    ret = avio_open(&encoder_format_context->pb, out_file, AVIO_FLAG_WRITE);
                    if (ret < 0) {
                        av_log(NULL, AV_LOG_ERROR, "Failed to open output file, error code %d\n", ret);
                        error_code = 1;
                        goto end2;
                    }
    
                    ret = avformat_write_header(encoder_format_context, NULL);
                    if (ret != AVSTREAM_INIT_IN_WRITE_HEADER && ret != AVSTREAM_INIT_IN_INIT_OUTPUT) {
                        av_log(NULL, AV_LOG_ERROR, "Failed to write output file header, error code %d\n", ret);
                        error_code = 1;
                        goto end2;
                    }
                }
    
                int ret2 = avcodec_send_frame(encoder_codec_context, decoded_frame);
    
                // For all output packets from frame
                while (ret2 >= 0) {
                    ret2 = avcodec_receive_packet(encoder_codec_context, output_packet);
                    if (ret2 == AVERROR(EAGAIN) || ret2 == AVERROR_EOF) {
                        av_packet_unref(output_packet);
                        break;
                    } else if (ret2 < 0) {
                        av_log(NULL, AV_LOG_ERROR, "Error receiving packet, error code %d\n", ret2);
                        av_packet_unref(output_packet);
                        av_frame_unref(decoded_frame);
                        av_packet_unref(input_packet);
                        error_code = 1;
                        goto end3;
                    }
    
                    output_packet->stream_index = 0;
    
                    ret2 = av_interleaved_write_frame(encoder_format_context, output_packet);
                    if (ret2 < 0) {
                        av_log(NULL, AV_LOG_ERROR, "Error writing frame, error code %d\n", ret2);
                        av_packet_unref(output_packet);
                        av_frame_unref(decoded_frame);
                        av_packet_unref(input_packet);
                        error_code = 1;
                        goto end3;
                    }
    
                    av_packet_unref(output_packet);
                }
    
    
                av_frame_unref(decoded_frame);
            }
    
            av_packet_unref(input_packet);
        }
    
        // Flushing encoder
        ret = avcodec_send_frame(encoder_codec_context, NULL);
        while (ret >= 0) {
            ret = avcodec_receive_packet(encoder_codec_context, output_packet);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
                av_packet_unref(output_packet);
                break;
            } else if (ret < 0) {
                av_log(NULL, AV_LOG_ERROR, "Error receiving packet, error code %d\n", ret);
                av_packet_unref(output_packet);
                error_code = 1;
                goto end3;
            }
    
            output_packet->stream_index = 0;
    
            ret = av_interleaved_write_frame(encoder_format_context, output_packet);
            if (ret < 0) {
                av_log(NULL, AV_LOG_ERROR, "Error writing frame, error code %d\n", ret);
                av_packet_unref(output_packet);
                error_code = 1;
                goto end3;
            }
    
            av_packet_unref(output_packet);
        }
    
        ret = av_write_trailer(encoder_format_context);
        if (ret != AVSTREAM_INIT_IN_WRITE_HEADER && ret != AVSTREAM_INIT_IN_INIT_OUTPUT) {
            av_log(NULL, AV_LOG_ERROR, "Failed to write output file trailer, error code %d\n", ret);
            error_code = 1;
            goto end3;
        }
    
    end3:
        av_frame_free(&decoded_frame);
        av_packet_free(&input_packet);
        av_packet_free(&output_packet);
    
    end2:
        avcodec_free_context(&decoder_codec_context);
        avcodec_free_context(&encoder_codec_context);
    
    end:
        avformat_free_context(decoder_format_context);
        avformat_free_context(encoder_format_context);
    
        return error_code;
    }