Mp3 decoding using ffmpeg API (missing header)

I tried to decode the MP3 file in pcm using the ffmpeg API, but I keep getting the error message

[mp3 @ 0x8553020] Missing title

this is the code i use:

#include <stdlib.h> #include <stdio.h> #include <string.h> #ifdef HAVE_AV_CONFIG_H #undef HAVE_AV_CONFIG_H #endif #include "libavcodec/avcodec.h" #include "libavutil/mathematics.h" #define INBUF_SIZE 4096 #define AUDIO_INBUF_SIZE 20480 #define AUDIO_REFILL_THRESH 4096 static void audio_decode_example(const char *outfilename, const char *filename) { AVCodec *codec; AVCodecContext *c= NULL; int out_size, len; FILE *f, *outfile; uint8_t *outbuf; uint8_t inbuf[AUDIO_INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE]; AVPacket avpkt; av_init_packet(&avpkt); printf("Audio decoding\n"); /* find the mpeg audio decoder */ codec = avcodec_find_decoder(CODEC_ID_MP3ON4); if (!codec) { fprintf(stderr, "codec not found\n"); exit(1); } c= avcodec_alloc_context(); /* open it */ if (avcodec_open(c, codec) < 0) { fprintf(stderr, "could not open codec\n"); exit(1); } outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); f = fopen(filename, "rb"); if (!f) { fprintf(stderr, "could not open %s\n", filename); exit(1); } outfile = fopen(outfilename, "wb"); if (!outfile) { av_free(c); exit(1); } /* decode until eof */ avpkt.data = inbuf; avpkt.size = fread(inbuf, 1, AUDIO_INBUF_SIZE, f); while (avpkt.size > 0) { out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; len = avcodec_decode_audio3(c, (short *)outbuf, &out_size, &avpkt); if (len < 0) { fprintf(stderr, "Error while decoding\n"); exit(1); } if (out_size > 0) { /* if a frame has been decoded, output it */ fwrite(outbuf, 1, out_size, outfile); } avpkt.size -= len; avpkt.data += len; if (avpkt.size < AUDIO_REFILL_THRESH) { /* Refill the input buffer, to avoid trying to decode * incomplete frames. Instead of this, one could also use * a parser, or use a proper container format through * libavformat. */ memmove(inbuf, avpkt.data, avpkt.size); avpkt.data = inbuf; len = fread(avpkt.data + avpkt.size, 1, AUDIO_INBUF_SIZE - avpkt.size, f); if (len > 0) avpkt.size += len; } } fclose(outfile); fclose(f); free(outbuf); avcodec_close(c); av_free(c); } int main(int argc, char **argv) { const char *filename; /* must be called before using avcodec lib */ avcodec_init(); /* register all the codecs */ avcodec_register_all(); audio_decode_example("test.wav", argv[1]); return 0; } 

when I use the same code to play the sound directly, for example:

 if (out_size > 0) { /* if a frame has been decoded, output it * play_sound(outbuf, out_size); } 

I don’t have problems with some files at all, other mp3 files just give an error without even starting ... are there any ideas?

PS: this code is from libavcodec / api-example.c, modified as needed

+7
source share
3 answers

I think I found my answer: avpkt.data should have a heading in front, without any junk or previous frames, or it could be the starting file of an mp3 file (name, gender, year ... etc.).

so you need to write a small parser, this is a useful link for mp3 headers (just find the correct bytes inside the file and increase the avpkt.data pointer to match):

http://www.mp3-tech.org/programmer/frame_header.html

+2
source

Use avformat to read instead of fread (). For example, it can be configured (for example, for buffering), it can automatically detect and check formats at opening, and also separate probe functions and other materials related to the format. And it works correctly with headers. I came to the following use (warning, code may contain errors)

 struct FormatCtx { inline FormatCtx(const char* filename) : ctx_(avformat_alloc_context()) { av_init_packet(&p); if (avformat_open_input(&ctx_, filename, 0, 0) < 0) abort(); if (avformat_find_stream_info(ctx_, 0) < 0) abort(); } inline ~FormatCtx() { av_free_packet(&p); } inline bool read() { return av_read_frame(ctx_, &p) >= 0; } AVFormatContext* ctx_; AVPacket p; } formatCtx_; AVCodec* findCodec(const char* filename) { AVCodec* codec = formatCtx_.ctx_->audio_codec; if (codec) return codec; codec = avcodec_find_decoder(formatCtx_.ctx_->audio_codec_id); if (codec) return codec; AVOutputFormat* fmt = av_guess_format(0, //const char *short_name, filename, 0); // const char *mime_type);; codec = fmt ? avcodec_find_decoder(fmt->audio_codec) : 0; if (codec) return codec; return 0; } //*** initialize all stuff *** AVCodec* codec = findCodec(filename); if (!codec) exit(1); AVCodecContext* c; // class member for me, needed for following reading int stream_index_; // class member for me, needed for extra stuff for (size_t i = 0; i < formatCtx_.ctx_->nb_streams; ++i) { AVCodecContext* tc = formatCtx_.ctx_->streams[i]->codec; if (tc->codec_type == AVMEDIA_TYPE_AUDIO) { c = tc; stream_index_ = i; break; } } // for example, here we're know track length l->onDurationDetected(double(formatCtx_.ctx_->streams[stream_index_]->duration) * av_q2d(formatCtx_.ctx_->streams[stream_index_]->time_base)); if (avcodec_open2(c, codec, &d.d_) < 0) exit(1); c->channels = 2; c->sample_rate = 48000; c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; c->channel_layout = av_get_default_channel_layout(2); 

After that, you should basically prepare the decoded_frame from the TC example and pass the package used for reading to avcodec_decode_audio4 (instead of avpkt ).

+1
source

disassembling Mp2 there is no this problem - do not use av_parser_parse2 () to use av_read_frame ()

0
source

Source: https://habr.com/ru/post/909698/


All Articles