[Libav-user] Can't convert raw audio to mp3
daytooner
daytooner at gmail.com
Thu Aug 21 19:17:52 CEST 2014
I have a raw audio file (s16, 44100, 2 channels). FWIW, the file was
generated from a FLAC file, and I have tested it in audacity and it is fine.
I am now trying to convert that to an mp3 file. The code I am using follows.
(Note that I have removed a lot of insignificant lines, such as #includes).
/************************* begin code ********************************
flac2mp3.cpp
*/
<snip>
# many includes/macros #
<snip>
typedef unsigned char BYTE;
static AVFormatContext *encfmt_ctx = NULL;
static AVCodecContext *audio_enc_ctx;
static AVStream *audio_encstream = NULL;
static int audio_frame_deccount = 0, audio_frame_enccount = 0;
static SwrContext *swr;
#define MP3_SAMPLE_FMT AV_SAMPLE_FMT_S16P
#define MP3_BITRATE 256000
#define MP3_SAMPLE_RATE 44100
#define FLAC_SAMPLE_FMT AV_SAMPLE_FMT_S16
#define FLAC_BITRATE 256000
#define FLAC_SAMPLE_RATE 44100
#define SAMPLES_TO_CB(stc, cs)
(av_get_bytes_per_sample(stc->codec->sample_fmt) * stc->codec->channels *
cs)
#define SAMPLES_FROM_CB(stc, cb)
cb/(av_get_bytes_per_sample(stc->codec->sample_fmt) * stc->codec->channels)
#define BYTES_TO_READ 4594
void flush_audio()
{
int ret;
int got_frame;
AVPacket epkt = {0};
av_init_packet(&epkt);
do
{
ret = avcodec_encode_audio2(audio_enc_ctx, &epkt, NULL, &got_frame);
av_assert0(ret >= 0);
}while(got_frame);
}
/*
* encode a buffer of cbdec bytes of raw audio
*/
bool encode_buffer(BYTE* buff, int cbdec)
{
int ret;
int got_frame;
int line_size;
BYTE* ob[2];
const BYTE* ib[2];
AVPacket epkt = {0};
AVFrame *eframe = avcodec_alloc_frame();
av_init_packet(&epkt);
/*
* convert audio
*/
long int c_insamples = cbdec/(4);
// long int delay = swr_get_delay(swr,(long int) 44100);
long int delay = 0;
int c_outsamples = av_rescale_rnd(delay + c_insamples,
(long int) MP3_SAMPLE_RATE,
(long int) FLAC_SAMPLE_RATE, AV_ROUND_UP);
ret = av_samples_alloc(ob, &line_size, 2,
c_outsamples,MP3_SAMPLE_FMT, 0);
av_assert0(ret >= 0);
ib[0] = buff;
ret = swr_convert(swr, ob, c_outsamples, ib, c_insamples);
av_assert0(ret >= 0);
/*
* encode
*/
eframe->nb_samples = cbdec/(4);
eframe->pts = (audio_frame_deccount * ( av_rescale_q(1,
audio_encstream->codec->time_base, audio_encstream->time_base)));
avcodec_fill_audio_frame(eframe, 2, MP3_SAMPLE_FMT, ob[0], cbdec, 1);
epkt.stream_index = audio_encstream->index;
eframe->nb_samples = audio_enc_ctx->frame_size;
ret = avcodec_encode_audio2(audio_enc_ctx, &epkt, eframe, &got_frame);
av_assert0(ret >= 0);
audio_frame_deccount +=(cbdec/4);
printf("cbdec=%d, decoded=%d pts=%ld\n", cbdec, audio_frame_deccount,
eframe->pts);
if (!got_frame)
{
return false;
}
epkt.stream_index = audio_encstream->index;
audio_frame_enccount ++ ;
/* Write the compressed frame to the media file. */
ret = av_interleaved_write_frame(encfmt_ctx, &epkt);
av_free(ob[0]);
avcodec_free_frame(&eframe);
return true;
}
int open_encodec_context(AVFormatContext *fmt_ctx, enum AVMediaType type)
{
int ret;
AVStream *st;
AVCodec *enc = NULL;
enc = avcodec_find_encoder(fmt_ctx->oformat->audio_codec);
av_assert0(enc != NULL);
st = avformat_new_stream(fmt_ctx, enc);
/* find encoder for the stream */
st->codec->sample_fmt = MP3_SAMPLE_FMT;
st->codec->bit_rate = MP3_BITRATE;
st->codec->sample_rate = MP3_SAMPLE_RATE;
st->codec->channels = 2;
st->codec->channel_layout = 3;
ret = avcodec_open2(st->codec, enc, NULL);
av_assert0(ret >= 0);
return 1;
}
int main(int argc, char **argv)
{
const char *fn_out = argv[1];
int ret;
av_register_all();
ret = avformat_alloc_output_context2(&encfmt_ctx, NULL, NULL, fn_out);
av_assert0(ret >= 0);
if (open_encodec_context(encfmt_ctx, AVMEDIA_TYPE_AUDIO) >= 0)
{
audio_encstream = encfmt_ctx->streams[0];
audio_enc_ctx = audio_encstream->codec;
av_dump_format(encfmt_ctx, 0, fn_out, 1);
}
swr = swr_alloc();
av_assert0(swr);
/* set options */
av_opt_set_int(swr, "in_channel_layout", 3, 0);
av_opt_set_int(swr, "in_channel_count", 2, 0);
av_opt_set_int(swr, "in_sample_rate", FLAC_SAMPLE_RATE,0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", FLAC_SAMPLE_FMT, 0);
av_opt_set_int(swr, "out_channel_layout",3, 0);
av_opt_set_int(swr, "out_sample_rate", MP3_SAMPLE_RATE, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt",MP3_SAMPLE_FMT, 0);
ret = swr_init(swr);
av_assert0(ret >= 0);
if (!(encfmt_ctx->oformat->flags & AVFMT_NOFILE))
{
ret = avio_open(&encfmt_ctx->pb, fn_out, AVIO_FLAG_WRITE);
av_assert0(ret >= 0);
}
ret = avformat_write_header(encfmt_ctx, NULL);
av_assert0(ret >= 0);
int cbread = 0;
int fd = open("/nas/temp/flac.raw", O_RDONLY);
assert(fd > 0);
int cb2read = BYTES_TO_READ;
BYTE b[cb2read];
int c_reads = 0;
while ((cbread = read(fd, b, cb2read)) > 0)
{
c_reads++;
encode_buffer(b, cbread);
}
avcodec_flush_buffers(audio_enc_ctx);
flush_audio();
close(fd);
ret = av_interleaved_write_frame(encfmt_ctx, NULL);
av_assert0(ret >= 0);
av_write_trailer(encfmt_ctx);
avio_close(encfmt_ctx->pb);
avcodec_close(audio_enc_ctx);
avformat_free_context(encfmt_ctx);
exit(1);
}
/**************** end code *************************/
I have discovered that if I change the number of bytes read in and encoded
(BYTES_TO_READ), that the output changes. I experimented with different
values, and the value 4594 seems to get the closest to the original audio -
although it it about 0.5 seconds longer and the audio is choppy. Also, with
some values of BYTES_TO_READ, the avcodec_encode_audio2 call fails, with an
error of "not enough bytes".
I would like to transcode directly from the flac file to mp3, as the ffmpeg
command line does, as well as take raw audio and encode it to mp3 and other
formats.
So, the basic question is: what is wrong with the above code? I have pieced
this together from the various libav samples on the ffmpeg website.
Also, in the future, I will need to do the same thing with video - encode
raw video in various pixel formats. So, any help here is greatly
appreciated.
TIA
ken
PS: sorry for the long message, but I did feel the code was important.
--
View this message in context: http://libav-users.943685.n4.nabble.com/Can-t-convert-raw-audio-to-mp3-tp4660311.html
Sent from the libav-users mailing list archive at Nabble.com.
More information about the Libav-user
mailing list