From 0e8928bf4f2b01b783f6da97d15e8f1abb0fd7d7 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 8 Jan 2015 13:40:53 -0800 Subject: 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 --- include/media/MediaPlayerInterface.h | 2 - include/media/MidiIoWrapper.h | 4 + include/media/stagefright/MediaDefs.h | 1 + media/libmedia/MidiIoWrapper.cpp | 14 + media/libmediaplayerservice/Android.mk | 2 - media/libmediaplayerservice/MediaPlayerFactory.cpp | 67 --- media/libmediaplayerservice/MediaPlayerService.cpp | 1 - .../MetadataRetrieverClient.cpp | 5 - media/libmediaplayerservice/MidiFile.cpp | 541 --------------------- media/libmediaplayerservice/MidiFile.h | 115 ----- .../MidiMetadataRetriever.cpp | 96 ---- .../libmediaplayerservice/MidiMetadataRetriever.h | 53 -- media/libstagefright/Android.mk | 1 + media/libstagefright/DataSource.cpp | 2 + media/libstagefright/MediaDefs.cpp | 1 + media/libstagefright/MediaExtractor.cpp | 3 + media/libstagefright/MidiExtractor.cpp | 325 +++++++++++++ media/libstagefright/StagefrightMediaScanner.cpp | 60 --- media/libstagefright/include/MidiExtractor.h | 95 ++++ 19 files changed, 446 insertions(+), 942 deletions(-) delete mode 100644 media/libmediaplayerservice/MidiFile.cpp delete mode 100644 media/libmediaplayerservice/MidiFile.h delete mode 100644 media/libmediaplayerservice/MidiMetadataRetriever.cpp delete mode 100644 media/libmediaplayerservice/MidiMetadataRetriever.h create mode 100644 media/libstagefright/MidiExtractor.cpp create mode 100644 media/libstagefright/include/MidiExtractor.h diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h index cf18a45..0f38c16 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -43,8 +43,6 @@ class IGraphicBufferProducer; template 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 +#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 &source); ~MidiIoWrapper(); @@ -37,6 +40,7 @@ private: int mFd; off64_t mBase; int64_t mLength; + sp 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 &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 d149290..89a9ddf 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -30,7 +29,6 @@ #include "MediaPlayerFactory.h" -#include "MidiFile.h" #include "TestPlayerStub.h" #include "StagefrightPlayer.h" #include "nuplayer/NuPlayerDriver.h" @@ -254,70 +252,6 @@ class NuPlayerFactory : public MediaPlayerFactory::IFactory { } }; -class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory { - public: - virtual float scoreFactory(const sp& /*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& /*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 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 createPlayer() { - ALOGV(" create MidiFile"); - return new MidiFile(); - } -}; - class TestPlayerFactory : public MediaPlayerFactory::IFactory { public: virtual float scoreFactory(const sp& /*client*/, @@ -344,7 +278,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 6ea522c..4d88a7f 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 #include #include -#include "MidiMetadataRetriever.h" #include "MetadataRetrieverClient.h" #include "StagefrightMetadataRetriever.h" #include "MediaPlayerFactory.h" @@ -90,10 +89,6 @@ static sp 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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 & /*httpService*/, - const char* path, - const KeyedVector *) { - 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 -#include -#include - -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 &httpService, - const char* path, - const KeyedVector *headers); - - virtual status_t setDataSource(int fd, int64_t offset, int64_t length); - virtual status_t setVideoSurfaceTexture( - const sp& /*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 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 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 - -#include "MidiMetadataRetriever.h" -#include - -#include - -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 &httpService, - const char *url, - const KeyedVector *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 -#include -#include - -#include "MidiFile.h" - -namespace android { - -class MidiMetadataRetriever : public MediaMetadataRetrieverInterface { -public: - MidiMetadataRetriever() {} - ~MidiMetadataRetriever() {} - - virtual status_t setDataSource( - const sp &httpService, - const char *url, - const KeyedVector *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 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 7bfd2fb..2629afc 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::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 + +#include "include/MidiExtractor.h" + +#include +#include +#include +#include +#include +#include +#include + +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 &engine, + const sp &trackMetadata); + + virtual status_t start(MetaData *params); + virtual status_t stop(); + virtual sp getFormat(); + + virtual status_t read( + MediaBuffer **buffer, const ReadOptions *options = NULL); + +protected: + virtual ~MidiSource(); + +private: + sp mEngine; + sp 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 &engine, + const sp &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 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, + const sp &fileMetadata, + const sp &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) + : 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 MidiExtractor::getTrack(size_t index) +{ + if (mInitCheck != OK || index > 0) { + return NULL; + } + return new MidiSource(mEngine, mTrackMetadata); +} + +sp MidiExtractor::getTrackMetaData( + size_t index, uint32_t /* flags */) { + ALOGV("MidiExtractor::getTrackMetaData"); + if (mInitCheck != OK || index > 0) { + return NULL; + } + return mTrackMetadata; +} + +sp MidiExtractor::getMetaData() +{ + ALOGV("MidiExtractor::getMetaData"); + return mFileMetadata; +} + +// Sniffer + +bool SniffMidi( + const sp &source, String8 *mimeType, float *confidence, + sp *) +{ + sp 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 #include -#include #include -// Sonivox includes -#include - 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 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 +#include +#include +#include +#include +#include +#include + +namespace android { + +class MidiEngine : public RefBase { +public: + MidiEngine(const sp &dataSource, + const sp &fileMetadata, + const sp &trackMetadata); + ~MidiEngine(); + + status_t initCheck(); + + status_t allocateBuffers(); + status_t releaseBuffers(); + status_t seekTo(int64_t positionUs); + MediaBuffer* readBuffer(); +private: + sp 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 &source); + + virtual size_t countTracks(); + virtual sp getTrack(size_t index); + virtual sp getTrackMetaData(size_t index, uint32_t flags); + + virtual sp getMetaData(); + +protected: + virtual ~MidiExtractor(); + +private: + sp mDataSource; + status_t mInitCheck; + sp mFileMetadata; + + // There is only one track + sp mTrackMetadata; + + sp 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 &source, String8 *mimeType, + float *confidence, sp *); + +} // namespace android + +#endif // MIDI_EXTRACTOR_H_ -- cgit v1.1