lame解码mp3时兼容性问题

    解决了lame-3.100交叉编译问题后,照着API文档实现了mp3编码,解码部分lame也有实现,使用的是mpg123的老版本库,通过hip这个接口实现,在lame.h中就hip_decode_init , hip_decode_exit, hip_decode , hip_decode_headers 这么几个函数体现。

    通过下面这个循环解析出帧格式,发现有很多mp3解析不对,兼容性不好。

while (!mp3data.header_parsed) {
         len = fread(buf, 1, sizeof(buf), inputFile);
         if (len != sizeof(buf))
             return -1;
         ret = hip_decode1_headers(hip, buf, len, pcm_l, pcm_r, &mp3data);
         if (-1 == ret)
         {
             break;
         }
     }

    但是,在shell中使用指令lame --decode可以把mp3转换为wav格式,解析不对的mp3都使用正常,发现lame  decode并不是使用上面的调用方法。把lame库代码添加到source insight工程,然后查找main函数,跳转到lame_main,发现指令解析mp3时主要调用的get_audio.h中的 int     init_infile(lame_t gfp, char const * inPath); 函数。然后顺藤摸瓜,找到了函数int
lame_decode_initfile(FILE * fd, mp3data_struct * mp3data, int *enc_delay, int *enc_padding)

    显然,要从库里调用这个函数不太现实,把frontend里的文件移植到工程中也比较麻烦,好在我只需要播放mp3,不太关注帧格式的信息,就从lame_decode_initfile提取部分代码到自己的函数中。

hip_decode_init();
memset(mp3data, 0, sizeof(mp3data_struct));

    len = 4;
    if (fread(buf, 1, len, fd) != len)
        return -1;      /* failed */
    while (buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3') {
        len = 6;
        if (fread(&buf[4], 1, len, fd) != len)
            return -1;  /* failed */
        len = lenOfId3v2Tag(&buf[6]);
        if (global.in_id3v2_size < 1) {
            global.in_id3v2_size = 10 + len;
            global.in_id3v2_tag = malloc(global.in_id3v2_size);
            if (global.in_id3v2_tag) {
                memcpy(global.in_id3v2_tag, buf, 10);
                if (fread(&global.in_id3v2_tag[10], 1, len, fd) != len)
                    return -1;  /* failed */
                len = 0; /* copied, nothing to skip */
            }
            else {
                global.in_id3v2_size = 0;
            }
        }
     
        fseek(fd, (long) len, SEEK_CUR);
        len = 4;
        if (fread(&buf, 1, len, fd) != len)
            return -1;  /* failed */
    }
    aid_header = check_aid(buf);
    if (aid_header) {
        if (fread(&buf, 1, 2, fd) != 2)
            return -1;  /* failed */
        aid_header = (unsigned char) buf[0] + 256 * (unsigned char) buf[1];
        if (global_ui_config.silent < 9) {
            console_printf("Album ID found.  length=%i \n", aid_header);
        }
        /* skip rest of AID, except for 6 bytes we have already read */
        fseek(fd, aid_header - 6, SEEK_CUR);

        /* read 4 more bytes to set up buffer for MP3 header check */
        if (fread(&buf, 1, len, fd) != len)
            return -1;  /* failed */
    }
    len = 4;
    while (!is_syncword_mp123(buf)) {
        unsigned int i;
        for (i = 0; i < len - 1; i++)
            buf[i] = buf[i + 1];
        if (fread(buf + len - 1, 1, 1, fd) != 1)
            return -1;  /* failed */
    }

    if ((buf[2] & 0xf0) == 0) {

        freeformat = 1;
    }
    /* now parse the current buffer looking for MP3 headers.    */
    /* (as of 11/00: mpglib modified so that for the first frame where  */
    /* headers are parsed, no data will be decoded.   */
    /* However, for freeformat, we need to decode an entire frame, */
    /* so mp3data->bitrate will be 0 until we have decoded the first */
    /* frame.  Cannot decode first frame here because we are not */
    /* yet prepared to handle the output. */
    ret = hip_decode1_headersB(global.hip, buf, len, pcm_l, pcm_r, mp3data, enc_delay, enc_padding);
    if (-1 == ret)
        return -1;

    /* repeat until we decode a valid mp3 header.  */
    while (!mp3data->header_parsed) {
        len = fread(buf, 1, sizeof(buf), fd);
        if (len != sizeof(buf))
            return -1;
        ret =
            hip_decode1_headersB(global.hip, buf, len, pcm_l, pcm_r, mp3data, enc_delay,
                                 enc_padding);
        if (-1 == ret)
            return -1;
    }

    if (mp3data->bitrate == 0 && !freeformat) {

        return lame_decode_initfile(fd, mp3data, enc_delay, enc_padding);
    }

    if (mp3data->totalframes > 0) {
        /* mpglib found a Xing VBR header and computed nsamp & totalframes */
    }
    else {
        /* set as unknown.  Later, we will take a guess based on file size
         * ant bitrate */
        mp3data->nsamp = MAX_U_32_NUM;
    }

    再把调用的几个小函数也copy过来,fskip直接用fseek替换了, is_syncword_mp123中不是sf_mp3就直接return 0。

    大致解读下这段函数意思,就是根据mp3的格式依次读取内容,首先识别ID3V2内容,然后是唱片集信息,然后是VBR帧头,注意vbr帧头的前4字节和mp3帧头的4字节格式相同,但总处在layer I层,就是这点害了我最上边那段解析的代码,读出来是不对的采样率和比特率,vbr帧头4字节后面是“Xing”火灾“lame”, 跳过vbr帧头才是mp3音频帧.

    解码的时候计算一下帧长度

// = 每帧采样率 / 8 × 比特率 / 采样频率 + 填充
    framesize = mp3data.framesize / 8 * mp3data.bitrate * 1000 / mp3data.samplerate + 1;

    vbr的时候帧长可变,好在hip会记录缓冲区上一次解码的地址,就默认每次都喂 framesize 个字节就能播放了,

使用的是hip_decode1,只解一帧或者不够一帧就返回0。

    MP3帧格式可搜索一下,有很多文章讲的很详细了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值