summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Nelissen <marcone@google.com>2014-12-17 14:44:33 -0800
committerMarco Nelissen <marcone@google.com>2014-12-18 11:54:42 -0800
commitfaf4efc6a41e88adf85f76f48f020a6d681f5ff1 (patch)
treea54aa43c242bb9c640afcf0d7c8b5f3a2c9e45ab
parent23c8dc13787186dc98731055858b2fba3aedc105 (diff)
downloadframeworks_av-faf4efc6a41e88adf85f76f48f020a6d681f5ff1.zip
frameworks_av-faf4efc6a41e88adf85f76f48f020a6d681f5ff1.tar.gz
frameworks_av-faf4efc6a41e88adf85f76f48f020a6d681f5ff1.tar.bz2
Replace MidiFile player with a Midi extractor
This gets rids of a bunch of special midi handling and replaces it with an extractor that works with NuPlayer and MediaMetadataRetriever. Change-Id: I8d0f5bbdde2ca24267cf4d62ab26afe9630e0217
-rw-r--r--include/media/MediaPlayerInterface.h2
-rw-r--r--include/media/MidiIoWrapper.h4
-rw-r--r--include/media/stagefright/MediaDefs.h1
-rw-r--r--media/libmedia/MidiIoWrapper.cpp14
-rw-r--r--media/libmediaplayerservice/Android.mk2
-rw-r--r--media/libmediaplayerservice/MediaPlayerFactory.cpp67
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp1
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp5
-rw-r--r--media/libmediaplayerservice/MidiFile.cpp541
-rw-r--r--media/libmediaplayerservice/MidiFile.h115
-rw-r--r--media/libmediaplayerservice/MidiMetadataRetriever.cpp96
-rw-r--r--media/libmediaplayerservice/MidiMetadataRetriever.h53
-rw-r--r--media/libstagefright/Android.mk1
-rw-r--r--media/libstagefright/DataSource.cpp2
-rw-r--r--media/libstagefright/MediaDefs.cpp1
-rw-r--r--media/libstagefright/MediaExtractor.cpp3
-rw-r--r--media/libstagefright/MidiExtractor.cpp325
-rw-r--r--media/libstagefright/StagefrightMediaScanner.cpp60
-rw-r--r--media/libstagefright/include/MidiExtractor.h95
19 files changed, 446 insertions, 942 deletions
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index c412299..0fc7dcf 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -43,8 +43,6 @@ class IGraphicBufferProducer;
template<typename T> class SortedVector;
enum player_type {
- PV_PLAYER = 1,
- SONIVOX_PLAYER = 2,
STAGEFRIGHT_PLAYER = 3,
NU_PLAYER = 4,
// Test players are available only in the 'test' and 'eng' builds.
diff --git a/include/media/MidiIoWrapper.h b/include/media/MidiIoWrapper.h
index caf1d75..e6f8cf7 100644
--- a/include/media/MidiIoWrapper.h
+++ b/include/media/MidiIoWrapper.h
@@ -19,12 +19,15 @@
#include <libsonivox/eas_types.h>
+#include "media/stagefright/DataSource.h"
+
namespace android {
class MidiIoWrapper : public RefBase {
public:
MidiIoWrapper(const char *path);
MidiIoWrapper(int fd, off64_t offset, int64_t size);
+ MidiIoWrapper(const sp<DataSource> &source);
~MidiIoWrapper();
@@ -37,6 +40,7 @@ private:
int mFd;
off64_t mBase;
int64_t mLength;
+ sp<DataSource> mDataSource;
EAS_FILE mEasFile;
};
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index e67d4d5..1f9ff45 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -36,6 +36,7 @@ extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG; // layer III
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I;
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
+extern const char *MEDIA_MIMETYPE_AUDIO_MIDI;
extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
extern const char *MEDIA_MIMETYPE_AUDIO_QCELP;
extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS;
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index ef931d2..2181111 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -47,6 +47,16 @@ MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
mLength = size;
}
+MidiIoWrapper::MidiIoWrapper(const sp<DataSource> &source) {
+ mDataSource = source;
+ off64_t l;
+ if (mDataSource->getSize(&l) == OK) {
+ mLength = l;
+ } else {
+ mLength = 0;
+ }
+}
+
MidiIoWrapper::~MidiIoWrapper() {
ALOGV("~MidiIoWrapper");
close(mFd);
@@ -54,6 +64,10 @@ MidiIoWrapper::~MidiIoWrapper() {
int MidiIoWrapper::readAt(void *buffer, int offset, int size) {
ALOGV("readAt(%p, %d, %d)", buffer, offset, size);
+
+ if (mDataSource != NULL) {
+ return mDataSource->readAt(offset, buffer, size);
+ }
lseek(mFd, mBase + offset, SEEK_SET);
if (offset + size > mLength) {
size = mLength - offset;
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 2cf5710..9d8fe62 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -15,8 +15,6 @@ LOCAL_SRC_FILES:= \
MediaPlayerService.cpp \
MediaRecorderClient.cpp \
MetadataRetrieverClient.cpp \
- MidiFile.cpp \
- MidiMetadataRetriever.cpp \
RemoteDisplay.cpp \
SharedLibrary.cpp \
StagefrightPlayer.cpp \
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index c689470..48884b9 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -21,7 +21,6 @@
#include <cutils/properties.h>
#include <media/IMediaPlayer.h>
-#include <media/MidiIoWrapper.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -31,7 +30,6 @@
#include "MediaPlayerFactory.h"
-#include "MidiFile.h"
#include "TestPlayerStub.h"
#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
@@ -281,70 +279,6 @@ class NuPlayerFactory : public MediaPlayerFactory::IFactory {
}
};
-class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory {
- public:
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- const char* url,
- float curScore) {
- static const float kOurScore = 0.4;
- static const char* const FILE_EXTS[] = { ".mid",
- ".midi",
- ".smf",
- ".xmf",
- ".mxmf",
- ".imy",
- ".rtttl",
- ".rtx",
- ".ota" };
- if (kOurScore <= curScore)
- return 0.0;
-
- // use MidiFile for MIDI extensions
- int lenURL = strlen(url);
- for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
- int len = strlen(FILE_EXTS[i]);
- int start = lenURL - len;
- if (start > 0) {
- if (!strncasecmp(url + start, FILE_EXTS[i], len)) {
- return kOurScore;
- }
- }
- }
- return 0.0;
- }
-
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- int fd,
- int64_t offset,
- int64_t length,
- float curScore) {
- static const float kOurScore = 0.8;
-
- if (kOurScore <= curScore)
- return 0.0;
-
- // Some kind of MIDI?
- EAS_DATA_HANDLE easdata;
- sp<MidiIoWrapper> wrapper = new MidiIoWrapper(fd, offset, length);
- if (EAS_Init(&easdata) == EAS_SUCCESS) {
- EAS_HANDLE eashandle;
- if (EAS_OpenFile(easdata, wrapper->getLocator(), &eashandle) == EAS_SUCCESS) {
- EAS_CloseFile(easdata, eashandle);
- EAS_Shutdown(easdata);
- return kOurScore;
- }
- EAS_Shutdown(easdata);
- }
-
- return 0.0;
- }
-
- virtual sp<MediaPlayerBase> createPlayer() {
- ALOGV(" create MidiFile");
- return new MidiFile();
- }
-};
-
class TestPlayerFactory : public MediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
@@ -371,7 +305,6 @@ void MediaPlayerFactory::registerBuiltinFactories() {
registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
- registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
sInitComplete = true;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 071b894..6efdfe4 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -70,7 +70,6 @@
#include "MetadataRetrieverClient.h"
#include "MediaPlayerFactory.h"
-#include "MidiFile.h"
#include "TestPlayerStub.h"
#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index fa28451..715cc0c 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -35,7 +35,6 @@
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/MediaPlayerInterface.h>
#include <private/media/VideoFrame.h>
-#include "MidiMetadataRetriever.h"
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
#include "MediaPlayerFactory.h"
@@ -90,10 +89,6 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
p = new StagefrightMetadataRetriever;
break;
}
- case SONIVOX_PLAYER:
- ALOGV("create midi metadata retriever");
- p = new MidiMetadataRetriever();
- break;
default:
// TODO:
// support for TEST_PLAYER
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
deleted file mode 100644
index 205d44f..0000000
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ /dev/null
@@ -1,541 +0,0 @@
-/* MidiFile.cpp
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MidiFile"
-#include "utils/Log.h"
-
-#include <stdio.h>
-#include <assert.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <utils/threads.h>
-#include <libsonivox/eas_reverb.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <system/audio.h>
-
-#include "MidiFile.h"
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-// The midi engine buffers are a bit small (128 frames), so we batch them up
-static const int NUM_BUFFERS = 4;
-
-// TODO: Determine appropriate return codes
-static status_t ERROR_NOT_OPEN = -1;
-static status_t ERROR_OPEN_FAILED = -2;
-static status_t ERROR_EAS_FAILURE = -3;
-static status_t ERROR_ALLOCATE_FAILED = -4;
-
-static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
-
-MidiFile::MidiFile() :
- mEasData(NULL), mEasHandle(NULL), mAudioBuffer(NULL),
- mPlayTime(-1), mDuration(-1), mState(EAS_STATE_ERROR),
- mStreamType(AUDIO_STREAM_MUSIC), mLoop(false), mExit(false),
- mPaused(false), mRender(false), mTid(-1)
-{
- ALOGV("constructor");
-
- // get the library configuration and do sanity check
- if (pLibConfig == NULL)
- pLibConfig = EAS_Config();
- if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) {
- ALOGE("EAS library/header mismatch");
- goto Failed;
- }
-
- // initialize EAS library
- if (EAS_Init(&mEasData) != EAS_SUCCESS) {
- ALOGE("EAS_Init failed");
- goto Failed;
- }
-
- // select reverb preset and enable
- EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET, EAS_PARAM_REVERB_CHAMBER);
- EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS, EAS_FALSE);
-
- // create playback thread
- {
- Mutex::Autolock l(mMutex);
- mThread = new MidiFileThread(this);
- mThread->run("midithread", ANDROID_PRIORITY_AUDIO);
- mCondition.wait(mMutex);
- ALOGV("thread started");
- }
-
- // indicate success
- if (mTid > 0) {
- ALOGV(" render thread(%d) started", mTid);
- mState = EAS_STATE_READY;
- }
-
-Failed:
- return;
-}
-
-status_t MidiFile::initCheck()
-{
- if (mState == EAS_STATE_ERROR) return ERROR_EAS_FAILURE;
- return NO_ERROR;
-}
-
-MidiFile::~MidiFile() {
- ALOGV("MidiFile destructor");
- release();
-}
-
-status_t MidiFile::setDataSource(
- const sp<IMediaHTTPService> & /*httpService*/,
- const char* path,
- const KeyedVector<String8, String8> *) {
- ALOGV("MidiFile::setDataSource url=%s", path);
- Mutex::Autolock lock(mMutex);
-
- // file still open?
- if (mEasHandle) {
- reset_nosync();
- }
-
- // open file and set paused state
- mIoWrapper = new MidiIoWrapper(path);
- EAS_RESULT result = EAS_OpenFile(mEasData, mIoWrapper->getLocator(), &mEasHandle);
- if (result == EAS_SUCCESS) {
- updateState();
- }
-
- if (result != EAS_SUCCESS) {
- ALOGE("EAS_OpenFile failed: [%d]", (int)result);
- mState = EAS_STATE_ERROR;
- return ERROR_OPEN_FAILED;
- }
-
- mState = EAS_STATE_OPEN;
- mPlayTime = 0;
- return NO_ERROR;
-}
-
-status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length)
-{
- ALOGV("MidiFile::setDataSource fd=%d", fd);
- Mutex::Autolock lock(mMutex);
-
- // file still open?
- if (mEasHandle) {
- reset_nosync();
- }
-
- // open file and set paused state
- mIoWrapper = new MidiIoWrapper(fd, offset, length);
- EAS_RESULT result = EAS_OpenFile(mEasData, mIoWrapper->getLocator(), &mEasHandle);
- updateState();
-
- if (result != EAS_SUCCESS) {
- ALOGE("EAS_OpenFile failed: [%d]", (int)result);
- mState = EAS_STATE_ERROR;
- return ERROR_OPEN_FAILED;
- }
-
- mState = EAS_STATE_OPEN;
- mPlayTime = 0;
- return NO_ERROR;
-}
-
-status_t MidiFile::prepare()
-{
- ALOGV("MidiFile::prepare");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- EAS_RESULT result;
- if ((result = EAS_Prepare(mEasData, mEasHandle)) != EAS_SUCCESS) {
- ALOGE("EAS_Prepare failed: [%ld]", result);
- return ERROR_EAS_FAILURE;
- }
- updateState();
- return NO_ERROR;
-}
-
-status_t MidiFile::prepareAsync()
-{
- ALOGV("MidiFile::prepareAsync");
- status_t ret = prepare();
-
- // don't hold lock during callback
- if (ret == NO_ERROR) {
- sendEvent(MEDIA_PREPARED);
- } else {
- sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ret);
- }
- return ret;
-}
-
-status_t MidiFile::start()
-{
- ALOGV("MidiFile::start");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
-
- // resuming after pause?
- if (mPaused) {
- if (EAS_Resume(mEasData, mEasHandle) != EAS_SUCCESS) {
- return ERROR_EAS_FAILURE;
- }
- mPaused = false;
- updateState();
- }
-
- mRender = true;
- if (mState == EAS_STATE_PLAY) {
- sendEvent(MEDIA_STARTED);
- }
-
- // wake up render thread
- ALOGV(" wakeup render thread");
- mCondition.signal();
- return NO_ERROR;
-}
-
-status_t MidiFile::stop()
-{
- ALOGV("MidiFile::stop");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- if (!mPaused && (mState != EAS_STATE_STOPPED)) {
- EAS_RESULT result = EAS_Pause(mEasData, mEasHandle);
- if (result != EAS_SUCCESS) {
- ALOGE("EAS_Pause returned error %ld", result);
- return ERROR_EAS_FAILURE;
- }
- }
- mPaused = false;
- sendEvent(MEDIA_STOPPED);
- return NO_ERROR;
-}
-
-status_t MidiFile::seekTo(int position)
-{
- ALOGV("MidiFile::seekTo %d", position);
- // hold lock during EAS calls
- {
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- EAS_RESULT result;
- if ((result = EAS_Locate(mEasData, mEasHandle, position, false))
- != EAS_SUCCESS)
- {
- ALOGE("EAS_Locate returned %ld", result);
- return ERROR_EAS_FAILURE;
- }
- EAS_GetLocation(mEasData, mEasHandle, &mPlayTime);
- }
- sendEvent(MEDIA_SEEK_COMPLETE);
- return NO_ERROR;
-}
-
-status_t MidiFile::pause()
-{
- ALOGV("MidiFile::pause");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- if ((mState == EAS_STATE_PAUSING) || (mState == EAS_STATE_PAUSED)) return NO_ERROR;
- if (EAS_Pause(mEasData, mEasHandle) != EAS_SUCCESS) {
- return ERROR_EAS_FAILURE;
- }
- mPaused = true;
- sendEvent(MEDIA_PAUSED);
- return NO_ERROR;
-}
-
-bool MidiFile::isPlaying()
-{
- ALOGV("MidiFile::isPlaying, mState=%d", int(mState));
- if (!mEasHandle || mPaused) return false;
- return (mState == EAS_STATE_PLAY);
-}
-
-status_t MidiFile::getCurrentPosition(int* position)
-{
- ALOGV("MidiFile::getCurrentPosition");
- if (!mEasHandle) {
- ALOGE("getCurrentPosition(): file not open");
- return ERROR_NOT_OPEN;
- }
- if (mPlayTime < 0) {
- ALOGE("getCurrentPosition(): mPlayTime = %ld", mPlayTime);
- return ERROR_EAS_FAILURE;
- }
- *position = mPlayTime;
- return NO_ERROR;
-}
-
-status_t MidiFile::getDuration(int* duration)
-{
-
- ALOGV("MidiFile::getDuration");
- {
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) return ERROR_NOT_OPEN;
- *duration = mDuration;
- }
-
- // if no duration cached, get the duration
- // don't need a lock here because we spin up a new engine
- if (*duration < 0) {
- EAS_I32 temp;
- EAS_DATA_HANDLE easData = NULL;
- EAS_HANDLE easHandle = NULL;
- EAS_RESULT result = EAS_Init(&easData);
- if (result == EAS_SUCCESS) {
- result = EAS_OpenFile(easData, mIoWrapper->getLocator(), &easHandle);
- }
- if (result == EAS_SUCCESS) {
- result = EAS_Prepare(easData, easHandle);
- }
- if (result == EAS_SUCCESS) {
- result = EAS_ParseMetaData(easData, easHandle, &temp);
- }
- if (easHandle) {
- EAS_CloseFile(easData, easHandle);
- }
- if (easData) {
- EAS_Shutdown(easData);
- }
-
- if (result != EAS_SUCCESS) {
- return ERROR_EAS_FAILURE;
- }
-
- // cache successful result
- mDuration = *duration = int(temp);
- }
-
- return NO_ERROR;
-}
-
-status_t MidiFile::release()
-{
- ALOGV("MidiFile::release");
- Mutex::Autolock l(mMutex);
- reset_nosync();
-
- // wait for render thread to exit
- mExit = true;
- mCondition.signal();
-
- // wait for thread to exit
- if (mAudioBuffer) {
- mCondition.wait(mMutex);
- }
-
- // release resources
- if (mEasData) {
- EAS_Shutdown(mEasData);
- mEasData = NULL;
- }
- return NO_ERROR;
-}
-
-status_t MidiFile::reset()
-{
- ALOGV("MidiFile::reset");
- Mutex::Autolock lock(mMutex);
- return reset_nosync();
-}
-
-// call only with mutex held
-status_t MidiFile::reset_nosync()
-{
- ALOGV("MidiFile::reset_nosync");
- sendEvent(MEDIA_STOPPED);
- // close file
- if (mEasHandle) {
- EAS_CloseFile(mEasData, mEasHandle);
- mEasHandle = NULL;
- }
-
- mIoWrapper.clear();
- mPlayTime = -1;
- mDuration = -1;
- mLoop = false;
- mPaused = false;
- mRender = false;
- return NO_ERROR;
-}
-
-status_t MidiFile::setLooping(int loop)
-{
- ALOGV("MidiFile::setLooping");
- Mutex::Autolock lock(mMutex);
- if (!mEasHandle) {
- return ERROR_NOT_OPEN;
- }
- loop = loop ? -1 : 0;
- if (EAS_SetRepeat(mEasData, mEasHandle, loop) != EAS_SUCCESS) {
- return ERROR_EAS_FAILURE;
- }
- return NO_ERROR;
-}
-
-status_t MidiFile::createOutputTrack() {
- if (mAudioSink->open(pLibConfig->sampleRate, pLibConfig->numChannels,
- CHANNEL_MASK_USE_CHANNEL_ORDER, AUDIO_FORMAT_PCM_16_BIT, 2 /*bufferCount*/) != NO_ERROR) {
- ALOGE("mAudioSink open failed");
- return ERROR_OPEN_FAILED;
- }
- return NO_ERROR;
-}
-
-int MidiFile::render() {
- EAS_RESULT result = EAS_FAILURE;
- EAS_I32 count;
- int temp;
- bool audioStarted = false;
-
- ALOGV("MidiFile::render");
-
- // allocate render buffer
- mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS];
- if (!mAudioBuffer) {
- ALOGE("mAudioBuffer allocate failed");
- goto threadExit;
- }
-
- // signal main thread that we started
- {
- Mutex::Autolock l(mMutex);
- mTid = gettid();
- ALOGV("render thread(%d) signal", mTid);
- mCondition.signal();
- }
-
- while (1) {
- mMutex.lock();
-
- // nothing to render, wait for client thread to wake us up
- while (!mRender && !mExit)
- {
- ALOGV("MidiFile::render - signal wait");
- mCondition.wait(mMutex);
- ALOGV("MidiFile::render - signal rx'd");
- }
- if (mExit) {
- mMutex.unlock();
- break;
- }
-
- // render midi data into the input buffer
- //ALOGV("MidiFile::render - rendering audio");
- int num_output = 0;
- EAS_PCM* p = mAudioBuffer;
- for (int i = 0; i < NUM_BUFFERS; i++) {
- result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
- if (result != EAS_SUCCESS) {
- ALOGE("EAS_Render returned %ld", result);
- }
- p += count * pLibConfig->numChannels;
- num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
- }
-
- // update playback state and position
- // ALOGV("MidiFile::render - updating state");
- EAS_GetLocation(mEasData, mEasHandle, &mPlayTime);
- EAS_State(mEasData, mEasHandle, &mState);
- mMutex.unlock();
-
- // create audio output track if necessary
- if (!mAudioSink->ready()) {
- ALOGV("MidiFile::render - create output track");
- if (createOutputTrack() != NO_ERROR)
- goto threadExit;
- }
-
- // Write data to the audio hardware
- // ALOGV("MidiFile::render - writing to audio output");
- if ((temp = mAudioSink->write(mAudioBuffer, num_output)) < 0) {
- ALOGE("Error in writing:%d",temp);
- return temp;
- }
-
- // start audio output if necessary
- if (!audioStarted) {
- //ALOGV("MidiFile::render - starting audio");
- mAudioSink->start();
- audioStarted = true;
- }
-
- // still playing?
- if ((mState == EAS_STATE_STOPPED) || (mState == EAS_STATE_ERROR) ||
- (mState == EAS_STATE_PAUSED))
- {
- switch(mState) {
- case EAS_STATE_STOPPED:
- {
- ALOGV("MidiFile::render - stopped");
- sendEvent(MEDIA_PLAYBACK_COMPLETE);
- break;
- }
- case EAS_STATE_ERROR:
- {
- ALOGE("MidiFile::render - error");
- sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN);
- break;
- }
- case EAS_STATE_PAUSED:
- ALOGV("MidiFile::render - paused");
- break;
- default:
- break;
- }
- mAudioSink->stop();
- audioStarted = false;
- mRender = false;
- }
- }
-
-threadExit:
- mAudioSink.clear();
- if (mAudioBuffer) {
- delete [] mAudioBuffer;
- mAudioBuffer = NULL;
- }
- mMutex.lock();
- mTid = -1;
- mCondition.signal();
- mMutex.unlock();
- return result;
-}
-
-} // end namespace android
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
deleted file mode 100644
index 48a42aa..0000000
--- a/media/libmediaplayerservice/MidiFile.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_MIDIFILE_H
-#define ANDROID_MIDIFILE_H
-
-#include <media/MediaPlayerInterface.h>
-#include <libsonivox/eas.h>
-#include <media/MidiIoWrapper.h>
-
-namespace android {
-
-// Note that the name MidiFile is misleading; this actually represents a MIDI file player
-class MidiFile : public MediaPlayerInterface {
-public:
- MidiFile();
- ~MidiFile();
-
- virtual status_t initCheck();
-
- virtual status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char* path,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setVideoSurfaceTexture(
- const sp<IGraphicBufferProducer>& /*bufferProducer*/)
- { return UNKNOWN_ERROR; }
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t seekTo(int msec);
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t getCurrentPosition(int* msec);
- virtual status_t getDuration(int* msec);
- virtual status_t release();
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType() { return SONIVOX_PLAYER; }
- virtual status_t invoke(const Parcel& /*request*/, Parcel* /*reply*/) {
- return INVALID_OPERATION;
- }
- virtual status_t setParameter(int /*key*/, const Parcel &/*request*/) {
- return INVALID_OPERATION;
- }
- virtual status_t getParameter(int /*key*/, Parcel* /*reply*/) {
- return INVALID_OPERATION;
- }
-
-private:
- status_t createOutputTrack();
- status_t reset_nosync();
- int render();
- void updateState(){ EAS_State(mEasData, mEasHandle, &mState); }
-
- Mutex mMutex;
- Condition mCondition;
- EAS_DATA_HANDLE mEasData;
- EAS_HANDLE mEasHandle;
- EAS_PCM* mAudioBuffer;
- EAS_I32 mPlayTime;
- EAS_I32 mDuration;
- EAS_STATE mState;
- sp<MidiIoWrapper> mIoWrapper;
- audio_stream_type_t mStreamType;
- bool mLoop;
- volatile bool mExit;
- bool mPaused;
- volatile bool mRender;
- pid_t mTid;
-
- class MidiFileThread : public Thread {
- public:
- MidiFileThread(MidiFile *midiPlayer) : mMidiFile(midiPlayer) {
- }
-
- protected:
- virtual ~MidiFileThread() {}
-
- private:
- MidiFile *mMidiFile;
-
- bool threadLoop() {
- int result;
- result = mMidiFile->render();
- return false;
- }
-
- MidiFileThread(const MidiFileThread &);
- MidiFileThread &operator=(const MidiFileThread &);
- };
-
- sp<MidiFileThread> mThread;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MIDIFILE_H
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
deleted file mode 100644
index f3cf6ef..0000000
--- a/media/libmediaplayerservice/MidiMetadataRetriever.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MidiMetadataRetriever"
-#include <utils/Log.h>
-
-#include "MidiMetadataRetriever.h"
-#include <media/mediametadataretriever.h>
-
-#include <media/IMediaHTTPService.h>
-
-namespace android {
-
-static status_t ERROR_NOT_OPEN = -1;
-static status_t ERROR_OPEN_FAILED = -2;
-static status_t ERROR_EAS_FAILURE = -3;
-static status_t ERROR_ALLOCATE_FAILED = -4;
-
-void MidiMetadataRetriever::clearMetadataValues()
-{
- ALOGV("clearMetadataValues");
- mMetadataValues[0][0] = '\0';
-}
-
-status_t MidiMetadataRetriever::setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers)
-{
- ALOGV("setDataSource: %s", url? url: "NULL pointer");
- Mutex::Autolock lock(mLock);
- clearMetadataValues();
- if (mMidiPlayer == 0) {
- mMidiPlayer = new MidiFile();
- }
- return mMidiPlayer->setDataSource(httpService, url, headers);
-}
-
-status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
-{
- ALOGV("setDataSource: fd(%d), offset(%lld), and length(%lld)", fd, offset, length);
- Mutex::Autolock lock(mLock);
- clearMetadataValues();
- if (mMidiPlayer == 0) {
- mMidiPlayer = new MidiFile();
- }
- return mMidiPlayer->setDataSource(fd, offset, length);;
-}
-
-const char* MidiMetadataRetriever::extractMetadata(int keyCode)
-{
- ALOGV("extractMetdata: key(%d)", keyCode);
- Mutex::Autolock lock(mLock);
- if (mMidiPlayer == 0 || mMidiPlayer->initCheck() != NO_ERROR) {
- ALOGE("Midi player is not initialized yet");
- return NULL;
- }
- switch (keyCode) {
- case METADATA_KEY_DURATION:
- {
- if (mMetadataValues[0][0] == '\0') {
- int duration = -1;
- if (mMidiPlayer->getDuration(&duration) != NO_ERROR) {
- ALOGE("failed to get duration");
- return NULL;
- }
- snprintf(mMetadataValues[0], MAX_METADATA_STRING_LENGTH, "%d", duration);
- }
-
- ALOGV("duration: %s ms", mMetadataValues[0]);
- return mMetadataValues[0];
- }
- default:
- ALOGE("Unsupported key code (%d)", keyCode);
- return NULL;
- }
- return NULL;
-}
-
-};
-
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.h b/media/libmediaplayerservice/MidiMetadataRetriever.h
deleted file mode 100644
index b8214ee..0000000
--- a/media/libmediaplayerservice/MidiMetadataRetriever.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_MIDIMETADATARETRIEVER_H
-#define ANDROID_MIDIMETADATARETRIEVER_H
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <media/MediaMetadataRetrieverInterface.h>
-
-#include "MidiFile.h"
-
-namespace android {
-
-class MidiMetadataRetriever : public MediaMetadataRetrieverInterface {
-public:
- MidiMetadataRetriever() {}
- ~MidiMetadataRetriever() {}
-
- virtual status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual const char* extractMetadata(int keyCode);
-
-private:
- static const uint32_t MAX_METADATA_STRING_LENGTH = 128;
- void clearMetadataValues();
-
- Mutex mLock;
- sp<MidiFile> mMidiPlayer;
- char mMetadataValues[1][MAX_METADATA_STRING_LENGTH];
-};
-
-}; // namespace android
-
-#endif // ANDROID_MIDIMETADATARETRIEVER_H
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 1810031..609847c 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -36,6 +36,7 @@ LOCAL_SRC_FILES:= \
MediaCodecSource.cpp \
MediaDefs.cpp \
MediaExtractor.cpp \
+ MidiExtractor.cpp \
http/MediaHTTP.cpp \
MediaMuxer.cpp \
MediaSource.cpp \
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index c99db84..f7dcf35 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -22,6 +22,7 @@
#include "include/DRMExtractor.h"
#include "include/FLACExtractor.h"
#include "include/HTTPBase.h"
+#include "include/MidiExtractor.h"
#include "include/MP3Extractor.h"
#include "include/MPEG2PSExtractor.h"
#include "include/MPEG2TSExtractor.h"
@@ -172,6 +173,7 @@ void DataSource::RegisterDefaultSniffers() {
RegisterSniffer_l(SniffAAC);
RegisterSniffer_l(SniffMPEG2PS);
RegisterSniffer_l(SniffWVM);
+ RegisterSniffer_l(SniffMidi);
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index d48dd84..fde6fbd 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -34,6 +34,7 @@ const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I = "audio/mpeg-L1";
const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II = "audio/mpeg-L2";
+const char *MEDIA_MIMETYPE_AUDIO_MIDI = "audio/midi";
const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp";
const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 9ab6611..e21fe6e 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -29,6 +29,7 @@
#include "include/WVMExtractor.h"
#include "include/FLACExtractor.h"
#include "include/AACExtractor.h"
+#include "include/MidiExtractor.h"
#include "matroska/MatroskaExtractor.h"
@@ -116,6 +117,8 @@ sp<MediaExtractor> MediaExtractor::Create(
ret = new AACExtractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
ret = new MPEG2PSExtractor(source);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
+ ret = new MidiExtractor(source);
}
if (ret != NULL) {
diff --git a/media/libstagefright/MidiExtractor.cpp b/media/libstagefright/MidiExtractor.cpp
new file mode 100644
index 0000000..66fab77
--- /dev/null
+++ b/media/libstagefright/MidiExtractor.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MidiExtractor"
+#include <utils/Log.h>
+
+#include "include/MidiExtractor.h"
+
+#include <media/MidiIoWrapper.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaSource.h>
+#include <libsonivox/eas_reverb.h>
+
+namespace android {
+
+// how many Sonivox output buffers to aggregate into one MediaBuffer
+static const int NUM_COMBINE_BUFFERS = 4;
+
+class MidiSource : public MediaSource {
+
+public:
+ MidiSource(
+ const sp<MidiEngine> &engine,
+ const sp<MetaData> &trackMetadata);
+
+ virtual status_t start(MetaData *params);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+ virtual ~MidiSource();
+
+private:
+ sp<MidiEngine> mEngine;
+ sp<MetaData> mTrackMetadata;
+ bool mInitCheck;
+ bool mStarted;
+
+ status_t init();
+
+ // no copy constructor or assignment
+ MidiSource(const MidiSource &);
+ MidiSource &operator=(const MidiSource &);
+
+};
+
+
+// Midisource
+
+MidiSource::MidiSource(
+ const sp<MidiEngine> &engine,
+ const sp<MetaData> &trackMetadata)
+ : mEngine(engine),
+ mTrackMetadata(trackMetadata),
+ mInitCheck(false),
+ mStarted(false)
+{
+ ALOGV("MidiSource ctor");
+ mInitCheck = init();
+}
+
+MidiSource::~MidiSource()
+{
+ ALOGV("MidiSource dtor");
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t MidiSource::start(MetaData * /* params */)
+{
+ ALOGV("MidiSource::start");
+
+ CHECK(!mStarted);
+ mStarted = true;
+ mEngine->allocateBuffers();
+ return OK;
+}
+
+status_t MidiSource::stop()
+{
+ ALOGV("MidiSource::stop");
+
+ CHECK(mStarted);
+ mStarted = false;
+ mEngine->releaseBuffers();
+
+ return OK;
+}
+
+sp<MetaData> MidiSource::getFormat()
+{
+ return mTrackMetadata;
+}
+
+status_t MidiSource::read(
+ MediaBuffer **outBuffer, const ReadOptions *options)
+{
+ ALOGV("MidiSource::read");
+ MediaBuffer *buffer;
+ // process an optional seek request
+ int64_t seekTimeUs;
+ ReadOptions::SeekMode mode;
+ if ((NULL != options) && options->getSeekTo(&seekTimeUs, &mode)) {
+ if (seekTimeUs <= 0LL) {
+ seekTimeUs = 0LL;
+ }
+ mEngine->seekTo(seekTimeUs);
+ }
+ buffer = mEngine->readBuffer();
+ *outBuffer = buffer;
+ ALOGV("MidiSource::read %p done", this);
+ return buffer != NULL ? (status_t) OK : (status_t) ERROR_END_OF_STREAM;
+}
+
+status_t MidiSource::init()
+{
+ ALOGV("MidiSource::init");
+ return OK;
+}
+
+// MidiEngine
+
+MidiEngine::MidiEngine(const sp<DataSource> &dataSource,
+ const sp<MetaData> &fileMetadata,
+ const sp<MetaData> &trackMetadata) :
+ mGroup(NULL),
+ mEasData(NULL),
+ mEasHandle(NULL),
+ mEasConfig(NULL),
+ mIsInitialized(false) {
+ mIoWrapper = new MidiIoWrapper(dataSource);
+ // spin up a new EAS engine
+ EAS_I32 temp;
+ EAS_RESULT result = EAS_Init(&mEasData);
+
+ if (result == EAS_SUCCESS) {
+ result = EAS_OpenFile(mEasData, mIoWrapper->getLocator(), &mEasHandle);
+ }
+ if (result == EAS_SUCCESS) {
+ result = EAS_Prepare(mEasData, mEasHandle);
+ }
+ if (result == EAS_SUCCESS) {
+ result = EAS_ParseMetaData(mEasData, mEasHandle, &temp);
+ }
+
+ if (result != EAS_SUCCESS) {
+ return;
+ }
+
+ if (fileMetadata != NULL) {
+ fileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MIDI);
+ }
+
+ if (trackMetadata != NULL) {
+ trackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+ trackMetadata->setInt64(kKeyDuration, 1000ll * temp); // milli->micro
+ mEasConfig = EAS_Config();
+ trackMetadata->setInt32(kKeySampleRate, mEasConfig->sampleRate);
+ trackMetadata->setInt32(kKeyChannelCount, mEasConfig->numChannels);
+ }
+ mIsInitialized = true;
+}
+
+MidiEngine::~MidiEngine() {
+ if (mEasHandle) {
+ EAS_CloseFile(mEasData, mEasHandle);
+ }
+ if (mEasData) {
+ EAS_Shutdown(mEasData);
+ }
+ delete mGroup;
+
+}
+
+status_t MidiEngine::initCheck() {
+ return mIsInitialized ? OK : UNKNOWN_ERROR;
+}
+
+status_t MidiEngine::allocateBuffers() {
+ // select reverb preset and enable
+ EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET, EAS_PARAM_REVERB_CHAMBER);
+ EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS, EAS_FALSE);
+
+ mGroup = new MediaBufferGroup;
+ int bufsize = sizeof(EAS_PCM)
+ * mEasConfig->mixBufferSize * mEasConfig->numChannels * NUM_COMBINE_BUFFERS;
+ ALOGV("using %d byte buffer", bufsize);
+ mGroup->add_buffer(new MediaBuffer(bufsize));
+ return OK;
+}
+
+status_t MidiEngine::releaseBuffers() {
+ delete mGroup;
+ mGroup = NULL;
+ return OK;
+}
+
+status_t MidiEngine::seekTo(int64_t positionUs) {
+ ALOGV("seekTo %lld", positionUs);
+ EAS_RESULT result = EAS_Locate(mEasData, mEasHandle, positionUs / 1000, false);
+ return result == EAS_SUCCESS ? OK : UNKNOWN_ERROR;
+}
+
+MediaBuffer* MidiEngine::readBuffer() {
+ EAS_STATE state;
+ EAS_State(mEasData, mEasHandle, &state);
+ if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) {
+ return NULL;
+ }
+ MediaBuffer *buffer;
+ status_t err = mGroup->acquire_buffer(&buffer);
+ if (err != OK) {
+ ALOGE("readBuffer: no buffer");
+ return NULL;
+ }
+ EAS_I32 timeMs;
+ EAS_GetLocation(mEasData, mEasHandle, &timeMs);
+ int64_t timeUs = 1000ll * timeMs;
+ buffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+ EAS_PCM* p = (EAS_PCM*) buffer->data();
+ int numBytesOutput = 0;
+ for (int i = 0; i < NUM_COMBINE_BUFFERS; i++) {
+ EAS_I32 numRendered;
+ EAS_RESULT result = EAS_Render(mEasData, p, mEasConfig->mixBufferSize, &numRendered);
+ if (result != EAS_SUCCESS) {
+ ALOGE("EAS_Render returned %ld", result);
+ break;
+ }
+ p += numRendered * mEasConfig->numChannels;
+ numBytesOutput += numRendered * mEasConfig->numChannels * sizeof(EAS_PCM);
+ }
+ buffer->set_range(0, numBytesOutput);
+ ALOGV("readBuffer: returning %zd in buffer %p", buffer->range_length(), buffer);
+ return buffer;
+}
+
+
+// MidiExtractor
+
+MidiExtractor::MidiExtractor(
+ const sp<DataSource> &dataSource)
+ : mDataSource(dataSource),
+ mInitCheck(false)
+{
+ ALOGV("MidiExtractor ctor");
+ mFileMetadata = new MetaData;
+ mTrackMetadata = new MetaData;
+ mEngine = new MidiEngine(mDataSource, mFileMetadata, mTrackMetadata);
+ mInitCheck = mEngine->initCheck();
+}
+
+MidiExtractor::~MidiExtractor()
+{
+ ALOGV("MidiExtractor dtor");
+}
+
+size_t MidiExtractor::countTracks()
+{
+ return mInitCheck == OK ? 1 : 0;
+}
+
+sp<MediaSource> MidiExtractor::getTrack(size_t index)
+{
+ if (mInitCheck != OK || index > 0) {
+ return NULL;
+ }
+ return new MidiSource(mEngine, mTrackMetadata);
+}
+
+sp<MetaData> MidiExtractor::getTrackMetaData(
+ size_t index, uint32_t /* flags */) {
+ ALOGV("MidiExtractor::getTrackMetaData");
+ if (mInitCheck != OK || index > 0) {
+ return NULL;
+ }
+ return mTrackMetadata;
+}
+
+sp<MetaData> MidiExtractor::getMetaData()
+{
+ ALOGV("MidiExtractor::getMetaData");
+ return mFileMetadata;
+}
+
+// Sniffer
+
+bool SniffMidi(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *)
+{
+ sp<MidiEngine> p = new MidiEngine(source, NULL, NULL);
+ if (p->initCheck() == OK) {
+ *mimeType = MEDIA_MIMETYPE_AUDIO_MIDI;
+ *confidence = 0.8;
+ ALOGV("SniffMidi: yes");
+ return true;
+ }
+ ALOGV("SniffMidi: no");
+ return false;
+
+}
+
+} // namespace android
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 6ded3a7..db33e83 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -26,12 +26,8 @@
#include <media/IMediaHTTPService.h>
#include <media/mediametadataretriever.h>
-#include <media/MidiIoWrapper.h>
#include <private/media/VideoFrame.h>
-// Sonivox includes
-#include <libsonivox/eas.h>
-
namespace android {
StagefrightMediaScanner::StagefrightMediaScanner() {}
@@ -58,50 +54,6 @@ static bool FileHasAcceptableExtension(const char *extension) {
return false;
}
-static MediaScanResult HandleMIDI(
- const char *filename, MediaScannerClient *client) {
- // get the library configuration and do sanity check
- const S_EAS_LIB_CONFIG* pLibConfig = EAS_Config();
- if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) {
- ALOGE("EAS library/header mismatch\n");
- return MEDIA_SCAN_RESULT_ERROR;
- }
- EAS_I32 temp;
-
- // spin up a new EAS engine
- EAS_DATA_HANDLE easData = NULL;
- EAS_HANDLE easHandle = NULL;
- EAS_RESULT result = EAS_Init(&easData);
- MidiIoWrapper wrapper(filename);
- if (result == EAS_SUCCESS) {
- result = EAS_OpenFile(easData, wrapper.getLocator(), &easHandle);
- }
- if (result == EAS_SUCCESS) {
- result = EAS_Prepare(easData, easHandle);
- }
- if (result == EAS_SUCCESS) {
- result = EAS_ParseMetaData(easData, easHandle, &temp);
- }
- if (easHandle) {
- EAS_CloseFile(easData, easHandle);
- }
- if (easData) {
- EAS_Shutdown(easData);
- }
-
- if (result != EAS_SUCCESS) {
- return MEDIA_SCAN_RESULT_SKIPPED;
- }
-
- char buffer[20];
- sprintf(buffer, "%ld", temp);
- status_t status = client->addStringTag("duration", buffer);
- if (status != OK) {
- return MEDIA_SCAN_RESULT_ERROR;
- }
- return MEDIA_SCAN_RESULT_OK;
-}
-
MediaScanResult StagefrightMediaScanner::processFile(
const char *path, const char *mimeType,
MediaScannerClient &client) {
@@ -127,18 +79,6 @@ MediaScanResult StagefrightMediaScanner::processFileInternal(
return MEDIA_SCAN_RESULT_SKIPPED;
}
- if (!strcasecmp(extension, ".mid")
- || !strcasecmp(extension, ".smf")
- || !strcasecmp(extension, ".imy")
- || !strcasecmp(extension, ".midi")
- || !strcasecmp(extension, ".xmf")
- || !strcasecmp(extension, ".rtttl")
- || !strcasecmp(extension, ".rtx")
- || !strcasecmp(extension, ".ota")
- || !strcasecmp(extension, ".mxmf")) {
- return HandleMIDI(path, &client);
- }
-
sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
int fd = open(path, O_RDONLY | O_LARGEFILE);
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/libstagefright/include/MidiExtractor.h
new file mode 100644
index 0000000..9a2abc0
--- /dev/null
+++ b/media/libstagefright/include/MidiExtractor.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MIDI_EXTRACTOR_H_
+#define MIDI_EXTRACTOR_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/MidiIoWrapper.h>
+#include <utils/String8.h>
+#include <libsonivox/eas.h>
+
+namespace android {
+
+class MidiEngine : public RefBase {
+public:
+ MidiEngine(const sp<DataSource> &dataSource,
+ const sp<MetaData> &fileMetadata,
+ const sp<MetaData> &trackMetadata);
+ ~MidiEngine();
+
+ status_t initCheck();
+
+ status_t allocateBuffers();
+ status_t releaseBuffers();
+ status_t seekTo(int64_t positionUs);
+ MediaBuffer* readBuffer();
+private:
+ sp<MidiIoWrapper> mIoWrapper;
+ MediaBufferGroup *mGroup;
+ EAS_DATA_HANDLE mEasData;
+ EAS_HANDLE mEasHandle;
+ const S_EAS_LIB_CONFIG* mEasConfig;
+ bool mIsInitialized;
+};
+
+class MidiExtractor : public MediaExtractor {
+
+public:
+ // Extractor assumes ownership of source
+ MidiExtractor(const sp<DataSource> &source);
+
+ virtual size_t countTracks();
+ virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+ virtual sp<MetaData> getMetaData();
+
+protected:
+ virtual ~MidiExtractor();
+
+private:
+ sp<DataSource> mDataSource;
+ status_t mInitCheck;
+ sp<MetaData> mFileMetadata;
+
+ // There is only one track
+ sp<MetaData> mTrackMetadata;
+
+ sp<MidiEngine> mEngine;
+
+ EAS_DATA_HANDLE mEasData;
+ EAS_HANDLE mEasHandle;
+ EAS_PCM* mAudioBuffer;
+ EAS_I32 mPlayTime;
+ EAS_I32 mDuration;
+ EAS_STATE mState;
+ EAS_FILE mFileLocator;
+
+ MidiExtractor(const MidiExtractor &);
+ MidiExtractor &operator=(const MidiExtractor &);
+
+};
+
+bool SniffMidi(const sp<DataSource> &source, String8 *mimeType,
+ float *confidence, sp<AMessage> *);
+
+} // namespace android
+
+#endif // MIDI_EXTRACTOR_H_