使用 ffmpeg API 的 mp3 解码(缺少标题) [英] mp3 decoding using ffmpeg API (Header missing)

查看:20
本文介绍了使用 ffmpeg API 的 mp3 解码(缺少标题)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用 ffmpeg API 将 MP3 文件解码为 pcm,但我一直收到错误

i have been trying to decode an MP3 file to pcm, using ffmpeg API, but i keep getting an error

[mp3 @ 0x8553020]标题丢失

[mp3 @ 0x8553020]Header missing

这是我使用的代码:

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

    /* find the mpeg audio decoder */
    codec = avcodec_find_decoder(CODEC_ID_MP3ON4);
    if (!codec) {
    fprintf(stderr, "codec not found
");
    exit(1);
    }

    c= avcodec_alloc_context();

    /* open it */
    if (avcodec_open(c, codec) < 0) {
    fprintf(stderr, "could not open codec
");
    exit(1);
    }

    outbuf = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);

    f = fopen(filename, "rb");
    if (!f) {
    fprintf(stderr, "could not open %s
", 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
");
        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 directly play the sound, like this :

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

我对某些文件完全没有问题,其他 mp3 文件甚至没有启动就出现错误......有什么想法吗?

i have no problem at all with some files, other mp3 files just gives an error without even starting ... is there any ideas ?

PS:此代码来自 libavcodec/api-example.c ,根据需要修改

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

推荐答案

我想我找到了答案,avpkt.data 前面必须有一个头,不能有任何垃圾或前帧字节,或者可能是初始 mp3 文件数据(姓名、性别、年份...等).

I think i found my answer, the avpkt.data must have a header in front, without any garbage or previous frame bytes, or may be initial mp3 file data (name, gender, year ... etc).

所以必须写一个小解析器,这是一个有用的 mp3 头链接(只需在文件中搜索正确的字节,并增加 avpkt.data 指针以匹配):

so a little parser must be wrote, this is a useful link for mp3 headers (just search for the correct bytes in within the file, and increase avpkt.data pointer to match):

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

这篇关于使用 ffmpeg API 的 mp3 解码(缺少标题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆