summaryrefslogtreecommitdiffstats
path: root/apps/metadata
diff options
context:
space:
mode:
Diffstat (limited to 'apps/metadata')
-rw-r--r--apps/metadata/metadata_parsers.h1
-rw-r--r--apps/metadata/oma.c188
2 files changed, 189 insertions, 0 deletions
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);
bool get_asap_metadata(int fd, struct mp3entry* id3);
bool get_rm_metadata(int fd, struct mp3entry* id3);
bool get_nsf_metadata(int fd, struct mp3entry* id3);
+bool get_oma_metadata(int fd, struct mp3entry* id3);
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 @@
+/*
+ * Sony OpenMG (OMA) demuxer
+ *
+ * Copyright (c) 2008 Maxim Poliakovski
+ * 2008 Benjamin Larsson
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file oma.c
+ * This is a demuxer for Sony OpenMG Music files
+ *
+ * Known file extensions: ".oma", "aa3"
+ * The format of such files consists of three parts:
+ * - "ea3" header carrying overall info and metadata.
+ * - "EA3" header is a Sony-specific header containing information about
+ * the OpenMG file: codec type (usually ATRAC, can also be MP3 or WMA),
+ * codec specific info (packet size, sample rate, channels and so on)
+ * and DRM related info (file encryption, content id).
+ * - Sound data organized in packets follow the EA3 header
+ * (can be encrypted using the Sony DRM!).
+ *
+ * LIMITATIONS: This version supports only plain (unencrypted) OMA files.
+ * If any DRM-protected (encrypted) file is encountered you will get the
+ * corresponding error message. Try to remove the encryption using any
+ * Sony software (for example SonicStage).
+ * CODEC SUPPORT: Only ATRAC3 codec is currently supported!
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include "metadata.h"
+#include "metadata_parsers.h"
+
+#define EA3_HEADER_SIZE 96
+
+#if 0
+#define DEBUGF printf
+#else
+#define DEBUGF(...)
+#endif
+
+/* Various helper macros taken from ffmpeg for reading *
+ * and writing buffers with a specified endianess. */
+# define AV_RB16(x) \
+ ((((const uint8_t*)(x))[0] << 8) | \
+ ((const uint8_t*)(x))[1])
+# define AV_RB24(x) \
+ ((((const uint8_t*)(x))[0] << 16) | \
+ (((const uint8_t*)(x))[1] << 8) | \
+ ((const uint8_t*)(x))[2])
+# define AV_RB32(x) \
+ ((((const uint8_t*)(x))[0] << 24) | \
+ (((const uint8_t*)(x))[1] << 16) | \
+ (((const uint8_t*)(x))[2] << 8) | \
+ ((const uint8_t*)(x))[3])
+# define AV_WL32(p, d) do { \
+ ((uint8_t*)(p))[0] = (d); \
+ ((uint8_t*)(p))[1] = (d)>>8; \
+ ((uint8_t*)(p))[2] = (d)>>16; \
+ ((uint8_t*)(p))[3] = (d)>>24; \
+ } while(0)
+# define AV_WL16(p, d) do { \
+ ((uint8_t*)(p))[0] = (d); \
+ ((uint8_t*)(p))[1] = (d)>>8; \
+ } while(0)
+
+/* Different codecs that could be present in a Sony OMA *
+ * container file. */
+enum {
+ OMA_CODECID_ATRAC3 = 0,
+ OMA_CODECID_ATRAC3P = 1,
+ OMA_CODECID_MP3 = 3,
+ OMA_CODECID_LPCM = 4,
+ OMA_CODECID_WMA = 5,
+};
+
+/* FIXME: This functions currently read different file *
+ * parameters required for decoding. It still *
+ * does not read the metadata - which should be *
+ * present in the ea3 (first) header. The *
+ * metadata in ea3 is stored as a variation of *
+ * the ID3v2 metadata format. */
+int oma_read_header(int fd, struct mp3entry* id3)
+{
+ static const uint16_t srate_tab[6] = {320,441,480,882,960,0};
+ int ret, ea3_taglen, EA3_pos, jsflag;
+ uint32_t codec_params;
+ int16_t eid;
+ uint8_t buf[EA3_HEADER_SIZE];
+
+ ret = read(fd, buf, 10);
+ if (ret != 10)
+ return -1;
+
+ ea3_taglen = ((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f);
+
+ EA3_pos = ea3_taglen + 10;
+ if (buf[5] & 0x10)
+ EA3_pos += 10;
+
+ lseek(fd, EA3_pos, SEEK_SET);
+ ret = read(fd, buf, EA3_HEADER_SIZE);
+ if (ret != EA3_HEADER_SIZE)
+ return -1;
+
+ if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}),3) || buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) {
+ DEBUGF("Couldn't find the EA3 header !\n");
+ return -1;
+ }
+
+ eid = AV_RB16(&buf[6]);
+ if (eid != -1 && eid != -128) {
+ DEBUGF("Encrypted file! Eid: %d\n", eid);
+ return -1;
+ }
+
+ codec_params = AV_RB24(&buf[33]);
+
+ switch (buf[32]) {
+ case OMA_CODECID_ATRAC3:
+ id3->frequency = srate_tab[(codec_params >> 13) & 7]*100;
+ if (id3->frequency != 44100) {
+ DEBUGF("Unsupported sample rate, send sample file to developers: %d\n", samplerate);
+ return -1;
+ }
+
+ id3->bytesperframe = (codec_params & 0x3FF) * 8;
+ id3->codectype = AFMT_OMA_ATRAC3;
+ jsflag = (codec_params >> 17) & 1; /* get stereo coding mode, 1 for joint-stereo */
+
+ id3->bitrate = id3->frequency * id3->bytesperframe * 8 / (1024 * 1000);
+
+ /* fake the atrac3 extradata (wav format, makes stream copy to wav work) */
+ /* ATRAC3 expects and extra-data size of 14 bytes for wav format; extra-data size *
+ * is stored in ATRAC3Context before initializing the decoder. See atrac3_oma.codec. *
+ * We use id3v2buf to hold the (fake) extra-data provided from the container. */
+
+ AV_WL16(&id3->id3v1buf[0][0], 1); // always 1
+ AV_WL32(&id3->id3v1buf[0][2], id3->frequency); // samples rate
+ AV_WL16(&id3->id3v1buf[0][6], jsflag); // coding mode
+ AV_WL16(&id3->id3v1buf[0][8], jsflag); // coding mode
+ AV_WL16(&id3->id3v1buf[0][10], 1); // always 1
+ AV_WL16(&id3->id3v1buf[0][12], 0); // always 0
+
+ DEBUGF("sample_rate = %d\n", id3->frequency);
+ DEBUGF("frame_size = %d\n", id3->bytesperframe);
+ DEBUGF("stereo_coding_mode = %d\n", jsflag);
+ break;
+ default:
+ DEBUGF("Unsupported codec %d!\n",buf[32]);
+ return -1;
+ break;
+ }
+
+ /* Store the the offset of the first audio frame, to be able to seek to it *
+ * directly in atrac3_oma.codec. */
+ id3->first_frame_offset = EA3_pos + EA3_HEADER_SIZE;
+ return 0;
+}
+
+bool get_oma_metadata(int fd, struct mp3entry* id3)
+{
+ if(oma_read_header(fd, id3) < 0)
+ return false;
+
+ /* Currently, there's no means of knowing the duration *
+ * directly from the the file so we calculate it. */
+ id3->filesize = filesize(fd);
+ id3->length = ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate;
+ return true;
+}