diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2018-12-22 20:01:42 -0500 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2018-12-22 20:12:10 -0500 |
commit | 928557bb174fdc6ae44d784137e19a61b4f42693 (patch) | |
tree | 37b6a3effd923b839c8fb02b806c43ea7506be9f /lib/rbcodec/metadata | |
parent | 9b9b30bd547c829157f3f83c71378f0bbd43241d (diff) | |
download | rockbox-928557bb174fdc6ae44d784137e19a61b4f42693.tar.gz rockbox-928557bb174fdc6ae44d784137e19a61b4f42693.zip |
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
Diffstat (limited to 'lib/rbcodec/metadata')
-rw-r--r-- | lib/rbcodec/metadata/aac.c | 122 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.c | 3 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.h | 1 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata_parsers.h | 1 |
4 files changed, 127 insertions, 0 deletions
diff --git a/lib/rbcodec/metadata/aac.c b/lib/rbcodec/metadata/aac.c new file mode 100644 index 0000000000..82adeacbde --- /dev/null +++ b/lib/rbcodec/metadata/aac.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Parsing ADTS and ADIF headers | ||
11 | * | ||
12 | * Written by Igor B. Poretsky | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | |||
24 | #include <stdlib.h> | ||
25 | #include <stdbool.h> | ||
26 | #include <string.h> | ||
27 | |||
28 | #include "platform.h" | ||
29 | |||
30 | #include "metadata.h" | ||
31 | #include "metadata_common.h" | ||
32 | #include "metadata_parsers.h" | ||
33 | |||
34 | static const int sample_rates[] = | ||
35 | { | ||
36 | 96000, 88200, 64000, 48000, | ||
37 | 44100, 32000, 24000, 22050, | ||
38 | 16000, 12000, 11025, 8000, | ||
39 | 7350, 0, 0, 0 | ||
40 | }; | ||
41 | |||
42 | static bool check_adts_syncword(int fd) | ||
43 | { | ||
44 | uint16_t syncword; | ||
45 | |||
46 | read_uint16be(fd, &syncword); | ||
47 | return (syncword & 0xFFF6) == 0xFFF0; | ||
48 | } | ||
49 | |||
50 | bool get_aac_metadata(int fd, struct mp3entry *entry) | ||
51 | { | ||
52 | unsigned char buf[5]; | ||
53 | |||
54 | entry->title = NULL; | ||
55 | entry->tracknum = 0; | ||
56 | entry->discnum = 0; | ||
57 | entry->id3v1len = 0; | ||
58 | entry->id3v2len = getid3v2len(fd); | ||
59 | entry->first_frame_offset = entry->id3v2len; | ||
60 | entry->filesize = filesize(fd) - entry->first_frame_offset; | ||
61 | entry->needs_upsampling_correction = false; | ||
62 | |||
63 | if (entry->id3v2len) | ||
64 | setid3v2title(fd, entry); | ||
65 | |||
66 | if (-1 == lseek(fd, entry->first_frame_offset, SEEK_SET)) | ||
67 | return false; | ||
68 | |||
69 | if (check_adts_syncword(fd)) | ||
70 | { | ||
71 | int frames; | ||
72 | int stat_length; | ||
73 | uint64_t total; | ||
74 | if (read(fd, buf, 5) != 5) | ||
75 | return false; | ||
76 | entry->frequency = sample_rates[(buf[0] >> 2) & 0x0F]; | ||
77 | entry->vbr = ((buf[3] & 0x1F) == 0x1F) | ||
78 | && ((buf[4] & 0xFC) == 0xFC); | ||
79 | stat_length = entry->frequency >> ((entry->vbr) ? 5 : 7); | ||
80 | for (frames = 1, total = 0; frames < stat_length; frames++) | ||
81 | { | ||
82 | unsigned int frame_length = (((unsigned int)buf[1] & 0x3) << 11) | ||
83 | | ((unsigned int)buf[2] << 3) | ||
84 | | ((unsigned int)buf[3] >> 5); | ||
85 | total += frame_length; | ||
86 | if (frame_length < 7) | ||
87 | break; | ||
88 | if (-1 == lseek(fd, frame_length - 7, SEEK_CUR)) | ||
89 | break; | ||
90 | if (!check_adts_syncword(fd)) | ||
91 | break; | ||
92 | if (read(fd, buf, 5) != 5) | ||
93 | break; | ||
94 | } | ||
95 | entry->bitrate = (unsigned int)((total * entry->frequency / frames + 64000) / 128000); | ||
96 | if (entry->frequency <= 24000) | ||
97 | { | ||
98 | entry->frequency <<= 1; | ||
99 | entry->needs_upsampling_correction = true; | ||
100 | } | ||
101 | } | ||
102 | else | ||
103 | { | ||
104 | uint32_t bitrate; | ||
105 | if (-1 == lseek(fd, entry->first_frame_offset, SEEK_SET)) | ||
106 | return false; | ||
107 | if (read(fd, buf, 5) != 5) | ||
108 | return false; | ||
109 | if (memcmp(buf, "ADIF", 4)) | ||
110 | return false; | ||
111 | if (-1 == lseek(fd, (buf[4] & 0x80) ? (entry->first_frame_offset + 9) : entry->first_frame_offset, SEEK_SET)) | ||
112 | return false; | ||
113 | read_uint32be(fd, &bitrate); | ||
114 | entry->vbr = (bitrate & 0x10000000) != 0; | ||
115 | entry->bitrate = ((bitrate & 0xFFFFFE0) + 16000) / 32000; | ||
116 | read_uint32be(fd, (uint32_t*)(&(entry->frequency))); | ||
117 | entry->frequency = sample_rates[(entry->frequency >> (entry->vbr ? 23 : 3)) & 0x0F]; | ||
118 | } | ||
119 | entry->length = (unsigned long)((entry->filesize * 8LL + (entry->bitrate >> 1)) / entry->bitrate); | ||
120 | |||
121 | return true; | ||
122 | } | ||
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c index 7ca4b1afd2..c24a27df2b 100644 --- a/lib/rbcodec/metadata/metadata.c +++ b/lib/rbcodec/metadata/metadata.c | |||
@@ -235,6 +235,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = | |||
235 | /* Opus */ | 235 | /* Opus */ |
236 | [AFMT_OPUS] = | 236 | [AFMT_OPUS] = |
237 | AFMT_ENTRY("Opus", "opus", NULL, get_ogg_metadata, "opus\0"), | 237 | AFMT_ENTRY("Opus", "opus", NULL, get_ogg_metadata, "opus\0"), |
238 | /* AAC bitstream format */ | ||
239 | [AFMT_AAC_BSF] = | ||
240 | AFMT_ENTRY("AAC", "aac_bsf", NULL, get_aac_metadata, "aac\0"), | ||
238 | #endif | 241 | #endif |
239 | }; | 242 | }; |
240 | 243 | ||
diff --git a/lib/rbcodec/metadata/metadata.h b/lib/rbcodec/metadata/metadata.h index 18cfce7523..a7ebcf16e5 100644 --- a/lib/rbcodec/metadata/metadata.h +++ b/lib/rbcodec/metadata/metadata.h | |||
@@ -90,6 +90,7 @@ enum | |||
90 | AFMT_VGM, /* VGM (Video Game Music Format) */ | 90 | AFMT_VGM, /* VGM (Video Game Music Format) */ |
91 | AFMT_KSS, /* KSS (MSX computer KSS Music File) */ | 91 | AFMT_KSS, /* KSS (MSX computer KSS Music File) */ |
92 | AFMT_OPUS, /* Opus (see http://www.opus-codec.org ) */ | 92 | AFMT_OPUS, /* Opus (see http://www.opus-codec.org ) */ |
93 | AFMT_AAC_BSF, | ||
93 | #endif | 94 | #endif |
94 | 95 | ||
95 | /* add new formats at any index above this line to have a sensible order - | 96 | /* add new formats at any index above this line to have a sensible order - |
diff --git a/lib/rbcodec/metadata/metadata_parsers.h b/lib/rbcodec/metadata/metadata_parsers.h index 304e393538..9f03c79bb5 100644 --- a/lib/rbcodec/metadata/metadata_parsers.h +++ b/lib/rbcodec/metadata/metadata_parsers.h | |||
@@ -56,4 +56,5 @@ bool get_hes_metadata(int fd, struct mp3entry* id3); | |||
56 | bool get_sgc_metadata(int fd, struct mp3entry* id3); | 56 | bool get_sgc_metadata(int fd, struct mp3entry* id3); |
57 | bool get_vgm_metadata(int fd, struct mp3entry* id3); | 57 | bool get_vgm_metadata(int fd, struct mp3entry* id3); |
58 | bool get_kss_metadata(int fd, struct mp3entry* id3); | 58 | bool get_kss_metadata(int fd, struct mp3entry* id3); |
59 | bool get_aac_metadata(int fd, struct mp3entry* id3); | ||
59 | #endif /* CONFIG_CODEC == SWCODEC */ | 60 | #endif /* CONFIG_CODEC == SWCODEC */ |