summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMohamed Tarek <mt@rockbox.org>2010-02-12 03:21:37 +0000
committerMohamed Tarek <mt@rockbox.org>2010-02-12 03:21:37 +0000
commit23ac6ffaa1efeea6417f7d064c0b8f4f280aa0cd (patch)
treea8a71c484048b6d199f587875c15a856e8910640 /apps
parent5039cc716de37035a60cc62585f534dcdd7fa903 (diff)
downloadrockbox-23ac6ffaa1efeea6417f7d064c0b8f4f280aa0cd.tar.gz
rockbox-23ac6ffaa1efeea6417f7d064c0b8f4f280aa0cd.zip
Add support for Sony OMA file format. Currently only supports ATRAC3 (without DRM), and seeks. Tested on sansa
e200. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24615 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/codecs/SOURCES1
-rw-r--r--apps/codecs/atrac3_oma.c158
-rw-r--r--apps/codecs/codecs.make1
-rw-r--r--apps/filetypes.c2
-rw-r--r--apps/metadata.c10
-rw-r--r--apps/metadata.h1
-rw-r--r--apps/metadata/metadata_parsers.h1
-rw-r--r--apps/metadata/oma.c188
9 files changed, 363 insertions, 0 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index f99c2bc640..7580caabc9 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -181,6 +181,7 @@ metadata/a52.c
181metadata/asap.c 181metadata/asap.c
182metadata/rm.c 182metadata/rm.c
183metadata/nsf.c 183metadata/nsf.c
184metadata/oma.c
184#endif 185#endif
185#ifdef HAVE_TAGCACHE 186#ifdef HAVE_TAGCACHE
186tagcache.c 187tagcache.c
diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES
index 75d74ab33b..4c847c23e0 100644
--- a/apps/codecs/SOURCES
+++ b/apps/codecs/SOURCES
@@ -13,6 +13,7 @@ cook.c
13raac.c 13raac.c
14a52_rm.c 14a52_rm.c
15atrac3_rm.c 15atrac3_rm.c
16atrac3_oma.c
16mpc.c 17mpc.c
17wma.c 18wma.c
18sid.c 19sid.c
diff --git a/apps/codecs/atrac3_oma.c b/apps/codecs/atrac3_oma.c
new file mode 100644
index 0000000000..b080b71524
--- /dev/null
+++ b/apps/codecs/atrac3_oma.c
@@ -0,0 +1,158 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Mohamed Tarek
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <string.h>
23
24#include "logf.h"
25#include "codeclib.h"
26#include "inttypes.h"
27#include "libatrac/atrac3.h"
28
29CODEC_HEADER
30
31#define FRAMESIZE ci->id3->bytesperframe
32#define BITRATE ci->id3->bitrate
33
34/* The codec has nothing to do with RM, it just uses an RMContext struct to *
35 * store the data needs to be passed to the decoder initializing function. */
36RMContext rmctx;
37ATRAC3Context q IBSS_ATTR;
38
39static void init_rm(RMContext *rmctx, struct mp3entry *id3)
40{
41 rmctx->sample_rate = id3->frequency;
42 rmctx->nb_channels = 2;
43 rmctx->bit_rate = id3->bitrate;
44 rmctx->block_align = id3->bytesperframe;
45
46 /* 14-byte extra-data was faked in the metadata parser so that *
47 * the ATRAC3 decoder would parse it as WAV format extra-data. */
48 rmctx->extradata_size = 14;
49 memcpy(rmctx->codec_extradata, &id3->id3v1buf[0][0], 14);
50}
51
52/* this is the codec entry point */
53enum codec_status codec_main(void)
54{
55 static size_t buff_size;
56 int datasize, res, frame_counter, total_frames, seek_frame_offset;
57 uint8_t *bit_buffer;
58 int elapsed = 0;
59 size_t resume_offset = ci->id3->offset;
60
61next_track:
62 if (codec_init()) {
63 DEBUGF("codec init failed\n");
64 return CODEC_ERROR;
65 }
66 while (!*ci->taginfo_ready && !ci->stop_codec)
67 ci->sleep(1);
68
69 codec_set_replaygain(ci->id3);
70 ci->memset(&rmctx,0,sizeof(RMContext));
71 ci->memset(&q,0,sizeof(ATRAC3Context));
72
73 init_rm(&rmctx, ci->id3);
74
75 ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
76 ci->configure(DSP_SET_SAMPLE_DEPTH, 17); /* Remark: atrac3 uses s15.0 by default, s15.2 was hacked. */
77 ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ?
78 STEREO_MONO : STEREO_NONINTERLEAVED);
79
80 res =atrac3_decode_init(&q, &rmctx);
81 if(res < 0) {
82 DEBUGF("failed to initialize atrac decoder\n");
83 return CODEC_ERROR;
84 }
85
86 /* check for a mid-track resume and force a seek time accordingly */
87 if(resume_offset > ci->id3->first_frame_offset) {
88 resume_offset -= ci->id3->first_frame_offset;
89 /* calculate resume_offset in frames */
90 resume_offset = (int)resume_offset / FRAMESIZE;
91 ci->seek_time = (int)resume_offset * ((FRAMESIZE * 8)/BITRATE);
92 }
93 total_frames = (ci->id3->filesize - ci->id3->first_frame_offset) / FRAMESIZE;
94 frame_counter = 0;
95
96 ci->set_elapsed(0);
97 ci->advance_buffer(ci->id3->first_frame_offset);
98
99 /* The main decoder loop */
100seek_start :
101 while(frame_counter < total_frames)
102 {
103 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
104
105 ci->yield();
106 if (ci->stop_codec || ci->new_track)
107 goto done;
108
109 if (ci->seek_time) {
110 ci->set_elapsed(ci->seek_time);
111
112 /* Do not allow seeking beyond the file's length */
113 if ((unsigned) ci->seek_time > ci->id3->length) {
114 ci->seek_complete();
115 goto done;
116 }
117
118 /* Seek to the start of the track */
119 if (ci->seek_time == 1) {
120 ci->set_elapsed(0);
121 ci->seek_complete();
122 ci->seek_buffer(ci->id3->first_frame_offset);
123 elapsed = 0;
124 goto seek_start;
125 }
126 seek_frame_offset = (ci->seek_time * BITRATE) / (8 * FRAMESIZE);
127 frame_counter = seek_frame_offset;
128 ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE);
129 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
130 elapsed = ci->seek_time;
131
132 ci->set_elapsed(elapsed);
133 ci->seek_complete();
134 }
135
136 res = atrac3_decode_frame(&rmctx, &q, &datasize, bit_buffer, FRAMESIZE);
137
138 if(res != (int)FRAMESIZE) {
139 DEBUGF("codec error\n");
140 return CODEC_ERROR;
141 }
142
143 if(datasize)
144 ci->pcmbuf_insert(q.outSamples, q.outSamples + 1024, q.samples_per_frame / rmctx.nb_channels);
145
146 elapsed += (FRAMESIZE * 8) / BITRATE;
147 ci->set_elapsed(elapsed);
148
149 ci->advance_buffer(FRAMESIZE);
150 frame_counter++;
151 }
152
153 done:
154 if (ci->request_next_track())
155 goto next_track;
156
157 return CODEC_OK;
158}
diff --git a/apps/codecs/codecs.make b/apps/codecs/codecs.make
index 0c3d2fade0..633f35b273 100644
--- a/apps/codecs/codecs.make
+++ b/apps/codecs/codecs.make
@@ -87,6 +87,7 @@ $(CODECDIR)/cook.codec : $(CODECDIR)/libcook.a $(CODECDIR)/librm.a
87$(CODECDIR)/raac.codec : $(CODECDIR)/libfaad.a $(CODECDIR)/librm.a 87$(CODECDIR)/raac.codec : $(CODECDIR)/libfaad.a $(CODECDIR)/librm.a
88$(CODECDIR)/a52_rm.codec : $(CODECDIR)/liba52.a $(CODECDIR)/librm.a 88$(CODECDIR)/a52_rm.codec : $(CODECDIR)/liba52.a $(CODECDIR)/librm.a
89$(CODECDIR)/atrac3_rm.codec : $(CODECDIR)/libatrac.a $(CODECDIR)/librm.a 89$(CODECDIR)/atrac3_rm.codec : $(CODECDIR)/libatrac.a $(CODECDIR)/librm.a
90$(CODECDIR)/atrac3_oma.codec : $(CODECDIR)/libatrac.a
90$(CODECDIR)/aiff.codec : $(CODECDIR)/libpcm.a 91$(CODECDIR)/aiff.codec : $(CODECDIR)/libpcm.a
91$(CODECDIR)/wav.codec : $(CODECDIR)/libpcm.a 92$(CODECDIR)/wav.codec : $(CODECDIR)/libpcm.a
92 93
diff --git a/apps/filetypes.c b/apps/filetypes.c
index 671a8d5f1b..3feb0f5ab8 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -98,6 +98,8 @@ static const struct filetype inbuilt_filetypes[] = {
98 { "tmc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 98 { "tmc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
99 { "tm8", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 99 { "tm8", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
100 { "tm2", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 100 { "tm2", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
101 { "oma", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
102 { "aa3", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
101#endif 103#endif
102 { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 104 { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
103 { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 105 { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
diff --git a/apps/metadata.c b/apps/metadata.c
index 6281a8526c..619a06e72d 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -162,6 +162,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
162 /* Atari TM2 File */ 162 /* Atari TM2 File */
163 [AFMT_TM2] = 163 [AFMT_TM2] =
164 AFMT_ENTRY("TM2", "asap", NULL, "tm2\0" ), 164 AFMT_ENTRY("TM2", "asap", NULL, "tm2\0" ),
165 /* Atrac3 in Sony OMA Container */
166 [AFMT_OMA_ATRAC3] =
167 AFMT_ENTRY("ATRAC3", "atrac3_oma", NULL, "oma\0aa3\0" ),
165#endif 168#endif
166}; 169};
167 170
@@ -437,6 +440,13 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
437 return false; 440 return false;
438 } 441 }
439 break; 442 break;
443 case AFMT_OMA_ATRAC3:
444 if (!get_oma_metadata(fd, id3))
445 {
446 DEBUGF("get_oma_metadata error\n");
447 return false;
448 }
449 break;
440 450
441#endif /* CONFIG_CODEC == SWCODEC */ 451#endif /* CONFIG_CODEC == SWCODEC */
442 452
diff --git a/apps/metadata.h b/apps/metadata.h
index 9b9cf9dfd1..b83c5497bf 100644
--- a/apps/metadata.h
+++ b/apps/metadata.h
@@ -77,6 +77,7 @@ enum
77 AFMT_TMC, /* Atari 8bit tmc format */ 77 AFMT_TMC, /* Atari 8bit tmc format */
78 AFMT_TM8, /* Atari 8bit tm8 format */ 78 AFMT_TM8, /* Atari 8bit tm8 format */
79 AFMT_TM2, /* Atari 8bit tm2 format */ 79 AFMT_TM2, /* Atari 8bit tm2 format */
80 AFMT_OMA_ATRAC3, /* Atrac3 in Sony OMA container */
80#endif 81#endif
81 82
82 /* add new formats at any index above this line to have a sensible order - 83 /* add new formats at any index above this line to have a sensible order -
diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h
index e8f1832b87..aa07101269 100644
--- a/apps/metadata/metadata_parsers.h
+++ b/apps/metadata/metadata_parsers.h
@@ -41,4 +41,5 @@ bool get_asf_metadata(int fd, struct mp3entry* id3);
41bool get_asap_metadata(int fd, struct mp3entry* id3); 41bool get_asap_metadata(int fd, struct mp3entry* id3);
42bool get_rm_metadata(int fd, struct mp3entry* id3); 42bool get_rm_metadata(int fd, struct mp3entry* id3);
43bool get_nsf_metadata(int fd, struct mp3entry* id3); 43bool get_nsf_metadata(int fd, struct mp3entry* id3);
44bool get_oma_metadata(int fd, struct mp3entry* id3);
44 45
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. */
86enum {
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. */
100int 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
178bool 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}