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:
Converting from a WAV file instead (same issue)
Manually setting encoder codec parameters (sample format S16, S32, 24-bit, etc.)
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
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;
}