2012-03-01 7 views
6

tôi đã cố gắng để giải mã một tập tin MP3 sang pcm, sử dụng API ffmpeg, nhưng tôi tiếp tục nhận được một lỗimp3 giải mã sử dụng ffmpeg API (Tiêu đề thiếu)

[mp3 @ 0x8553020] Tiêu đề thiếu

này được mã tôi sử dụng:

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

khi tôi sử dụng cùng mã trực tiếp chơi âm thanh, như thế này:

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

tôi không có vấn đề gì với một số tệp, các tệp mp3 khác chỉ đưa ra một lỗi mà không cần khởi động ... có ý tưởng nào không?

PS: mã này là từ libavcodec/api-example.c, sửa đổi khi cần thiết

Trả lời

2

Tôi nghĩ rằng tôi tìm thấy câu trả lời của tôi, avpkt.data phải có một tiêu đề ở phía trước, mà không cần bất kỳ rác hoặc byte khung trước hoặc có thể là dữ liệu tệp mp3 ban đầu (tên, giới tính, năm ... v.v.).

do đó, một phân tích cú pháp ít phải được viết, đây là một liên kết hữu ích cho tiêu đề mp3 (chỉ cần tìm kiếm các byte đúng trong trong tập tin, và tăng avpkt.data con trỏ để phù hợp):

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

+4

Bạn có thể giải thích cách bạn giải quyết lỗi này không. Tôi cũng bị mắc kẹt ở giai đoạn này như các tập tin mp3 với thẻ ID3 không chơi bằng cách sử dụng ffmpeg. –

+1

@WIN bạn có thể cung cấp thêm chi tiết về cách bạn khắc phục lỗi không? – w2lame

1

Sử dụng avformat để đọc thay vì fread(). Ví dụ, nó có thể được tùy chỉnh (ví dụ: để đệm), nó có thể phát hiện và kiểm tra định dạng tự động khi mở và cũng có chức năng thăm dò riêng biệt và các công cụ liên quan đến định dạng khác. Và nó hoạt động đúng với tiêu đề. Tôi đến việc sử dụng sau đây (cảnh báo, mã này có thể chứa lỗi)

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

Sau đó về cơ bản bạn nên chuẩn bị decoded_frame từ ví dụ TC và vượt qua gói sử dụng cho việc đọc để avcodec_decode_audio4 (thay vì avpkt).