2012-03-01 25 views
6

(Üstbilgi eksik), ancak bir hatamp3 kod çözme kullanarak ffmpeg API i ffmpeg API kullanarak PCM olarak bir MP3 dosyası çözmeye çalışıyorlar

almaya devam [mp3 @ 0x8553020] Başlık

bu kayıp kod i kullanmak edilir:

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

i doğrudan bu gibi ses çıkarması aynı kodu kullandığınızda:

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

Bazı dosyalarda hiç sorun yaşamadım, diğer mp3 dosyaları bile başlamadan bir hata veriyor ... herhangi bir fikir var mı?

Not: Bu kod Ben herhangi çöp veya önceki çerçeve bayt olmadan, avpkt.data, önünde bir başlığa sahip olmalıdır benim cevap buldum gerekli

cevap

2

olarak değiştirilmiş, libavcodec/api-example.c dan ya da ilk mp3 dosyası verisi olabilir (isim, cinsiyet, yıl ... vb).

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

+4

Bu hatayı nasıl çözdüğünüzü açıklar mısınız? ID3 etiketli mp3 dosyaları ffmpeg kullanılarak oynatılmıyorken bu aşamada da takıldım. –

+1

@WIN Hatayı nasıl düzelttiğiniz hakkında daha fazla bilgi verebilir misiniz? – w2lame

1
:

yüzden biraz ayrıştırıcı yazdı gerekir bu mp3 başlıklarını için yararlı bir bağlantı (sadece dosya içinde doğru bayt arayabilir ve maç için avpkt.data işaretçi artırmak) 'dir

Fread yerine okumak için avformat kullanın(). Örneğin, özelleştirilebilir (örneğin, tamponlama için), açılışta otomatik olarak formatları tespit edebilir ve kontrol edebilir ve ayrıca prob fonksiyonlarını ve formatla ilgili diğer şeyleri ayırabilir. Ve başlıklarla düzgün çalışıyor. Ben temelde (yerine avpkt arasında) avcodec_decode_audio4 için okunması için kullanılan paket TC örnekten decoded_frame hazırlayıp geçmelidir Bundan sonra

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

(kod hataları içerebilir uyarı) Aşağıdaki kullanım geldi.

İlgili konular