2012-03-01 13 views
6

मैं ffmpeg एपीआई का उपयोग कर पीसीएम के लिए एक एमपी 3 फ़ाइल को डिकोड करने के प्रयास कर रहे हैं, लेकिन मैं एक त्रुटि प्राप्त हो रहीएमपी 3 डिकोडिंग ffmpeg का उपयोग कर एपीआई (हैडर लापता)

[एमपी 3 @ 0x8553020] हैडर लापता

इस है कोड मैं का उपयोग करें:

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

जब मैं सीधे, ध्वनि खेलने के लिए इस तरह एक ही कोड का उपयोग करें:

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

मुझे कुछ फाइलों के साथ कोई समस्या नहीं है, अन्य एमपी 3 फाइलें बिना किसी शुरुआत के त्रुटि भी देती हैं ... क्या कोई विचार है?

पुनश्च: इस कोड, libavcodec/api-example.c से है के रूप में की जरूरत

उत्तर

2

मुझे लगता है कि मैं अपने जवाब मिल गया किसी भी कचरा या पिछले फ्रेम बाइट्स के बिना, avpkt.data, सामने एक शीर्ष लेख होना आवश्यक संशोधित , या प्रारंभिक एमपी 3 फ़ाइल डेटा (नाम, लिंग, वर्ष ... आदि) हो सकता है।

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

+4

क्या आप कृपया बता सकते हैं कि आपने यह त्रुटि कैसे हल की है। मैं इस चरण में भी अटक गया हूं क्योंकि आईडी 3 टैग वाले एमपी 3 फाइलें ffmpeg का उपयोग नहीं कर रही हैं। –

+1

@WIN क्या आप इस बारे में अधिक जानकारी दे सकते हैं कि आपने त्रुटि को कैसे ठीक किया? – w2lame

1
:

तो एक छोटे से पार्सर लिखा जाना चाहिए, यह एक उपयोगी (सिर्फ फ़ाइल के भीतर में सही बाइट्स के लिए खोज, और मैच के लिए avpkt.data सूचक वृद्धि) एमपी 3 हेडर के लिए कड़ी है

फ़्रेड() के बजाय पढ़ने के लिए avformat का उपयोग करें। उदाहरण के लिए, इसे अनुकूलित किया जा सकता है (उदा। बफरिंग के लिए), यह स्वचालित रूप से खोलने पर स्वरूपों का पता लगा सकता है और जांच सकता है और जांच कार्यों और अन्य प्रारूप से संबंधित सामान को भी अलग कर सकता है। और यह हेडर के साथ ठीक से काम करता है। मैं निम्नलिखित उपयोग के लिए आया था (चेतावनी, कोड त्रुटियां हो सकती है)

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

उसके बाद आप मूल रूप से टीसी के उदाहरण से decoded_frame तैयार करने और (avpkt के बजाय) avcodec_decode_audio4 को पढ़ने के लिए इस्तेमाल किया पैकेट पास करना चाहिए।