diff options
Diffstat (limited to 'apps/metadata/oma.c')
-rw-r--r-- | apps/metadata/oma.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/apps/metadata/oma.c b/apps/metadata/oma.c new file mode 100644 index 0000000000..695ae0b114 --- /dev/null +++ b/apps/metadata/oma.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* | ||
2 | * Sony OpenMG (OMA) demuxer | ||
3 | * | ||
4 | * Copyright (c) 2008 Maxim Poliakovski | ||
5 | * 2008 Benjamin Larsson | ||
6 | * | ||
7 | * This file is part of FFmpeg. | ||
8 | * | ||
9 | * FFmpeg is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU Lesser General Public | ||
11 | * License as published by the Free Software Foundation; either | ||
12 | * version 2.1 of the License, or (at your option) any later version. | ||
13 | * | ||
14 | * FFmpeg is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public | ||
20 | * License along with FFmpeg; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | */ | ||
23 | |||
24 | /** | ||
25 | * @file oma.c | ||
26 | * This is a demuxer for Sony OpenMG Music files | ||
27 | * | ||
28 | * Known file extensions: ".oma", "aa3" | ||
29 | * The format of such files consists of three parts: | ||
30 | * - "ea3" header carrying overall info and metadata. | ||
31 | * - "EA3" header is a Sony-specific header containing information about | ||
32 | * the OpenMG file: codec type (usually ATRAC, can also be MP3 or WMA), | ||
33 | * codec specific info (packet size, sample rate, channels and so on) | ||
34 | * and DRM related info (file encryption, content id). | ||
35 | * - Sound data organized in packets follow the EA3 header | ||
36 | * (can be encrypted using the Sony DRM!). | ||
37 | * | ||
38 | * LIMITATIONS: This version supports only plain (unencrypted) OMA files. | ||
39 | * If any DRM-protected (encrypted) file is encountered you will get the | ||
40 | * corresponding error message. Try to remove the encryption using any | ||
41 | * Sony software (for example SonicStage). | ||
42 | * CODEC SUPPORT: Only ATRAC3 codec is currently supported! | ||
43 | */ | ||
44 | |||
45 | #include <stdlib.h> | ||
46 | #include <inttypes.h> | ||
47 | #include <string.h> | ||
48 | #include "metadata.h" | ||
49 | #include "metadata_parsers.h" | ||
50 | |||
51 | #define EA3_HEADER_SIZE 96 | ||
52 | |||
53 | #if 0 | ||
54 | #define DEBUGF printf | ||
55 | #else | ||
56 | #define DEBUGF(...) | ||
57 | #endif | ||
58 | |||
59 | /* Various helper macros taken from ffmpeg for reading * | ||
60 | * and writing buffers with a specified endianess. */ | ||
61 | # define AV_RB16(x) \ | ||
62 | ((((const uint8_t*)(x))[0] << 8) | \ | ||
63 | ((const uint8_t*)(x))[1]) | ||
64 | # define AV_RB24(x) \ | ||
65 | ((((const uint8_t*)(x))[0] << 16) | \ | ||
66 | (((const uint8_t*)(x))[1] << 8) | \ | ||
67 | ((const uint8_t*)(x))[2]) | ||
68 | # define AV_RB32(x) \ | ||
69 | ((((const uint8_t*)(x))[0] << 24) | \ | ||
70 | (((const uint8_t*)(x))[1] << 16) | \ | ||
71 | (((const uint8_t*)(x))[2] << 8) | \ | ||
72 | ((const uint8_t*)(x))[3]) | ||
73 | # define AV_WL32(p, d) do { \ | ||
74 | ((uint8_t*)(p))[0] = (d); \ | ||
75 | ((uint8_t*)(p))[1] = (d)>>8; \ | ||
76 | ((uint8_t*)(p))[2] = (d)>>16; \ | ||
77 | ((uint8_t*)(p))[3] = (d)>>24; \ | ||
78 | } while(0) | ||
79 | # define AV_WL16(p, d) do { \ | ||
80 | ((uint8_t*)(p))[0] = (d); \ | ||
81 | ((uint8_t*)(p))[1] = (d)>>8; \ | ||
82 | } while(0) | ||
83 | |||
84 | /* Different codecs that could be present in a Sony OMA * | ||
85 | * container file. */ | ||
86 | enum { | ||
87 | OMA_CODECID_ATRAC3 = 0, | ||
88 | OMA_CODECID_ATRAC3P = 1, | ||
89 | OMA_CODECID_MP3 = 3, | ||
90 | OMA_CODECID_LPCM = 4, | ||
91 | OMA_CODECID_WMA = 5, | ||
92 | }; | ||
93 | |||
94 | /* FIXME: This functions currently read different file * | ||
95 | * parameters required for decoding. It still * | ||
96 | * does not read the metadata - which should be * | ||
97 | * present in the ea3 (first) header. The * | ||
98 | * metadata in ea3 is stored as a variation of * | ||
99 | * the ID3v2 metadata format. */ | ||
100 | int oma_read_header(int fd, struct mp3entry* id3) | ||
101 | { | ||
102 | static const uint16_t srate_tab[6] = {320,441,480,882,960,0}; | ||
103 | int ret, ea3_taglen, EA3_pos, jsflag; | ||
104 | uint32_t codec_params; | ||
105 | int16_t eid; | ||
106 | uint8_t buf[EA3_HEADER_SIZE]; | ||
107 | |||
108 | ret = read(fd, buf, 10); | ||
109 | if (ret != 10) | ||
110 | return -1; | ||
111 | |||
112 | ea3_taglen = ((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f); | ||
113 | |||
114 | EA3_pos = ea3_taglen + 10; | ||
115 | if (buf[5] & 0x10) | ||
116 | EA3_pos += 10; | ||
117 | |||
118 | lseek(fd, EA3_pos, SEEK_SET); | ||
119 | ret = read(fd, buf, EA3_HEADER_SIZE); | ||
120 | if (ret != EA3_HEADER_SIZE) | ||
121 | return -1; | ||
122 | |||
123 | if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}),3) || buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) { | ||
124 | DEBUGF("Couldn't find the EA3 header !\n"); | ||
125 | return -1; | ||
126 | } | ||
127 | |||
128 | eid = AV_RB16(&buf[6]); | ||
129 | if (eid != -1 && eid != -128) { | ||
130 | DEBUGF("Encrypted file! Eid: %d\n", eid); | ||
131 | return -1; | ||
132 | } | ||
133 | |||
134 | codec_params = AV_RB24(&buf[33]); | ||
135 | |||
136 | switch (buf[32]) { | ||
137 | case OMA_CODECID_ATRAC3: | ||
138 | id3->frequency = srate_tab[(codec_params >> 13) & 7]*100; | ||
139 | if (id3->frequency != 44100) { | ||
140 | DEBUGF("Unsupported sample rate, send sample file to developers: %d\n", samplerate); | ||
141 | return -1; | ||
142 | } | ||
143 | |||
144 | id3->bytesperframe = (codec_params & 0x3FF) * 8; | ||
145 | id3->codectype = AFMT_OMA_ATRAC3; | ||
146 | jsflag = (codec_params >> 17) & 1; /* get stereo coding mode, 1 for joint-stereo */ | ||
147 | |||
148 | id3->bitrate = id3->frequency * id3->bytesperframe * 8 / (1024 * 1000); | ||
149 | |||
150 | /* fake the atrac3 extradata (wav format, makes stream copy to wav work) */ | ||
151 | /* ATRAC3 expects and extra-data size of 14 bytes for wav format; extra-data size * | ||
152 | * is stored in ATRAC3Context before initializing the decoder. See atrac3_oma.codec. * | ||
153 | * We use id3v2buf to hold the (fake) extra-data provided from the container. */ | ||
154 | |||
155 | AV_WL16(&id3->id3v1buf[0][0], 1); // always 1 | ||
156 | AV_WL32(&id3->id3v1buf[0][2], id3->frequency); // samples rate | ||
157 | AV_WL16(&id3->id3v1buf[0][6], jsflag); // coding mode | ||
158 | AV_WL16(&id3->id3v1buf[0][8], jsflag); // coding mode | ||
159 | AV_WL16(&id3->id3v1buf[0][10], 1); // always 1 | ||
160 | AV_WL16(&id3->id3v1buf[0][12], 0); // always 0 | ||
161 | |||
162 | DEBUGF("sample_rate = %d\n", id3->frequency); | ||
163 | DEBUGF("frame_size = %d\n", id3->bytesperframe); | ||
164 | DEBUGF("stereo_coding_mode = %d\n", jsflag); | ||
165 | break; | ||
166 | default: | ||
167 | DEBUGF("Unsupported codec %d!\n",buf[32]); | ||
168 | return -1; | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | /* Store the the offset of the first audio frame, to be able to seek to it * | ||
173 | * directly in atrac3_oma.codec. */ | ||
174 | id3->first_frame_offset = EA3_pos + EA3_HEADER_SIZE; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | bool get_oma_metadata(int fd, struct mp3entry* id3) | ||
179 | { | ||
180 | if(oma_read_header(fd, id3) < 0) | ||
181 | return false; | ||
182 | |||
183 | /* Currently, there's no means of knowing the duration * | ||
184 | * directly from the the file so we calculate it. */ | ||
185 | id3->filesize = filesize(fd); | ||
186 | id3->length = ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate; | ||
187 | return true; | ||
188 | } | ||