2012-03-01 14 views
6

que he estado tratando de descifrar un archivo MP3 a PCM, usando API ffmpeg, pero sigo obteniendo un errormp3 decodificación usando ffmpeg API (Cabecera falta)

[mp3 @ 0x8553020] Cabecera falta

este es el código que utilizo:

#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; 
} 

cuando se utiliza el mismo código para reproducir directamente el sonido, así:

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

no tengo ningún problema con algunos archivos, otros archivos mp3 simplemente dan un error sin siquiera iniciar ... ¿hay alguna idea?

PS: este código es de/api-example.c libavcodec, modificado según sea necesario

Respuesta

2

Creo que he encontrado mi respuesta, la avpkt.data debe tener una cabecera delante, sin ningún tipo de basura o bytes de la trama anteriores , o pueden ser datos iniciales de archivos mp3 (nombre, sexo, año ... etc.).

así que un poco analizador debe ser escrito, este es un vínculo útil para los encabezados de mp3 (sólo la búsqueda de los bytes correctos en dentro del archivo, y aumentar avpkt.data puntero a coincidir):

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

+4

¿Puede explicar cómo resolvió este error? También estoy sorprendido en esta etapa ya que los archivos mp3 con etiquetas ID3 no se reproducen usando ffmpeg. –

+1

@WIN ¿puedes dar más detalles sobre cómo corrigió el error? – w2lame

1

Use avformat para leer en lugar de fread(). Por ejemplo, puede personalizarse (por ejemplo, para el almacenamiento en búfer), puede detectar y verificar formatos automáticamente al abrirse y también tiene funciones de sonda separadas y otras cosas relacionadas con el formato. Y funciona correctamente con los encabezados. Vine a uso siguiente (advertencia, código puede contener errores)

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); 

Después de que básicamente debe preparar decoded_frame del ejemplo de TC y pasar paquete utilizado para la lectura a avcodec_decode_audio4 (en lugar de avpkt).

Cuestiones relacionadas