rockbox/lib/rbcodec/metadata/aac.c
Solomon Peachy 928557bb17 AAC bitstream format files support
Files with extension "aac" in ADTS or ADIF format are now playable.

Full credit goes to Igor Poretsky.

Change-Id: I413b34e15e5242fea60d3461966ae0984080f530
2018-12-22 20:12:10 -05:00

122 lines
3.9 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Parsing ADTS and ADIF headers
*
* Written by Igor B. Poretsky
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "platform.h"
#include "metadata.h"
#include "metadata_common.h"
#include "metadata_parsers.h"
static const int sample_rates[] =
{
96000, 88200, 64000, 48000,
44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000,
7350, 0, 0, 0
};
static bool check_adts_syncword(int fd)
{
uint16_t syncword;
read_uint16be(fd, &syncword);
return (syncword & 0xFFF6) == 0xFFF0;
}
bool get_aac_metadata(int fd, struct mp3entry *entry)
{
unsigned char buf[5];
entry->title = NULL;
entry->tracknum = 0;
entry->discnum = 0;
entry->id3v1len = 0;
entry->id3v2len = getid3v2len(fd);
entry->first_frame_offset = entry->id3v2len;
entry->filesize = filesize(fd) - entry->first_frame_offset;
entry->needs_upsampling_correction = false;
if (entry->id3v2len)
setid3v2title(fd, entry);
if (-1 == lseek(fd, entry->first_frame_offset, SEEK_SET))
return false;
if (check_adts_syncword(fd))
{
int frames;
int stat_length;
uint64_t total;
if (read(fd, buf, 5) != 5)
return false;
entry->frequency = sample_rates[(buf[0] >> 2) & 0x0F];
entry->vbr = ((buf[3] & 0x1F) == 0x1F)
&& ((buf[4] & 0xFC) == 0xFC);
stat_length = entry->frequency >> ((entry->vbr) ? 5 : 7);
for (frames = 1, total = 0; frames < stat_length; frames++)
{
unsigned int frame_length = (((unsigned int)buf[1] & 0x3) << 11)
| ((unsigned int)buf[2] << 3)
| ((unsigned int)buf[3] >> 5);
total += frame_length;
if (frame_length < 7)
break;
if (-1 == lseek(fd, frame_length - 7, SEEK_CUR))
break;
if (!check_adts_syncword(fd))
break;
if (read(fd, buf, 5) != 5)
break;
}
entry->bitrate = (unsigned int)((total * entry->frequency / frames + 64000) / 128000);
if (entry->frequency <= 24000)
{
entry->frequency <<= 1;
entry->needs_upsampling_correction = true;
}
}
else
{
uint32_t bitrate;
if (-1 == lseek(fd, entry->first_frame_offset, SEEK_SET))
return false;
if (read(fd, buf, 5) != 5)
return false;
if (memcmp(buf, "ADIF", 4))
return false;
if (-1 == lseek(fd, (buf[4] & 0x80) ? (entry->first_frame_offset + 9) : entry->first_frame_offset, SEEK_SET))
return false;
read_uint32be(fd, &bitrate);
entry->vbr = (bitrate & 0x10000000) != 0;
entry->bitrate = ((bitrate & 0xFFFFFE0) + 16000) / 32000;
read_uint32be(fd, (uint32_t*)(&(entry->frequency)));
entry->frequency = sample_rates[(entry->frequency >> (entry->vbr ? 23 : 3)) & 0x0F];
}
entry->length = (unsigned long)((entry->filesize * 8LL + (entry->bitrate >> 1)) / entry->bitrate);
return true;
}