diff options
Diffstat (limited to 'media')
80 files changed, 2034 insertions, 1968 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 8aa54dc..fc4b2a5 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -25,6 +25,8 @@ LOCAL_SRC_FILES:= \ AudioRecord.cpp \ AudioSystem.cpp \ mediaplayer.cpp \ + IMediaHTTPConnection.cpp \ + IMediaHTTPService.cpp \ IMediaLogService.cpp \ IMediaPlayerService.cpp \ IMediaPlayerClient.cpp \ diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index 8dfffb3..35f6557 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -380,9 +380,9 @@ void AudioEffect::enableStatusChanged(bool enabled) } void AudioEffect::commandExecuted(uint32_t cmdCode, - uint32_t cmdSize, + uint32_t cmdSize __unused, void *cmdData, - uint32_t replySize, + uint32_t replySize __unused, void *replyData) { if (cmdData == NULL || replyData == NULL) { diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index b69e3ae..a9ba154 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -87,7 +87,7 @@ AudioRecord::AudioRecord( int notificationFrames, int sessionId, transfer_type transferType, - audio_input_flags_t flags) + audio_input_flags_t flags __unused) : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), @@ -228,7 +228,8 @@ status_t AudioRecord::set( ALOGE("frameCount %u < minFrameCount %u", frameCount, minFrameCount); return BAD_VALUE; } - mFrameCount = frameCount; + // mFrameCount is initialized in openRecord_l + mReqFrameCount = frameCount; mNotificationFramesReq = notificationFrames; mNotificationFramesAct = 0; @@ -449,11 +450,12 @@ status_t AudioRecord::openRecord_l(size_t epoch) } mNotificationFramesAct = mNotificationFramesReq; + size_t frameCount = mReqFrameCount; if (!(mFlags & AUDIO_INPUT_FLAG_FAST)) { // Make sure that application is notified with sufficient margin before overrun - if (mNotificationFramesAct == 0 || mNotificationFramesAct > mFrameCount/2) { - mNotificationFramesAct = mFrameCount/2; + if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/2) { + mNotificationFramesAct = frameCount/2; } } @@ -467,7 +469,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) // Now that we have a reference to an I/O handle and have not yet handed it off to AudioFlinger, // we must release it ourselves if anything goes wrong. - size_t temp = mFrameCount; // temp may be replaced by a revised value of frameCount, + size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also int originalSessionId = mSessionId; sp<IAudioRecord> record = audioFlinger->openRecord(input, @@ -510,10 +512,15 @@ status_t AudioRecord::openRecord_l(size_t epoch) audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer); mCblk = cblk; // note that temp is the (possibly revised) value of mFrameCount - if (temp < mFrameCount || (mFrameCount == 0 && temp == 0)) { - ALOGW("Requested frameCount %u but received frameCount %u", mFrameCount, temp); + if (temp < frameCount || (frameCount == 0 && temp == 0)) { + ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp); + } + frameCount = temp; + // If IAudioRecord is re-created, don't let the requested frameCount + // decrease. This can confuse clients that cache frameCount(). + if (frameCount > mReqFrameCount) { + mReqFrameCount = frameCount; } - mFrameCount = temp; // FIXME missing fast track frameCount logic mAwaitBoost = false; @@ -538,6 +545,8 @@ status_t AudioRecord::openRecord_l(size_t epoch) // starting address of buffers in shared memory void *buffers = (char*)cblk + sizeof(audio_track_cblk_t); + mFrameCount = frameCount; + // update proxy mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize); mProxy->setEpoch(epoch); diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index dcb72f8..1ab94fa 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -333,7 +333,7 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t st } status_t AudioSystem::getLatency(audio_io_handle_t output, - audio_stream_type_t streamType, + audio_stream_type_t streamType __unused, uint32_t* latency) { OutputDescriptor *outputDesc; diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp new file mode 100644 index 0000000..622d9cf --- /dev/null +++ b/media/libmedia/IMediaHTTPConnection.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2013 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 "IMediaHTTPConnection" +#include <utils/Log.h> + +#include <media/IMediaHTTPConnection.h> + +#include <binder/IMemory.h> +#include <binder/Parcel.h> +#include <utils/String8.h> +#include <media/stagefright/foundation/ADebug.h> + +namespace android { + +enum { + CONNECT = IBinder::FIRST_CALL_TRANSACTION, + DISCONNECT, + READ_AT, + GET_SIZE, + GET_MIME_TYPE, +}; + +struct BpMediaHTTPConnection : public BpInterface<IMediaHTTPConnection> { + BpMediaHTTPConnection(const sp<IBinder> &impl) + : BpInterface<IMediaHTTPConnection>(impl) { + } + + virtual bool connect( + const char *uri, const KeyedVector<String8, String8> *headers) { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + String16 tmp(uri); + data.writeString16(tmp); + + tmp = String16(""); + if (headers != NULL) { + for (size_t i = 0; i < headers->size(); ++i) { + String16 key(headers->keyAt(i).string()); + String16 val(headers->valueAt(i).string()); + + tmp.append(key); + tmp.append(String16(": ")); + tmp.append(val); + tmp.append(String16("\r\n")); + } + } + data.writeString16(tmp); + + remote()->transact(CONNECT, data, &reply); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + sp<IBinder> binder = reply.readStrongBinder(); + mMemory = interface_cast<IMemory>(binder); + + return mMemory != NULL; + } + + virtual void disconnect() { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + remote()->transact(DISCONNECT, data, &reply); + } + + virtual ssize_t readAt(off64_t offset, void *buffer, size_t size) { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + data.writeInt64(offset); + data.writeInt32(size); + + status_t err = remote()->transact(READ_AT, data, &reply); + CHECK_EQ(err, (status_t)OK); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + int32_t len = reply.readInt32(); + + if (len > 0) { + memcpy(buffer, mMemory->pointer(), len); + } + + return len; + } + + virtual off64_t getSize() { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + remote()->transact(GET_SIZE, data, &reply); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + return reply.readInt64(); + } + + virtual status_t getMIMEType(String8 *mimeType) { + *mimeType = String8(""); + + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPConnection::getInterfaceDescriptor()); + + remote()->transact(GET_MIME_TYPE, data, &reply); + + int32_t exceptionCode = reply.readExceptionCode(); + + if (exceptionCode) { + return UNKNOWN_ERROR; + } + + *mimeType = String8(reply.readString16()); + + return OK; + } + +private: + sp<IMemory> mMemory; +}; + +IMPLEMENT_META_INTERFACE( + MediaHTTPConnection, "android.media.IMediaHTTPConnection"); + +} // namespace android + diff --git a/media/libmedia/IMediaHTTPService.cpp b/media/libmedia/IMediaHTTPService.cpp new file mode 100644 index 0000000..1260582 --- /dev/null +++ b/media/libmedia/IMediaHTTPService.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 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 "IMediaHTTPService" +#include <utils/Log.h> + +#include <media/IMediaHTTPService.h> + +#include <binder/Parcel.h> +#include <media/IMediaHTTPConnection.h> + +namespace android { + +enum { + MAKE_HTTP = IBinder::FIRST_CALL_TRANSACTION, +}; + +struct BpMediaHTTPService : public BpInterface<IMediaHTTPService> { + BpMediaHTTPService(const sp<IBinder> &impl) + : BpInterface<IMediaHTTPService>(impl) { + } + + virtual sp<IMediaHTTPConnection> makeHTTPConnection() { + Parcel data, reply; + data.writeInterfaceToken( + IMediaHTTPService::getInterfaceDescriptor()); + + remote()->transact(MAKE_HTTP, data, &reply); + + status_t err = reply.readInt32(); + + if (err != OK) { + return NULL; + } + + return interface_cast<IMediaHTTPConnection>(reply.readStrongBinder()); + } +}; + +IMPLEMENT_META_INTERFACE( + MediaHTTPService, "android.media.IMediaHTTPService"); + +} // namespace android + diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp index bb066a0..c7d9d51 100644 --- a/media/libmedia/IMediaMetadataRetriever.cpp +++ b/media/libmedia/IMediaMetadataRetriever.cpp @@ -18,6 +18,7 @@ #include <stdint.h> #include <sys/types.h> #include <binder/Parcel.h> +#include <media/IMediaHTTPService.h> #include <media/IMediaMetadataRetriever.h> #include <utils/String8.h> #include <utils/KeyedVector.h> @@ -84,10 +85,16 @@ public: } status_t setDataSource( - const char *srcUrl, const KeyedVector<String8, String8> *headers) + const sp<IMediaHTTPService> &httpService, + const char *srcUrl, + const KeyedVector<String8, String8> *headers) { Parcel data, reply; data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); + data.writeInt32(httpService != NULL); + if (httpService != NULL) { + data.writeStrongBinder(httpService->asBinder()); + } data.writeCString(srcUrl); if (headers == NULL) { @@ -195,6 +202,13 @@ status_t BnMediaMetadataRetriever::onTransact( } break; case SET_DATA_SOURCE_URL: { CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); + + sp<IMediaHTTPService> httpService; + if (data.readInt32()) { + httpService = + interface_cast<IMediaHTTPService>(data.readStrongBinder()); + } + const char* srcUrl = data.readCString(); KeyedVector<String8, String8> headers; @@ -206,7 +220,8 @@ status_t BnMediaMetadataRetriever::onTransact( } reply->writeInt32( - setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL)); + setDataSource( + httpService, srcUrl, numHeaders > 0 ? &headers : NULL)); return NO_ERROR; } break; diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index e79bcd2..d778d05 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -21,6 +21,7 @@ #include <binder/Parcel.h> +#include <media/IMediaHTTPService.h> #include <media/IMediaPlayer.h> #include <media/IStreamSource.h> @@ -75,11 +76,17 @@ public: remote()->transact(DISCONNECT, data, &reply); } - status_t setDataSource(const char* url, + status_t setDataSource( + const sp<IMediaHTTPService> &httpService, + const char* url, const KeyedVector<String8, String8>* headers) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeInt32(httpService != NULL); + if (httpService != NULL) { + data.writeStrongBinder(httpService->asBinder()); + } data.writeCString(url); if (headers == NULL) { data.writeInt32(0); @@ -355,6 +362,13 @@ status_t BnMediaPlayer::onTransact( } break; case SET_DATA_SOURCE_URL: { CHECK_INTERFACE(IMediaPlayer, data, reply); + + sp<IMediaHTTPService> httpService; + if (data.readInt32()) { + httpService = + interface_cast<IMediaHTTPService>(data.readStrongBinder()); + } + const char* url = data.readCString(); KeyedVector<String8, String8> headers; int32_t numHeaders = data.readInt32(); @@ -363,7 +377,8 @@ status_t BnMediaPlayer::onTransact( String8 value = data.readString8(); headers.add(key, value); } - reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL)); + reply->writeInt32(setDataSource( + httpService, url, numHeaders > 0 ? &headers : NULL)); return NO_ERROR; } break; case SET_DATA_SOURCE_FD: { diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 3c22b4c..d116b14 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -23,6 +23,7 @@ #include <media/ICrypto.h> #include <media/IDrm.h> #include <media/IHDCP.h> +#include <media/IMediaHTTPService.h> #include <media/IMediaPlayerService.h> #include <media/IMediaRecorder.h> #include <media/IOMX.h> @@ -48,7 +49,6 @@ enum { ADD_BATTERY_DATA, PULL_BATTERY_DATA, LISTEN_FOR_REMOTE_DISPLAY, - UPDATE_PROXY_CONFIG, }; class BpMediaPlayerService: public BpInterface<IMediaPlayerService> @@ -86,12 +86,21 @@ public: return interface_cast<IMediaRecorder>(reply.readStrongBinder()); } - virtual status_t decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, - audio_format_t* pFormat, - const sp<IMemoryHeap>& heap, size_t *pSize) + virtual status_t decode( + const sp<IMediaHTTPService> &httpService, + const char* url, + uint32_t *pSampleRate, + int* pNumChannels, + audio_format_t* pFormat, + const sp<IMemoryHeap>& heap, + size_t *pSize) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeInt32(httpService != NULL); + if (httpService != NULL) { + data.writeStrongBinder(httpService->asBinder()); + } data.writeCString(url); data.writeStrongBinder(heap->asBinder()); status_t status = remote()->transact(DECODE_URL, data, &reply); @@ -182,25 +191,6 @@ public: remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply); return interface_cast<IRemoteDisplay>(reply.readStrongBinder()); } - - virtual status_t updateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - Parcel data, reply; - - data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); - if (host == NULL) { - data.writeInt32(0); - } else { - data.writeInt32(1); - data.writeCString(host); - data.writeInt32(port); - data.writeCString(exclusionList); - } - - remote()->transact(UPDATE_PROXY_CONFIG, data, &reply); - - return reply.readInt32(); - } }; IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.media.IMediaPlayerService"); @@ -222,13 +212,25 @@ status_t BnMediaPlayerService::onTransact( } break; case DECODE_URL: { CHECK_INTERFACE(IMediaPlayerService, data, reply); + sp<IMediaHTTPService> httpService; + if (data.readInt32()) { + httpService = + interface_cast<IMediaHTTPService>(data.readStrongBinder()); + } const char* url = data.readCString(); sp<IMemoryHeap> heap = interface_cast<IMemoryHeap>(data.readStrongBinder()); uint32_t sampleRate; int numChannels; audio_format_t format; size_t size; - status_t status = decode(url, &sampleRate, &numChannels, &format, heap, &size); + status_t status = + decode(httpService, + url, + &sampleRate, + &numChannels, + &format, + heap, + &size); reply->writeInt32(status); if (status == NO_ERROR) { reply->writeInt32(sampleRate); @@ -316,24 +318,6 @@ status_t BnMediaPlayerService::onTransact( reply->writeStrongBinder(display->asBinder()); return NO_ERROR; } break; - case UPDATE_PROXY_CONFIG: - { - CHECK_INTERFACE(IMediaPlayerService, data, reply); - - const char *host = NULL; - int32_t port = 0; - const char *exclusionList = NULL; - - if (data.readInt32()) { - host = data.readCString(); - port = data.readInt32(); - exclusionList = data.readCString(); - } - - reply->writeInt32(updateProxyConfig(host, port, exclusionList)); - - return OK; - } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp index 98acd1f..9ed010d 100644 --- a/media/libmedia/SoundPool.cpp +++ b/media/libmedia/SoundPool.cpp @@ -21,6 +21,7 @@ #define USE_SHARED_MEM_BUFFER #include <media/AudioTrack.h> +#include <media/IMediaHTTPService.h> #include <media/mediaplayer.h> #include <media/SoundPool.h> #include "SoundPoolThread.h" @@ -496,7 +497,14 @@ status_t Sample::doLoad() ALOGV("Start decode"); if (mUrl) { - status = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format, mHeap, &mSize); + status = MediaPlayer::decode( + NULL /* httpService */, + mUrl, + &sampleRate, + &numChannels, + &format, + mHeap, + &mSize); } else { status = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format, mHeap, &mSize); diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp index bad2494..1d6bb6f 100644 --- a/media/libmedia/mediametadataretriever.cpp +++ b/media/libmedia/mediametadataretriever.cpp @@ -21,6 +21,7 @@ #include <binder/IServiceManager.h> #include <binder/IPCThreadState.h> #include <media/mediametadataretriever.h> +#include <media/IMediaHTTPService.h> #include <media/IMediaPlayerService.h> #include <utils/Log.h> #include <dlfcn.h> @@ -93,7 +94,9 @@ void MediaMetadataRetriever::disconnect() } status_t MediaMetadataRetriever::setDataSource( - const char *srcUrl, const KeyedVector<String8, String8> *headers) + const sp<IMediaHTTPService> &httpService, + const char *srcUrl, + const KeyedVector<String8, String8> *headers) { ALOGV("setDataSource"); Mutex::Autolock _l(mLock); @@ -106,7 +109,7 @@ status_t MediaMetadataRetriever::setDataSource( return UNKNOWN_ERROR; } ALOGV("data source (%s)", srcUrl); - return mRetriever->setDataSource(srcUrl, headers); + return mRetriever->setDataSource(httpService, srcUrl, headers); } status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length) diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 7a6f31d..24663ad 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -136,6 +136,7 @@ status_t MediaPlayer::attachNewPlayer(const sp<IMediaPlayer>& player) } status_t MediaPlayer::setDataSource( + const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers) { ALOGV("setDataSource(%s)", url); @@ -145,7 +146,7 @@ status_t MediaPlayer::setDataSource( if (service != 0) { sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || - (NO_ERROR != player->setDataSource(url, headers))) { + (NO_ERROR != player->setDataSource(httpService, url, headers))) { player.clear(); } err = attachNewPlayer(player); @@ -776,15 +777,20 @@ void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj) } } -/*static*/ status_t MediaPlayer::decode(const char* url, uint32_t *pSampleRate, - int* pNumChannels, audio_format_t* pFormat, - const sp<IMemoryHeap>& heap, size_t *pSize) +/*static*/ status_t MediaPlayer::decode( + const sp<IMediaHTTPService> &httpService, + const char* url, + uint32_t *pSampleRate, + int* pNumChannels, + audio_format_t* pFormat, + const sp<IMemoryHeap>& heap, + size_t *pSize) { ALOGV("decode(%s)", url); status_t status; const sp<IMediaPlayerService>& service = getMediaPlayerService(); if (service != 0) { - status = service->decode(url, pSampleRate, pNumChannels, pFormat, heap, pSize); + status = service->decode(httpService, url, pSampleRate, pNumChannels, pFormat, heap, pSize); } else { ALOGE("Unable to locate media service"); status = DEAD_OBJECT; @@ -832,15 +838,4 @@ status_t MediaPlayer::setNextMediaPlayer(const sp<MediaPlayer>& next) { return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer); } -status_t MediaPlayer::updateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - const sp<IMediaPlayerService>& service = getMediaPlayerService(); - - if (service != NULL) { - return service->updateProxyConfig(host, port, exclusionList); - } - - return INVALID_OPERATION; -} - }; // namespace android diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 9ac9105..f1bc79c 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -44,6 +44,7 @@ #include <utils/SystemClock.h> #include <utils/Vector.h> +#include <media/IMediaHTTPService.h> #include <media/IRemoteDisplay.h> #include <media/IRemoteDisplayClient.h> #include <media/MediaPlayerInterface.h> @@ -306,11 +307,6 @@ sp<IRemoteDisplay> MediaPlayerService::listenForRemoteDisplay( return new RemoteDisplay(client, iface.string()); } -status_t MediaPlayerService::updateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - return HTTPBase::UpdateProxyConfig(host, port, exclusionList); -} - status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const { const size_t SIZE = 256; @@ -622,7 +618,9 @@ void MediaPlayerService::Client::setDataSource_post( } status_t MediaPlayerService::Client::setDataSource( - const char *url, const KeyedVector<String8, String8> *headers) + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers) { ALOGV("setDataSource(%s)", url); if (url == NULL) @@ -657,7 +655,7 @@ status_t MediaPlayerService::Client::setDataSource( return NO_INIT; } - setDataSource_post(p, p->setDataSource(url, headers)); + setDataSource_post(p, p->setDataSource(httpService, url, headers)); return mStatus; } } @@ -1176,9 +1174,14 @@ int Antagonizer::callbackThread(void* user) } #endif -status_t MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, - audio_format_t* pFormat, - const sp<IMemoryHeap>& heap, size_t *pSize) +status_t MediaPlayerService::decode( + const sp<IMediaHTTPService> &httpService, + const char* url, + uint32_t *pSampleRate, + int* pNumChannels, + audio_format_t* pFormat, + const sp<IMemoryHeap>& heap, + size_t *pSize) { ALOGV("decode(%s)", url); sp<MediaPlayerBase> player; @@ -1206,7 +1209,7 @@ status_t MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache); // set data source - if (player->setDataSource(url) != NO_ERROR) goto Exit; + if (player->setDataSource(httpService, url) != NO_ERROR) goto Exit; ALOGV("prepare"); player->prepareAsync(); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 9c084e1..65b28dc 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -256,9 +256,15 @@ public: virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId); - virtual status_t decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, - audio_format_t* pFormat, - const sp<IMemoryHeap>& heap, size_t *pSize); + virtual status_t decode( + const sp<IMediaHTTPService> &httpService, + const char* url, + uint32_t *pSampleRate, + int* pNumChannels, + audio_format_t* pFormat, + const sp<IMemoryHeap>& heap, + size_t *pSize); + virtual status_t decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat, @@ -272,9 +278,6 @@ public: const String8& iface); virtual status_t dump(int fd, const Vector<String16>& args); - virtual status_t updateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - void removeClient(wp<Client> client); // For battery usage tracking purpose @@ -356,6 +359,7 @@ private: sp<MediaPlayerBase> createPlayer(player_type playerType); virtual status_t setDataSource( + const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers); diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index 348957f..c61cf89 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -31,6 +31,7 @@ #include <binder/MemoryHeapBase.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> +#include <media/IMediaHTTPService.h> #include <media/MediaMetadataRetrieverInterface.h> #include <media/MediaPlayerInterface.h> #include <private/media/VideoFrame.h> @@ -106,7 +107,9 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType) } status_t MetadataRetrieverClient::setDataSource( - const char *url, const KeyedVector<String8, String8> *headers) + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers) { ALOGV("setDataSource(%s)", url); Mutex::Autolock lock(mLock); @@ -127,7 +130,7 @@ status_t MetadataRetrieverClient::setDataSource( ALOGV("player type = %d", playerType); sp<MediaMetadataRetrieverBase> p = createRetriever(playerType); if (p == NULL) return NO_INIT; - status_t ret = p->setDataSource(url, headers); + status_t ret = p->setDataSource(httpService, url, headers); if (ret == NO_ERROR) mRetriever = p; return ret; } diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h index f08f933..9d3fbe9 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.h +++ b/media/libmediaplayerservice/MetadataRetrieverClient.h @@ -30,6 +30,7 @@ namespace android { +struct IMediaHTTPService; class IMediaPlayerService; class MemoryDealer; @@ -43,7 +44,9 @@ public: virtual void disconnect(); virtual status_t setDataSource( - const char *url, const KeyedVector<String8, String8> *headers); + 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 sp<IMemory> getFrameAtTime(int64_t timeUs, int option); diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp index 0a6aa90..deeddd1 100644 --- a/media/libmediaplayerservice/MidiFile.cpp +++ b/media/libmediaplayerservice/MidiFile.cpp @@ -114,7 +114,9 @@ MidiFile::~MidiFile() { } status_t MidiFile::setDataSource( - const char* path, const KeyedVector<String8, String8> *) { + const sp<IMediaHTTPService> &httpService, + const char* path, + const KeyedVector<String8, String8> *) { ALOGV("MidiFile::setDataSource url=%s", path); Mutex::Autolock lock(mMutex); diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h index 24d59b4..12802ba 100644 --- a/media/libmediaplayerservice/MidiFile.h +++ b/media/libmediaplayerservice/MidiFile.h @@ -32,7 +32,9 @@ public: virtual status_t initCheck(); virtual status_t setDataSource( - const char* path, const KeyedVector<String8, String8> *headers); + 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( diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp index 465209f..f3cf6ef 100644 --- a/media/libmediaplayerservice/MidiMetadataRetriever.cpp +++ b/media/libmediaplayerservice/MidiMetadataRetriever.cpp @@ -22,6 +22,8 @@ #include "MidiMetadataRetriever.h" #include <media/mediametadataretriever.h> +#include <media/IMediaHTTPService.h> + namespace android { static status_t ERROR_NOT_OPEN = -1; @@ -36,7 +38,9 @@ void MidiMetadataRetriever::clearMetadataValues() } status_t MidiMetadataRetriever::setDataSource( - const char *url, const KeyedVector<String8, String8> *headers) + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers) { ALOGV("setDataSource: %s", url? url: "NULL pointer"); Mutex::Autolock lock(mLock); @@ -44,7 +48,7 @@ status_t MidiMetadataRetriever::setDataSource( if (mMidiPlayer == 0) { mMidiPlayer = new MidiFile(); } - return mMidiPlayer->setDataSource(url, headers); + return mMidiPlayer->setDataSource(httpService, url, headers); } status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length) diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.h b/media/libmediaplayerservice/MidiMetadataRetriever.h index 4cee42d..b8214ee 100644 --- a/media/libmediaplayerservice/MidiMetadataRetriever.h +++ b/media/libmediaplayerservice/MidiMetadataRetriever.h @@ -32,7 +32,9 @@ public: ~MidiMetadataRetriever() {} virtual status_t setDataSource( - const char *url, const KeyedVector<String8, String8> *headers); + 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); diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index de61d9b..b19e8bf 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -54,8 +54,10 @@ status_t StagefrightPlayer::setUID(uid_t uid) { } status_t StagefrightPlayer::setDataSource( - const char *url, const KeyedVector<String8, String8> *headers) { - return mPlayer->setDataSource(url, headers); + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers) { + return mPlayer->setDataSource(httpService, url, headers); } // Warning: The filedescriptor passed into this method will only be valid until diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h index 600945e..e6c30ff 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.h +++ b/media/libmediaplayerservice/StagefrightPlayer.h @@ -34,7 +34,9 @@ public: virtual status_t setUID(uid_t uid); virtual status_t setDataSource( - const char *url, const KeyedVector<String8, String8> *headers); + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 78dad19..1ee0ee4 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -24,8 +24,10 @@ #include <binder/IServiceManager.h> #include <media/IMediaPlayerService.h> -#include <media/openmax/OMX_Audio.h> +#include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/foundation/ALooper.h> #include <media/stagefright/AudioSource.h> #include <media/stagefright/AMRWriter.h> #include <media/stagefright/AACWriter.h> @@ -35,13 +37,12 @@ #include <media/stagefright/MPEG4Writer.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaData.h> +#include <media/stagefright/MediaCodecSource.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXCodec.h> -#include <media/stagefright/SurfaceMediaSource.h> #include <media/MediaProfiles.h> #include <camera/ICamera.h> #include <camera/CameraParameters.h> -#include <gui/Surface.h> #include <utils/Errors.h> #include <sys/types.h> @@ -71,8 +72,7 @@ StagefrightRecorder::StagefrightRecorder() mAudioSource(AUDIO_SOURCE_CNT), mVideoSource(VIDEO_SOURCE_LIST_END), mCaptureTimeLapse(false), - mStarted(false), - mSurfaceMediaSource(NULL) { + mStarted(false) { ALOGV("Constructor"); reset(); @@ -81,10 +81,19 @@ StagefrightRecorder::StagefrightRecorder() StagefrightRecorder::~StagefrightRecorder() { ALOGV("Destructor"); stop(); + + if (mLooper != NULL) { + mLooper->stop(); + } } status_t StagefrightRecorder::init() { ALOGV("init"); + + mLooper = new ALooper; + mLooper->setName("recorder_looper"); + mLooper->start(); + return OK; } @@ -93,7 +102,7 @@ status_t StagefrightRecorder::init() { // while encoding GL Frames sp<IGraphicBufferProducer> StagefrightRecorder::querySurfaceMediaSource() const { ALOGV("Get SurfaceMediaSource"); - return mSurfaceMediaSource->getBufferQueue(); + return mGraphicBufferProducer; } status_t StagefrightRecorder::setAudioSource(audio_source_t as) { @@ -739,18 +748,14 @@ status_t StagefrightRecorder::setClientName(const String16& clientName) { } status_t StagefrightRecorder::prepare() { - return OK; -} - -status_t StagefrightRecorder::start() { - CHECK_GE(mOutputFd, 0); + ALOGV("prepare"); + if (mOutputFd < 0) { + ALOGE("Output file descriptor is invalid"); + return INVALID_OPERATION; + } // Get UID here for permission checking mClientUid = IPCThreadState::self()->getCallingUid(); - if (mWriter != NULL) { - ALOGE("File writer is not avaialble"); - return UNKNOWN_ERROR; - } status_t status = OK; @@ -758,25 +763,25 @@ status_t StagefrightRecorder::start() { case OUTPUT_FORMAT_DEFAULT: case OUTPUT_FORMAT_THREE_GPP: case OUTPUT_FORMAT_MPEG_4: - status = startMPEG4Recording(); + status = setupMPEG4Recording(); break; case OUTPUT_FORMAT_AMR_NB: case OUTPUT_FORMAT_AMR_WB: - status = startAMRRecording(); + status = setupAMRRecording(); break; case OUTPUT_FORMAT_AAC_ADIF: case OUTPUT_FORMAT_AAC_ADTS: - status = startAACRecording(); + status = setupAACRecording(); break; case OUTPUT_FORMAT_RTP_AVP: - status = startRTPRecording(); + status = setupRTPRecording(); break; case OUTPUT_FORMAT_MPEG2TS: - status = startMPEG2TSRecording(); + status = setupMPEG2TSRecording(); break; default: @@ -785,6 +790,60 @@ status_t StagefrightRecorder::start() { break; } + return status; +} + +status_t StagefrightRecorder::start() { + ALOGV("start"); + if (mOutputFd < 0) { + ALOGE("Output file descriptor is invalid"); + return INVALID_OPERATION; + } + + // Get UID here for permission checking + mClientUid = IPCThreadState::self()->getCallingUid(); + if (mWriter == NULL) { + ALOGE("File writer is not avaialble"); + return UNKNOWN_ERROR; + } + + status_t status = OK; + + switch (mOutputFormat) { + case OUTPUT_FORMAT_DEFAULT: + case OUTPUT_FORMAT_THREE_GPP: + case OUTPUT_FORMAT_MPEG_4: + { + sp<MetaData> meta = new MetaData; + setupMPEG4MetaData(&meta); + status = mWriter->start(meta.get()); + break; + } + + case OUTPUT_FORMAT_AMR_NB: + case OUTPUT_FORMAT_AMR_WB: + case OUTPUT_FORMAT_AAC_ADIF: + case OUTPUT_FORMAT_AAC_ADTS: + case OUTPUT_FORMAT_RTP_AVP: + case OUTPUT_FORMAT_MPEG2TS: + { + status = mWriter->start(); + break; + } + + default: + { + ALOGE("Unsupported output file format: %d", mOutputFormat); + status = UNKNOWN_ERROR; + break; + } + } + + if (status != OK) { + mWriter.clear(); + mWriter = NULL; + } + if ((status == OK) && (!mStarted)) { mStarted = true; @@ -816,58 +875,54 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() { return NULL; } - sp<MetaData> encMeta = new MetaData; + sp<AMessage> format = new AMessage; const char *mime; switch (mAudioEncoder) { case AUDIO_ENCODER_AMR_NB: case AUDIO_ENCODER_DEFAULT: - mime = MEDIA_MIMETYPE_AUDIO_AMR_NB; + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB); break; case AUDIO_ENCODER_AMR_WB: - mime = MEDIA_MIMETYPE_AUDIO_AMR_WB; + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_WB); break; case AUDIO_ENCODER_AAC: - mime = MEDIA_MIMETYPE_AUDIO_AAC; - encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC); + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC); + format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC); break; case AUDIO_ENCODER_HE_AAC: - mime = MEDIA_MIMETYPE_AUDIO_AAC; - encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectHE); + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC); + format->setInt32("aac-profile", OMX_AUDIO_AACObjectHE); break; case AUDIO_ENCODER_AAC_ELD: - mime = MEDIA_MIMETYPE_AUDIO_AAC; - encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD); + format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC); + format->setInt32("aac-profile", OMX_AUDIO_AACObjectELD); break; default: ALOGE("Unknown audio encoder: %d", mAudioEncoder); return NULL; } - encMeta->setCString(kKeyMIMEType, mime); int32_t maxInputSize; CHECK(audioSource->getFormat()->findInt32( kKeyMaxInputSize, &maxInputSize)); - encMeta->setInt32(kKeyMaxInputSize, maxInputSize); - encMeta->setInt32(kKeyChannelCount, mAudioChannels); - encMeta->setInt32(kKeySampleRate, mSampleRate); - encMeta->setInt32(kKeyBitRate, mAudioBitRate); + format->setInt32("max-input-size", maxInputSize); + format->setInt32("channel-count", mAudioChannels); + format->setInt32("sample-rate", mSampleRate); + format->setInt32("bitrate", mAudioBitRate); if (mAudioTimeScale > 0) { - encMeta->setInt32(kKeyTimeScale, mAudioTimeScale); + format->setInt32("time-scale", mAudioTimeScale); } - OMXClient client; - CHECK_EQ(client.connect(), (status_t)OK); sp<MediaSource> audioEncoder = - OMXCodec::Create(client.interface(), encMeta, - true /* createEncoder */, audioSource); + MediaCodecSource::Create(mLooper, format, audioSource); mAudioSourceNode = audioSource; return audioEncoder; } -status_t StagefrightRecorder::startAACRecording() { +status_t StagefrightRecorder::setupAACRecording() { // FIXME: // Add support for OUTPUT_FORMAT_AAC_ADIF CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS); @@ -878,16 +933,10 @@ status_t StagefrightRecorder::startAACRecording() { CHECK(mAudioSource != AUDIO_SOURCE_CNT); mWriter = new AACWriter(mOutputFd); - status_t status = startRawAudioRecording(); - if (status != OK) { - mWriter.clear(); - mWriter = NULL; - } - - return status; + return setupRawAudioRecording(); } -status_t StagefrightRecorder::startAMRRecording() { +status_t StagefrightRecorder::setupAMRRecording() { CHECK(mOutputFormat == OUTPUT_FORMAT_AMR_NB || mOutputFormat == OUTPUT_FORMAT_AMR_WB); @@ -907,15 +956,10 @@ status_t StagefrightRecorder::startAMRRecording() { } mWriter = new AMRWriter(mOutputFd); - status_t status = startRawAudioRecording(); - if (status != OK) { - mWriter.clear(); - mWriter = NULL; - } - return status; + return setupRawAudioRecording(); } -status_t StagefrightRecorder::startRawAudioRecording() { +status_t StagefrightRecorder::setupRawAudioRecording() { if (mAudioSource >= AUDIO_SOURCE_CNT) { ALOGE("Invalid audio source: %d", mAudioSource); return BAD_VALUE; @@ -941,12 +985,11 @@ status_t StagefrightRecorder::startRawAudioRecording() { mWriter->setMaxFileSize(mMaxFileSizeBytes); } mWriter->setListener(mListener); - mWriter->start(); return OK; } -status_t StagefrightRecorder::startRTPRecording() { +status_t StagefrightRecorder::setupRTPRecording() { CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_RTP_AVP); if ((mAudioSource != AUDIO_SOURCE_CNT @@ -983,10 +1026,10 @@ status_t StagefrightRecorder::startRTPRecording() { mWriter->addSource(source); mWriter->setListener(mListener); - return mWriter->start(); + return OK; } -status_t StagefrightRecorder::startMPEG2TSRecording() { +status_t StagefrightRecorder::setupMPEG2TSRecording() { CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS); sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd); @@ -1036,7 +1079,7 @@ status_t StagefrightRecorder::startMPEG2TSRecording() { mWriter = writer; - return mWriter->start(); + return OK; } void StagefrightRecorder::clipVideoFrameRate() { @@ -1277,49 +1320,14 @@ status_t StagefrightRecorder::setupMediaSource( return err; } *mediaSource = cameraSource; - } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) { - // If using GRAlloc buffers, setup surfacemediasource. - // Later a handle to that will be passed - // to the client side when queried - status_t err = setupSurfaceMediaSource(); - if (err != OK) { - return err; - } - *mediaSource = mSurfaceMediaSource; + } else if (mVideoSource == VIDEO_SOURCE_SURFACE) { + *mediaSource = NULL; } else { return INVALID_OPERATION; } return OK; } -// setupSurfaceMediaSource creates a source with the given -// width and height and framerate. -// TODO: This could go in a static function inside SurfaceMediaSource -// similar to that in CameraSource -status_t StagefrightRecorder::setupSurfaceMediaSource() { - status_t err = OK; - mSurfaceMediaSource = new SurfaceMediaSource(mVideoWidth, mVideoHeight); - if (mSurfaceMediaSource == NULL) { - return NO_INIT; - } - - if (mFrameRate == -1) { - int32_t frameRate = 0; - CHECK (mSurfaceMediaSource->getFormat()->findInt32( - kKeyFrameRate, &frameRate)); - ALOGI("Frame rate is not explicitly set. Use the current frame " - "rate (%d fps)", frameRate); - mFrameRate = frameRate; - } else { - err = mSurfaceMediaSource->setFrameRate(mFrameRate); - } - CHECK(mFrameRate != -1); - - mIsMetaDataStoredInVideoBuffers = - mSurfaceMediaSource->isMetaDataStoredInVideoBuffers(); - return err; -} - status_t StagefrightRecorder::setupCameraSource( sp<CameraSource> *cameraSource) { status_t err = OK; @@ -1386,21 +1394,19 @@ status_t StagefrightRecorder::setupVideoEncoder( sp<MediaSource> *source) { source->clear(); - sp<MetaData> enc_meta = new MetaData; - enc_meta->setInt32(kKeyBitRate, mVideoBitRate); - enc_meta->setInt32(kKeyFrameRate, mFrameRate); + sp<AMessage> format = new AMessage(); switch (mVideoEncoder) { case VIDEO_ENCODER_H263: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); + format->setString("mime", MEDIA_MIMETYPE_VIDEO_H263); break; case VIDEO_ENCODER_MPEG_4_SP: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + format->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4); break; case VIDEO_ENCODER_H264: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); + format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC); break; default: @@ -1408,59 +1414,69 @@ status_t StagefrightRecorder::setupVideoEncoder( break; } - sp<MetaData> meta = cameraSource->getFormat(); + if (cameraSource != NULL) { + sp<MetaData> meta = cameraSource->getFormat(); - int32_t width, height, stride, sliceHeight, colorFormat; - CHECK(meta->findInt32(kKeyWidth, &width)); - CHECK(meta->findInt32(kKeyHeight, &height)); - CHECK(meta->findInt32(kKeyStride, &stride)); - CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight)); - CHECK(meta->findInt32(kKeyColorFormat, &colorFormat)); + int32_t width, height, stride, sliceHeight, colorFormat; + CHECK(meta->findInt32(kKeyWidth, &width)); + CHECK(meta->findInt32(kKeyHeight, &height)); + CHECK(meta->findInt32(kKeyStride, &stride)); + CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight)); + CHECK(meta->findInt32(kKeyColorFormat, &colorFormat)); + + format->setInt32("width", width); + format->setInt32("height", height); + format->setInt32("stride", stride); + format->setInt32("slice-height", sliceHeight); + format->setInt32("color-format", colorFormat); + } else { + format->setInt32("width", mVideoWidth); + format->setInt32("height", mVideoHeight); + format->setInt32("stride", mVideoWidth); + format->setInt32("slice-height", mVideoWidth); + format->setInt32("color-format", OMX_COLOR_FormatAndroidOpaque); + } + + format->setInt32("bitrate", mVideoBitRate); + format->setInt32("frame-rate", mFrameRate); + format->setInt32("i-frame-interval", mIFramesIntervalSec); - enc_meta->setInt32(kKeyWidth, width); - enc_meta->setInt32(kKeyHeight, height); - enc_meta->setInt32(kKeyIFramesInterval, mIFramesIntervalSec); - enc_meta->setInt32(kKeyStride, stride); - enc_meta->setInt32(kKeySliceHeight, sliceHeight); - enc_meta->setInt32(kKeyColorFormat, colorFormat); if (mVideoTimeScale > 0) { - enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale); + format->setInt32("time-scale", mVideoTimeScale); } if (mVideoEncoderProfile != -1) { - enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile); + format->setInt32("profile", mVideoEncoderProfile); } if (mVideoEncoderLevel != -1) { - enc_meta->setInt32(kKeyVideoLevel, mVideoEncoderLevel); + format->setInt32("level", mVideoEncoderLevel); } - OMXClient client; - CHECK_EQ(client.connect(), (status_t)OK); - - uint32_t encoder_flags = 0; + uint32_t flags = 0; if (mIsMetaDataStoredInVideoBuffers) { - encoder_flags |= OMXCodec::kStoreMetaDataInVideoBuffers; + flags |= MediaCodecSource::FLAG_USE_METADATA_INPUT; } - // Do not wait for all the input buffers to become available. - // This give timelapse video recording faster response in - // receiving output from video encoder component. - if (mCaptureTimeLapse) { - encoder_flags |= OMXCodec::kOnlySubmitOneInputBufferAtOneTime; + if (cameraSource == NULL) { + flags |= MediaCodecSource::FLAG_USE_SURFACE_INPUT; } - sp<MediaSource> encoder = OMXCodec::Create( - client.interface(), enc_meta, - true /* createEncoder */, cameraSource, - NULL, encoder_flags); + sp<MediaCodecSource> encoder = + MediaCodecSource::Create(mLooper, format, cameraSource, flags); if (encoder == NULL) { ALOGW("Failed to create the encoder"); // When the encoder fails to be created, we need // release the camera source due to the camera's lock // and unlock mechanism. - cameraSource->stop(); + if (cameraSource != NULL) { + cameraSource->stop(); + } return UNKNOWN_ERROR; } + if (cameraSource == NULL) { + mGraphicBufferProducer = encoder->getGraphicBufferProducer(); + } + *source = encoder; return OK; @@ -1494,9 +1510,10 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) { return OK; } -status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { +status_t StagefrightRecorder::setupMPEG4Recording() { mWriter.clear(); - *totalBitRate = 0; + mTotalBitRate = 0; + status_t err = OK; sp<MediaWriter> writer = new MPEG4Writer(mOutputFd); @@ -1515,7 +1532,7 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { } writer->addSource(encoder); - *totalBitRate += mVideoBitRate; + mTotalBitRate += mVideoBitRate; } // Audio source is added at the end if it exists. @@ -1524,7 +1541,7 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) { err = setupAudioEncoder(writer); if (err != OK) return err; - *totalBitRate += mAudioBitRate; + mTotalBitRate += mAudioBitRate; } if (mInterleaveDurationUs > 0) { @@ -1542,7 +1559,13 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { writer->setMaxFileSize(mMaxFileSizeBytes); } - mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId); + if (mVideoSource == VIDEO_SOURCE_DEFAULT + || mVideoSource == VIDEO_SOURCE_CAMERA) { + mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId); + } else if (mVideoSource == VIDEO_SOURCE_SURFACE) { + // surface source doesn't need large initial delay + mStartTimeOffsetMs = 200; + } if (mStartTimeOffsetMs > 0) { reinterpret_cast<MPEG4Writer *>(writer.get())-> setStartTimeOffsetMs(mStartTimeOffsetMs); @@ -1553,11 +1576,11 @@ status_t StagefrightRecorder::setupMPEG4Recording(int32_t *totalBitRate) { return OK; } -void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate, - sp<MetaData> *meta) { +void StagefrightRecorder::setupMPEG4MetaData(sp<MetaData> *meta) { + int64_t startTimeUs = systemTime() / 1000; (*meta)->setInt64(kKeyTime, startTimeUs); (*meta)->setInt32(kKeyFileType, mOutputFormat); - (*meta)->setInt32(kKeyBitRate, totalBitRate); + (*meta)->setInt32(kKeyBitRate, mTotalBitRate); (*meta)->setInt32(kKey64BitFileOffset, mUse64BitFileOffset); if (mMovieTimeScale > 0) { (*meta)->setInt32(kKeyTimeScale, mMovieTimeScale); @@ -1570,25 +1593,6 @@ void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalB } } -status_t StagefrightRecorder::startMPEG4Recording() { - int32_t totalBitRate; - status_t err = setupMPEG4Recording(&totalBitRate); - if (err != OK) { - return err; - } - - int64_t startTimeUs = systemTime() / 1000; - sp<MetaData> meta = new MetaData; - setupMPEG4MetaData(startTimeUs, totalBitRate, &meta); - - err = mWriter->start(meta.get()); - if (err != OK) { - return err; - } - - return OK; -} - status_t StagefrightRecorder::pause() { ALOGV("pause"); if (mWriter == NULL) { @@ -1628,6 +1632,8 @@ status_t StagefrightRecorder::stop() { mWriter.clear(); } + mGraphicBufferProducer.clear(); + if (mOutputFd >= 0) { ::close(mOutputFd); mOutputFd = -1; @@ -1647,7 +1653,6 @@ status_t StagefrightRecorder::stop() { addBatteryData(params); } - return err; } @@ -1699,6 +1704,7 @@ status_t StagefrightRecorder::reset() { mRotationDegrees = 0; mLatitudex10000 = -3600000; mLongitudex10000 = -3600000; + mTotalBitRate = 0; mOutputFd = -1; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index bc43488..7d6abd3 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -37,6 +37,7 @@ struct AudioSource; class MediaProfiles; class IGraphicBufferProducer; class SurfaceMediaSource; +class ALooper; struct StagefrightRecorder : public MediaRecorderBase { StagefrightRecorder(); @@ -106,6 +107,7 @@ private: int32_t mLatitudex10000; int32_t mLongitudex10000; int32_t mStartTimeOffsetMs; + int32_t mTotalBitRate; bool mCaptureTimeLapse; int64_t mTimeBetweenTimeLapseFrameCaptureUs; @@ -122,17 +124,16 @@ private: // An <IGraphicBufferProducer> pointer // will be sent to the client side using which the // frame buffers will be queued and dequeued - sp<SurfaceMediaSource> mSurfaceMediaSource; - - status_t setupMPEG4Recording(int32_t *totalBitRate); - void setupMPEG4MetaData(int64_t startTimeUs, int32_t totalBitRate, - sp<MetaData> *meta); - status_t startMPEG4Recording(); - status_t startAMRRecording(); - status_t startAACRecording(); - status_t startRawAudioRecording(); - status_t startRTPRecording(); - status_t startMPEG2TSRecording(); + sp<IGraphicBufferProducer> mGraphicBufferProducer; + sp<ALooper> mLooper; + + status_t setupMPEG4Recording(); + void setupMPEG4MetaData(sp<MetaData> *meta); + status_t setupAMRRecording(); + status_t setupAACRecording(); + status_t setupRawAudioRecording(); + status_t setupRTPRecording(); + status_t setupMPEG2TSRecording(); sp<MediaSource> createAudioSource(); status_t checkVideoEncoderCapabilities( bool *supportsCameraSourceMetaDataMode); @@ -142,9 +143,6 @@ private: // depending on the videosource type status_t setupMediaSource(sp<MediaSource> *mediaSource); status_t setupCameraSource(sp<CameraSource> *cameraSource); - // setup the surfacemediasource for the encoder - status_t setupSurfaceMediaSource(); - status_t setupAudioEncoder(const sp<MediaWriter>& writer); status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source); diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp index 5d9728a..5795773 100644 --- a/media/libmediaplayerservice/TestPlayerStub.cpp +++ b/media/libmediaplayerservice/TestPlayerStub.cpp @@ -113,7 +113,9 @@ status_t TestPlayerStub::parseUrl() // Create the test player. // Call setDataSource on the test player with the url in param. status_t TestPlayerStub::setDataSource( - const char *url, const KeyedVector<String8, String8> *headers) { + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers) { if (!isTestUrl(url) || NULL != mHandle) { return INVALID_OPERATION; } @@ -162,7 +164,7 @@ status_t TestPlayerStub::setDataSource( } mPlayer = (*mNewPlayer)(); - return mPlayer->setDataSource(mContentUrl, headers); + return mPlayer->setDataSource(httpService, mContentUrl, headers); } // Internal cleanup. diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h index a3802eb..55bf2c8 100644 --- a/media/libmediaplayerservice/TestPlayerStub.h +++ b/media/libmediaplayerservice/TestPlayerStub.h @@ -66,7 +66,9 @@ class TestPlayerStub : public MediaPlayerInterface { // @param url Should be a test url. See class comment. virtual status_t setDataSource( - const char* url, const KeyedVector<String8, String8> *headers); + const sp<IMediaHTTPService> &httpService, + const char* url, + const KeyedVector<String8, String8> *headers); // Test player for a file descriptor source is not supported. virtual status_t setDataSource(int, int64_t, int64_t) { diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index b04e7a6..06aac33 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -33,17 +33,16 @@ namespace android { NuPlayer::GenericSource::GenericSource( const sp<AMessage> ¬ify, + const sp<IMediaHTTPService> &httpService, const char *url, - const KeyedVector<String8, String8> *headers, - bool uidValid, - uid_t uid) + const KeyedVector<String8, String8> *headers) : Source(notify), mDurationUs(0ll), mAudioIsVorbis(false) { DataSource::RegisterDefaultSniffers(); sp<DataSource> dataSource = - DataSource::CreateFromURI(url, headers); + DataSource::CreateFromURI(httpService, url, headers); CHECK(dataSource != NULL); initFromDataSource(dataSource); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 2da680c..20d597e 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -33,10 +33,9 @@ struct MediaSource; struct NuPlayer::GenericSource : public NuPlayer::Source { GenericSource( const sp<AMessage> ¬ify, + const sp<IMediaHTTPService> &httpService, const char *url, - const KeyedVector<String8, String8> *headers, - bool uidValid = false, - uid_t uid = 0); + const KeyedVector<String8, String8> *headers); GenericSource( const sp<AMessage> ¬ify, diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp index f1782cc..ac2aab8 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp @@ -24,6 +24,7 @@ #include "LiveDataSource.h" #include "LiveSession.h" +#include <media/IMediaHTTPService.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -34,13 +35,12 @@ namespace android { NuPlayer::HTTPLiveSource::HTTPLiveSource( const sp<AMessage> ¬ify, + const sp<IMediaHTTPService> &httpService, const char *url, - const KeyedVector<String8, String8> *headers, - bool uidValid, uid_t uid) + const KeyedVector<String8, String8> *headers) : Source(notify), + mHTTPService(httpService), mURL(url), - mUIDValid(uidValid), - mUID(uid), mFlags(0), mFinalResult(OK), mOffset(0), @@ -79,8 +79,7 @@ void NuPlayer::HTTPLiveSource::prepareAsync() { mLiveSession = new LiveSession( notify, (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0, - mUIDValid, - mUID); + mHTTPService); mLiveLooper->registerHandler(mLiveSession); diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h index bcc3f8b..4d7251f 100644 --- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h +++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h @@ -28,10 +28,9 @@ struct LiveSession; struct NuPlayer::HTTPLiveSource : public NuPlayer::Source { HTTPLiveSource( const sp<AMessage> ¬ify, + const sp<IMediaHTTPService> &httpService, const char *url, - const KeyedVector<String8, String8> *headers, - bool uidValid = false, - uid_t uid = 0); + const KeyedVector<String8, String8> *headers); virtual void prepareAsync(); virtual void start(); @@ -61,10 +60,9 @@ private: kWhatFetchSubtitleData, }; + sp<IMediaHTTPService> mHTTPService; AString mURL; KeyedVector<String8, String8> mExtraHeaders; - bool mUIDValid; - uid_t mUID; uint32_t mFlags; status_t mFinalResult; off64_t mOffset; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 3669a5b..817395a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -212,7 +212,9 @@ static bool IsHTTPLiveURL(const char *url) { } void NuPlayer::setDataSourceAsync( - const char *url, const KeyedVector<String8, String8> *headers) { + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers) { sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); size_t len = strlen(url); @@ -220,16 +222,18 @@ void NuPlayer::setDataSourceAsync( sp<Source> source; if (IsHTTPLiveURL(url)) { - source = new HTTPLiveSource(notify, url, headers, mUIDValid, mUID); + source = new HTTPLiveSource(notify, httpService, url, headers); } else if (!strncasecmp(url, "rtsp://", 7)) { - source = new RTSPSource(notify, url, headers, mUIDValid, mUID); + source = new RTSPSource( + notify, httpService, url, headers, mUIDValid, mUID); } else if ((!strncasecmp(url, "http://", 7) || !strncasecmp(url, "https://", 8)) && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) || strstr(url, ".sdp?"))) { - source = new RTSPSource(notify, url, headers, mUIDValid, mUID, true); + source = new RTSPSource( + notify, httpService, url, headers, mUIDValid, mUID, true); } else { - source = new GenericSource(notify, url, headers, mUIDValid, mUID); + source = new GenericSource(notify, httpService, url, headers); } msg->setObject("source", source); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 590e1f2..9dfe4a0 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -38,7 +38,9 @@ struct NuPlayer : public AHandler { void setDataSourceAsync(const sp<IStreamSource> &source); void setDataSourceAsync( - const char *url, const KeyedVector<String8, String8> *headers); + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers); void setDataSourceAsync(int fd, int64_t offset, int64_t length); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 47834fd..d35d1df 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -70,7 +70,9 @@ status_t NuPlayerDriver::setUID(uid_t uid) { } status_t NuPlayerDriver::setDataSource( - const char *url, const KeyedVector<String8, String8> *headers) { + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers) { Mutex::Autolock autoLock(mLock); if (mState != STATE_IDLE) { @@ -79,7 +81,7 @@ status_t NuPlayerDriver::setDataSource( mState = STATE_SET_DATASOURCE_PENDING; - mPlayer->setDataSourceAsync(url, headers); + mPlayer->setDataSourceAsync(httpService, url, headers); while (mState == STATE_SET_DATASOURCE_PENDING) { mCondition.wait(mLock); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 99f72a6..0148fb1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -31,7 +31,9 @@ struct NuPlayerDriver : public MediaPlayerInterface { virtual status_t setUID(uid_t uid); virtual status_t setDataSource( - const char *url, const KeyedVector<String8, String8> *headers); + const sp<IMediaHTTPService> &httpService, + const char *url, + const KeyedVector<String8, String8> *headers); virtual status_t setDataSource(int fd, int64_t offset, int64_t length); diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp index 18cf6d1..94800ba 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp @@ -24,6 +24,7 @@ #include "MyHandler.h" #include "SDPLoader.h" +#include <media/IMediaHTTPService.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaData.h> @@ -33,12 +34,14 @@ const int64_t kNearEOSTimeoutUs = 2000000ll; // 2 secs NuPlayer::RTSPSource::RTSPSource( const sp<AMessage> ¬ify, + const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers, bool uidValid, uid_t uid, bool isSDP) : Source(notify), + mHTTPService(httpService), mURL(url), mUIDValid(uidValid), mUID(uid), @@ -92,7 +95,7 @@ void NuPlayer::RTSPSource::prepareAsync() { if (mIsSDP) { mSDPLoader = new SDPLoader(notify, (mFlags & kFlagIncognito) ? SDPLoader::kFlagIncognito : 0, - mUIDValid, mUID); + mHTTPService); mSDPLoader->load( mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h index 8cf34a0..3718bf9 100644 --- a/media/libmediaplayerservice/nuplayer/RTSPSource.h +++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h @@ -34,6 +34,7 @@ struct SDPLoader; struct NuPlayer::RTSPSource : public NuPlayer::Source { RTSPSource( const sp<AMessage> ¬ify, + const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers, bool uidValid = false, @@ -88,6 +89,7 @@ private: bool mNPTMappingValid; }; + sp<IMediaHTTPService> mHTTPService; AString mURL; KeyedVector<String8, String8> mExtraHeaders; bool mUIDValid; diff --git a/media/libnbaio/PipeReader.cpp b/media/libnbaio/PipeReader.cpp index d786b84..24da1bd 100644 --- a/media/libnbaio/PipeReader.cpp +++ b/media/libnbaio/PipeReader.cpp @@ -59,7 +59,7 @@ ssize_t PipeReader::availableToRead() return avail; } -ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS) +ssize_t PipeReader::read(void *buffer, size_t count, int64_t readPTS __unused) { ssize_t avail = availableToRead(); if (CC_UNLIKELY(avail <= 0)) { diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index c9f89fc..f2354b4 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -374,7 +374,8 @@ ACodec::ACodec() mStoreMetaDataInOutputBuffers(false), mMetaDataBuffersToSubmit(0), mRepeatFrameDelayUs(-1ll), - mMaxPtsGapUs(-1l) { + mMaxPtsGapUs(-1l), + mCreateInputBuffersSuspended(false) { mUninitializedState = new UninitializedState(this); mLoadedState = new LoadedState(this); mLoadedToIdleState = new LoadedToIdleState(this); @@ -1120,6 +1121,12 @@ status_t ACodec::configureCodec( if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) { mMaxPtsGapUs = -1l; } + + if (!msg->findInt32( + "create-input-buffers-suspended", + (int32_t*)&mCreateInputBuffersSuspended)) { + mCreateInputBuffersSuspended = false; + } } // Always try to enable dynamic output buffers on native surface @@ -3941,6 +3948,22 @@ void ACodec::LoadedState::onCreateInputSurface( if (err != OK) { ALOGE("[%s] Unable to configure max timestamp gap (err %d)", + mCodec->mComponentName.c_str(), + err); + } + } + + if (err == OK && mCodec->mCreateInputBuffersSuspended) { + bool suspend = true; + err = mCodec->mOMX->setInternalOption( + mCodec->mNode, + kPortIndexInput, + IOMX::INTERNAL_OPTION_SUSPEND, + &suspend, + sizeof(suspend)); + + if (err != OK) { + ALOGE("[%s] Unable to configure option to suspend (err %d)", mCodec->mComponentName.c_str(), err); } @@ -4003,6 +4026,7 @@ status_t ACodec::LoadedToIdleState::allocateBuffers() { bool ACodec::LoadedToIdleState::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { + case kWhatSetParameters: case kWhatShutdown: { mCodec->deferMessage(msg); @@ -4069,6 +4093,7 @@ void ACodec::IdleToExecutingState::stateEntered() { bool ACodec::IdleToExecutingState::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { + case kWhatSetParameters: case kWhatShutdown: { mCodec->deferMessage(msg); @@ -4338,6 +4363,22 @@ status_t ACodec::setParameters(const sp<AMessage> ¶ms) { } } + int64_t skipFramesBeforeUs; + if (params->findInt64("skip-frames-before", &skipFramesBeforeUs)) { + status_t err = + mOMX->setInternalOption( + mNode, + kPortIndexInput, + IOMX::INTERNAL_OPTION_START_TIME, + &skipFramesBeforeUs, + sizeof(skipFramesBeforeUs)); + + if (err != OK) { + ALOGE("Failed to set parameter 'skip-frames-before' (err %d)", err); + return err; + } + } + int32_t dropInputFrames; if (params->findInt32("drop-input-frames", &dropInputFrames)) { bool suspend = dropInputFrames != 0; diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 6a2a696..63f9399 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -30,8 +30,10 @@ LOCAL_SRC_FILES:= \ MediaBufferGroup.cpp \ MediaCodec.cpp \ MediaCodecList.cpp \ + MediaCodecSource.cpp \ MediaDefs.cpp \ MediaExtractor.cpp \ + http/MediaHTTP.cpp \ MediaMuxer.cpp \ MediaSource.cpp \ MetaData.cpp \ @@ -103,13 +105,6 @@ LOCAL_STATIC_LIBRARIES := \ libFLAC \ libmedia_helper -LOCAL_SRC_FILES += \ - chromium_http_stub.cpp -LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1 - -LOCAL_SHARED_LIBRARIES += libstlport -include external/stlport/libstlport.mk - LOCAL_SHARED_LIBRARIES += \ libstagefright_enc_common \ libstagefright_avc_common \ diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index aae6800..67ea052 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -34,6 +34,8 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> +#include <media/IMediaHTTPConnection.h> +#include <media/IMediaHTTPService.h> #include <media/IMediaPlayerService.h> #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/foundation/ADebug.h> @@ -44,6 +46,7 @@ #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaExtractor.h> +#include <media/stagefright/MediaHTTP.h> #include <media/stagefright/MediaSource.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/OMXCodec.h> @@ -276,15 +279,20 @@ void AwesomePlayer::setUID(uid_t uid) { } status_t AwesomePlayer::setDataSource( - const char *uri, const KeyedVector<String8, String8> *headers) { + const sp<IMediaHTTPService> &httpService, + const char *uri, + const KeyedVector<String8, String8> *headers) { Mutex::Autolock autoLock(mLock); - return setDataSource_l(uri, headers); + return setDataSource_l(httpService, uri, headers); } status_t AwesomePlayer::setDataSource_l( - const char *uri, const KeyedVector<String8, String8> *headers) { + const sp<IMediaHTTPService> &httpService, + const char *uri, + const KeyedVector<String8, String8> *headers) { reset_l(); + mHTTPService = httpService; mUri = uri; if (headers) { @@ -581,6 +589,7 @@ void AwesomePlayer::reset_l() { mSeekNotificationSent = true; mSeekTimeUs = 0; + mHTTPService.clear(); mUri.setTo(""); mUriHeaders.clear(); @@ -1482,7 +1491,7 @@ void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& so CHECK(source != NULL); if (mTextDriver == NULL) { - mTextDriver = new TimedTextDriver(mListener); + mTextDriver = new TimedTextDriver(mListener, mHTTPService); } mTextDriver->addInBandTextSource(trackIndex, source); @@ -2192,15 +2201,14 @@ status_t AwesomePlayer::finishSetDataSource_l() { if (!strncasecmp("http://", mUri.string(), 7) || !strncasecmp("https://", mUri.string(), 8) || isWidevineStreaming) { - mConnectingDataSource = HTTPBase::Create( - (mFlags & INCOGNITO) - ? HTTPBase::kFlagIncognito - : 0); - - if (mUIDValid) { - mConnectingDataSource->setUID(mUID); + if (mHTTPService == NULL) { + ALOGE("Attempt to play media from http URI without HTTP service."); + return UNKNOWN_ERROR; } + sp<IMediaHTTPConnection> conn = mHTTPService->makeHTTPConnection(); + mConnectingDataSource = new MediaHTTP(conn); + String8 cacheConfig; bool disconnectAtHighwatermark; NuCachedSource2::RemoveCacheSpecificHeaders( @@ -2316,7 +2324,8 @@ status_t AwesomePlayer::finishSetDataSource_l() { } } } else { - dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); + dataSource = DataSource::CreateFromURI( + mHTTPService, mUri.string(), &mUriHeaders); } if (dataSource == NULL) { @@ -2758,7 +2767,7 @@ status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) { { Mutex::Autolock autoLock(mLock); if (mTextDriver == NULL) { - mTextDriver = new TimedTextDriver(mListener); + mTextDriver = new TimedTextDriver(mListener, mHTTPService); } // String values written in Parcel are UTF-16 values. String8 uri(request.readString16()); @@ -2770,7 +2779,7 @@ status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) { { Mutex::Autolock autoLock(mLock); if (mTextDriver == NULL) { - mTextDriver = new TimedTextDriver(mListener); + mTextDriver = new TimedTextDriver(mListener, mHTTPService); } int fd = request.readFileDescriptor(); off64_t offset = request.readInt64(); @@ -2899,6 +2908,8 @@ void AwesomePlayer::onAudioTearDownEvent() { // get current position so we can start recreated stream from here getPosition(&mAudioTearDownPosition); + sp<IMediaHTTPService> savedHTTPService = mHTTPService; + // Reset and recreate reset_l(); @@ -2908,7 +2919,7 @@ void AwesomePlayer::onAudioTearDownEvent() { mFileSource = fileSource; err = setDataSource_l(fileSource); } else { - err = setDataSource_l(uri, &uriHeaders); + err = setDataSource_l(savedHTTPService, uri, &uriHeaders); } mFlags |= PREPARING; diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 97987e2..2704b74 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -16,10 +16,6 @@ #include "include/AMRExtractor.h" -#if CHROMIUM_AVAILABLE -#include "include/chromium_http_stub.h" -#endif - #include "include/AACExtractor.h" #include "include/DRMExtractor.h" #include "include/FLACExtractor.h" @@ -35,10 +31,13 @@ #include "matroska/MatroskaExtractor.h" +#include <media/IMediaHTTPConnection.h> +#include <media/IMediaHTTPService.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/FileSource.h> #include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaHTTP.h> #include <utils/String8.h> #include <cutils/properties.h> @@ -180,7 +179,9 @@ void DataSource::RegisterDefaultSniffers() { // static sp<DataSource> DataSource::CreateFromURI( - const char *uri, const KeyedVector<String8, String8> *headers) { + const sp<IMediaHTTPService> &httpService, + const char *uri, + const KeyedVector<String8, String8> *headers) { bool isWidevine = !strncasecmp("widevine://", uri, 11); sp<DataSource> source; @@ -189,7 +190,7 @@ sp<DataSource> DataSource::CreateFromURI( } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8) || isWidevine) { - sp<HTTPBase> httpSource = HTTPBase::Create(); + sp<HTTPBase> httpSource = new MediaHTTP(httpService->makeHTTPConnection()); String8 tmp; if (isWidevine) { @@ -220,11 +221,6 @@ sp<DataSource> DataSource::CreateFromURI( // in the widevine:// case. source = httpSource; } - -# if CHROMIUM_AVAILABLE - } else if (!strncasecmp("data:", uri, 5)) { - source = createDataUriSource(uri); -#endif } else { // Assume it's a filename. source = new FileSource(uri); diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp index 5fa4b6f..ca68c3d 100644 --- a/media/libstagefright/HTTPBase.cpp +++ b/media/libstagefright/HTTPBase.cpp @@ -20,10 +20,6 @@ #include "include/HTTPBase.h" -#if CHROMIUM_AVAILABLE -#include "include/chromium_http_stub.h" -#endif - #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALooper.h> @@ -40,34 +36,7 @@ HTTPBase::HTTPBase() mTotalTransferBytes(0), mPrevBandwidthMeasureTimeUs(0), mPrevEstimatedBandWidthKbps(0), - mBandWidthCollectFreqMs(5000), - mUIDValid(false), - mUID(0) { -} - -// static -sp<HTTPBase> HTTPBase::Create(uint32_t flags) { -#if CHROMIUM_AVAILABLE - HTTPBase *dataSource = createChromiumHTTPDataSource(flags); - if (dataSource) { - return dataSource; - } -#endif - { - TRESPASS(); - - return NULL; - } -} - -// static -status_t HTTPBase::UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { -#if CHROMIUM_AVAILABLE - return UpdateChromiumHTTPDataSourceProxyConfig(host, port, exclusionList); -#else - return INVALID_OPERATION; -#endif + mBandWidthCollectFreqMs(5000) { } void HTTPBase::addBandwidthMeasurement( @@ -135,21 +104,6 @@ status_t HTTPBase::setBandwidthStatCollectFreq(int32_t freqMs) { return OK; } -void HTTPBase::setUID(uid_t uid) { - mUIDValid = true; - mUID = uid; -} - -bool HTTPBase::getUID(uid_t *uid) const { - if (!mUIDValid) { - return false; - } - - *uid = mUID; - - return true; -} - // static void HTTPBase::RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag) { int res = qtaguid_tagSocket(sockfd, kTag, uid); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index b7a4b75..0fa3b2d 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -1763,7 +1763,7 @@ status_t MPEG4Writer::Track::pause() { } status_t MPEG4Writer::Track::stop() { - ALOGD("Stopping %s track", mIsAudio? "Audio": "Video"); + ALOGD("%s track stopping", mIsAudio? "Audio": "Video"); if (!mStarted) { ALOGE("Stop() called but track is not started"); return ERROR_END_OF_STREAM; @@ -1774,19 +1774,14 @@ status_t MPEG4Writer::Track::stop() { } mDone = true; + ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); + mSource->stop(); + ALOGD("%s track source stopped", mIsAudio? "Audio": "Video"); + void *dummy; pthread_join(mThread, &dummy); - status_t err = (status_t) dummy; - ALOGD("Stopping %s track source", mIsAudio? "Audio": "Video"); - { - status_t status = mSource->stop(); - if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { - err = status; - } - } - ALOGD("%s track stopped", mIsAudio? "Audio": "Video"); return err; } diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp new file mode 100644 index 0000000..2c20d62 --- /dev/null +++ b/media/libstagefright/MediaCodecSource.cpp @@ -0,0 +1,881 @@ +/* + * Copyright 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 "MediaCodecSource" +#define DEBUG_DRIFT_TIME 0 +#include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> +#include <media/ICrypto.h> +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/ALooper.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MediaCodec.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/MediaCodecSource.h> +#include <media/stagefright/Utils.h> + +namespace android { + +static void ReleaseMediaBufferReference(const sp<ABuffer> &accessUnit) { + void *mbuf; + if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf) + && mbuf != NULL) { + ALOGV("releasing mbuf %p", mbuf); + + accessUnit->meta()->setPointer("mediaBuffer", NULL); + + static_cast<MediaBuffer *>(mbuf)->release(); + mbuf = NULL; + } +} + +struct MediaCodecSource::Puller : public AHandler { + Puller(const sp<MediaSource> &source); + + status_t start(const sp<MetaData> &meta, const sp<AMessage> ¬ify); + void stopAsync(); + + void pause(); + void resume(); + +protected: + virtual void onMessageReceived(const sp<AMessage> &msg); + virtual ~Puller(); + +private: + enum { + kWhatStart = 'msta', + kWhatStop, + kWhatPull, + kWhatPause, + kWhatResume, + }; + + sp<MediaSource> mSource; + sp<AMessage> mNotify; + sp<ALooper> mLooper; + int32_t mPullGeneration; + bool mIsAudio; + bool mPaused; + bool mReachedEOS; + + status_t postSynchronouslyAndReturnError(const sp<AMessage> &msg); + void schedulePull(); + void handleEOS(); + + DISALLOW_EVIL_CONSTRUCTORS(Puller); +}; + +MediaCodecSource::Puller::Puller(const sp<MediaSource> &source) + : mSource(source), + mLooper(new ALooper()), + mPullGeneration(0), + mIsAudio(false), + mPaused(false), + mReachedEOS(false) { + sp<MetaData> meta = source->getFormat(); + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + mIsAudio = !strncasecmp(mime, "audio/", 6); + + mLooper->setName("pull_looper"); +} + +MediaCodecSource::Puller::~Puller() { + mLooper->unregisterHandler(id()); + mLooper->stop(); +} + +status_t MediaCodecSource::Puller::postSynchronouslyAndReturnError( + const sp<AMessage> &msg) { + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + + if (err != OK) { + return err; + } + + if (!response->findInt32("err", &err)) { + err = OK; + } + + return err; +} + +status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, + const sp<AMessage> ¬ify) { + ALOGV("puller (%s) start", mIsAudio ? "audio" : "video"); + mLooper->start( + false /* runOnCallingThread */, + false /* canCallJava */, + PRIORITY_AUDIO); + mLooper->registerHandler(this); + mNotify = notify; + + sp<AMessage> msg = new AMessage(kWhatStart, id()); + msg->setObject("meta", meta); + return postSynchronouslyAndReturnError(msg); +} + +void MediaCodecSource::Puller::stopAsync() { + ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video"); + (new AMessage(kWhatStop, id()))->post(); +} + +void MediaCodecSource::Puller::pause() { + (new AMessage(kWhatPause, id()))->post(); +} + +void MediaCodecSource::Puller::resume() { + (new AMessage(kWhatResume, id()))->post(); +} + +void MediaCodecSource::Puller::schedulePull() { + sp<AMessage> msg = new AMessage(kWhatPull, id()); + msg->setInt32("generation", mPullGeneration); + msg->post(); +} + +void MediaCodecSource::Puller::handleEOS() { + if (!mReachedEOS) { + ALOGV("puller (%s) posting EOS", mIsAudio ? "audio" : "video"); + mReachedEOS = true; + sp<AMessage> notify = mNotify->dup(); + notify->setPointer("accessUnit", NULL); + notify->post(); + } +} + +void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatStart: + { + sp<RefBase> obj; + CHECK(msg->findObject("meta", &obj)); + + mReachedEOS = false; + + status_t err = mSource->start(static_cast<MetaData *>(obj.get())); + + if (err == OK) { + schedulePull(); + } + + sp<AMessage> response = new AMessage; + response->setInt32("err", err); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + response->postReply(replyID); + break; + } + + case kWhatStop: + { + ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video"); + mSource->stop(); + ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video"); + ++mPullGeneration; + + handleEOS(); + break; + } + + case kWhatPull: + { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + + if (generation != mPullGeneration) { + break; + } + + MediaBuffer *mbuf; + status_t err = mSource->read(&mbuf); + + if (mPaused) { + if (err == OK) { + mbuf->release(); + mbuf = NULL; + } + + msg->post(); + break; + } + + if (err != OK) { + if (err == ERROR_END_OF_STREAM) { + ALOGV("stream ended, mbuf %p", mbuf); + } else { + ALOGE("error %d reading stream.", err); + } + handleEOS(); + } else { + sp<AMessage> notify = mNotify->dup(); + + notify->setPointer("accessUnit", mbuf); + notify->post(); + + msg->post(); + } + break; + } + + case kWhatPause: + { + mPaused = true; + break; + } + + case kWhatResume: + { + mPaused = false; + break; + } + + default: + TRESPASS(); + } +} + +// static +sp<MediaCodecSource> MediaCodecSource::Create( + const sp<ALooper> &looper, + const sp<AMessage> &format, + const sp<MediaSource> &source, + uint32_t flags) { + sp<MediaCodecSource> mediaSource = + new MediaCodecSource(looper, format, source, flags); + + if (mediaSource->init() == OK) { + return mediaSource; + } + return NULL; +} + +status_t MediaCodecSource::start(MetaData* params) { + sp<AMessage> msg = new AMessage(kWhatStart, mReflector->id()); + msg->setObject("meta", params); + return postSynchronouslyAndReturnError(msg); +} + +status_t MediaCodecSource::stop() { + sp<AMessage> msg = new AMessage(kWhatStop, mReflector->id()); + return postSynchronouslyAndReturnError(msg); +} + +status_t MediaCodecSource::pause() { + (new AMessage(kWhatPause, mReflector->id()))->post(); + return OK; +} + +sp<IGraphicBufferProducer> MediaCodecSource::getGraphicBufferProducer() { + CHECK(mFlags & FLAG_USE_SURFACE_INPUT); + return mGraphicBufferProducer; +} + +status_t MediaCodecSource::read(MediaBuffer** buffer, + const ReadOptions* options) { + Mutex::Autolock autolock(mOutputBufferLock); + + *buffer = NULL; + while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) { + mOutputBufferCond.wait(mOutputBufferLock); + } + if (!mEncodedReachedEOS) { + *buffer = *mOutputBufferQueue.begin(); + mOutputBufferQueue.erase(mOutputBufferQueue.begin()); + return OK; + } + return mErrorCode; +} + +void MediaCodecSource::signalBufferReturned(MediaBuffer *buffer) { + buffer->setObserver(0); + buffer->release(); +} + +MediaCodecSource::MediaCodecSource( + const sp<ALooper> &looper, + const sp<AMessage> &outputFormat, + const sp<MediaSource> &source, + uint32_t flags) + : mLooper(looper), + mOutputFormat(outputFormat), + mMeta(new MetaData), + mFlags(flags), + mIsVideo(false), + mStarted(false), + mStopping(false), + mDoMoreWorkPending(false), + mPullerReachedEOS(false), + mFirstSampleTimeUs(-1ll), + mEncodedReachedEOS(false), + mErrorCode(OK) { + CHECK(mLooper != NULL); + + AString mime; + CHECK(mOutputFormat->findString("mime", &mime)); + + if (!strncasecmp("video/", mime.c_str(), 6)) { + mIsVideo = true; + } + + if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { + mPuller = new Puller(source); + } +} + +MediaCodecSource::~MediaCodecSource() { + releaseEncoder(); + + mCodecLooper->stop(); + mLooper->unregisterHandler(mReflector->id()); +} + +status_t MediaCodecSource::init() { + status_t err = initEncoder(); + + if (err != OK) { + releaseEncoder(); + } + + return err; +} + +status_t MediaCodecSource::initEncoder() { + mReflector = new AHandlerReflector<MediaCodecSource>(this); + mLooper->registerHandler(mReflector); + + mCodecLooper = new ALooper; + mCodecLooper->setName("codec_looper"); + mCodecLooper->start(); + + if (mFlags & FLAG_USE_METADATA_INPUT) { + mOutputFormat->setInt32("store-metadata-in-buffers", 1); + } + + if (mFlags & FLAG_USE_SURFACE_INPUT) { + mOutputFormat->setInt32("create-input-buffers-suspended", 1); + } + + AString outputMIME; + CHECK(mOutputFormat->findString("mime", &outputMIME)); + + mEncoder = MediaCodec::CreateByType( + mCodecLooper, outputMIME.c_str(), true /* encoder */); + + if (mEncoder == NULL) { + return NO_INIT; + } + + ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str()); + + status_t err = mEncoder->configure( + mOutputFormat, + NULL /* nativeWindow */, + NULL /* crypto */, + MediaCodec::CONFIGURE_FLAG_ENCODE); + + if (err != OK) { + return err; + } + + mEncoder->getOutputFormat(&mOutputFormat); + convertMessageToMetaData(mOutputFormat, mMeta); + + if (mFlags & FLAG_USE_SURFACE_INPUT) { + CHECK(mIsVideo); + + err = mEncoder->createInputSurface(&mGraphicBufferProducer); + + if (err != OK) { + return err; + } + } + + err = mEncoder->start(); + + if (err != OK) { + return err; + } + + err = mEncoder->getInputBuffers(&mEncoderInputBuffers); + + if (err != OK) { + return err; + } + + err = mEncoder->getOutputBuffers(&mEncoderOutputBuffers); + + if (err != OK) { + return err; + } + + mEncodedReachedEOS = false; + mErrorCode = OK; + + return OK; +} + +void MediaCodecSource::releaseEncoder() { + if (mEncoder == NULL) { + return; + } + + mEncoder->release(); + mEncoder.clear(); + + while (!mInputBufferQueue.empty()) { + MediaBuffer *mbuf = *mInputBufferQueue.begin(); + mInputBufferQueue.erase(mInputBufferQueue.begin()); + if (mbuf != NULL) { + mbuf->release(); + } + } + + for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) { + sp<ABuffer> accessUnit = mEncoderInputBuffers.itemAt(i); + ReleaseMediaBufferReference(accessUnit); + } + + mEncoderInputBuffers.clear(); + mEncoderOutputBuffers.clear(); +} + +bool MediaCodecSource::reachedEOS() { + return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS); +} + +status_t MediaCodecSource::postSynchronouslyAndReturnError( + const sp<AMessage> &msg) { + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + + if (err != OK) { + return err; + } + + if (!response->findInt32("err", &err)) { + err = OK; + } + + return err; +} + +void MediaCodecSource::signalEOS(status_t err) { + if (!mEncodedReachedEOS) { + ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio"); + { + Mutex::Autolock autoLock(mOutputBufferLock); + // release all unread media buffers + for (List<MediaBuffer*>::iterator it = mOutputBufferQueue.begin(); + it != mOutputBufferQueue.end(); it++) { + (*it)->release(); + } + mOutputBufferQueue.clear(); + mEncodedReachedEOS = true; + mErrorCode = err; + mOutputBufferCond.signal(); + } + + releaseEncoder(); + } + if (mStopping && reachedEOS()) { + ALOGI("MediaCodecSource (%s) fully stopped", + mIsVideo ? "video" : "audio"); + // posting reply to everyone that's waiting + List<uint32_t>::iterator it; + for (it = mStopReplyIDQueue.begin(); + it != mStopReplyIDQueue.end(); it++) { + (new AMessage)->postReply(*it); + } + mStopReplyIDQueue.clear(); + mStopping = false; + } +} + +void MediaCodecSource::suspend() { + CHECK(mFlags & FLAG_USE_SURFACE_INPUT); + if (mEncoder != NULL) { + sp<AMessage> params = new AMessage; + params->setInt32("drop-input-frames", true); + mEncoder->setParameters(params); + } +} + +void MediaCodecSource::resume(int64_t skipFramesBeforeUs) { + CHECK(mFlags & FLAG_USE_SURFACE_INPUT); + if (mEncoder != NULL) { + sp<AMessage> params = new AMessage; + params->setInt32("drop-input-frames", false); + if (skipFramesBeforeUs > 0) { + params->setInt64("skip-frames-before", skipFramesBeforeUs); + } + mEncoder->setParameters(params); + } +} + +void MediaCodecSource::scheduleDoMoreWork() { + if (mDoMoreWorkPending) { + return; + } + + mDoMoreWorkPending = true; + + if (mEncoderActivityNotify == NULL) { + mEncoderActivityNotify = new AMessage( + kWhatEncoderActivity, mReflector->id()); + } + mEncoder->requestActivityNotification(mEncoderActivityNotify); +} + +status_t MediaCodecSource::feedEncoderInputBuffers() { + while (!mInputBufferQueue.empty() + && !mAvailEncoderInputIndices.empty()) { + MediaBuffer* mbuf = *mInputBufferQueue.begin(); + mInputBufferQueue.erase(mInputBufferQueue.begin()); + + size_t bufferIndex = *mAvailEncoderInputIndices.begin(); + mAvailEncoderInputIndices.erase(mAvailEncoderInputIndices.begin()); + + int64_t timeUs = 0ll; + uint32_t flags = 0; + size_t size = 0; + + if (mbuf != NULL) { + CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); + + // push decoding time for video, or drift time for audio + if (mIsVideo) { + mDecodingTimeQueue.push_back(timeUs); + } else { +#if DEBUG_DRIFT_TIME + if (mFirstSampleTimeUs < 0ll) { + mFirstSampleTimeUs = timeUs; + } + + int64_t driftTimeUs = 0; + if (mbuf->meta_data()->findInt64(kKeyDriftTime, &driftTimeUs) + && driftTimeUs) { + driftTimeUs = timeUs - mFirstSampleTimeUs - driftTimeUs; + } + mDriftTimeQueue.push_back(driftTimeUs); +#endif // DEBUG_DRIFT_TIME + } + + size = mbuf->size(); + + memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(), + mbuf->data(), size); + + if (mIsVideo) { + // video encoder will release MediaBuffer when done + // with underlying data. + mEncoderInputBuffers.itemAt(bufferIndex)->meta() + ->setPointer("mediaBuffer", mbuf); + } else { + mbuf->release(); + } + } else { + flags = MediaCodec::BUFFER_FLAG_EOS; + } + + status_t err = mEncoder->queueInputBuffer( + bufferIndex, 0, size, timeUs, flags); + + if (err != OK) { + return err; + } + } + + return OK; +} + +status_t MediaCodecSource::doMoreWork() { + status_t err; + + if (!(mFlags & FLAG_USE_SURFACE_INPUT)) { + for (;;) { + size_t bufferIndex; + err = mEncoder->dequeueInputBuffer(&bufferIndex); + + if (err != OK) { + break; + } + + mAvailEncoderInputIndices.push_back(bufferIndex); + } + + feedEncoderInputBuffers(); + } + + for (;;) { + size_t bufferIndex; + size_t offset; + size_t size; + int64_t timeUs; + uint32_t flags; + native_handle_t* handle = NULL; + err = mEncoder->dequeueOutputBuffer( + &bufferIndex, &offset, &size, &timeUs, &flags); + + if (err != OK) { + if (err == INFO_FORMAT_CHANGED) { + continue; + } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) { + mEncoder->getOutputBuffers(&mEncoderOutputBuffers); + continue; + } + + if (err == -EAGAIN) { + err = OK; + } + break; + } + if (!(flags & MediaCodec::BUFFER_FLAG_EOS)) { + sp<ABuffer> outbuf = mEncoderOutputBuffers.itemAt(bufferIndex); + + MediaBuffer *mbuf = new MediaBuffer(outbuf->size()); + memcpy(mbuf->data(), outbuf->data(), outbuf->size()); + + if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) { + if (mIsVideo) { + int64_t decodingTimeUs; + if (mFlags & FLAG_USE_SURFACE_INPUT) { + // GraphicBufferSource is supposed to discard samples + // queued before start, and offset timeUs by start time + CHECK_GE(timeUs, 0ll); + // TODO: + // Decoding time for surface source is unavailable, + // use presentation time for now. May need to move + // this logic into MediaCodec. + decodingTimeUs = timeUs; + } else { + CHECK(!mDecodingTimeQueue.empty()); + decodingTimeUs = *(mDecodingTimeQueue.begin()); + mDecodingTimeQueue.erase(mDecodingTimeQueue.begin()); + } + mbuf->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs); + + ALOGV("[video] time %lld us (%.2f secs), dts/pts diff %lld", + timeUs, timeUs / 1E6, decodingTimeUs - timeUs); + } else { + int64_t driftTimeUs = 0; +#if DEBUG_DRIFT_TIME + CHECK(!mDriftTimeQueue.empty()); + driftTimeUs = *(mDriftTimeQueue.begin()); + mDriftTimeQueue.erase(mDriftTimeQueue.begin()); + mbuf->meta_data()->setInt64(kKeyDriftTime, driftTimeUs); +#endif // DEBUG_DRIFT_TIME + ALOGV("[audio] time %lld us (%.2f secs), drift %lld", + timeUs, timeUs / 1E6, driftTimeUs); + } + mbuf->meta_data()->setInt64(kKeyTime, timeUs); + } else { + mbuf->meta_data()->setInt32(kKeyIsCodecConfig, true); + } + if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) { + mbuf->meta_data()->setInt32(kKeyIsSyncFrame, true); + } + mbuf->setObserver(this); + mbuf->add_ref(); + + { + Mutex::Autolock autoLock(mOutputBufferLock); + mOutputBufferQueue.push_back(mbuf); + mOutputBufferCond.signal(); + } + } + + mEncoder->releaseOutputBuffer(bufferIndex); + + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + err = ERROR_END_OF_STREAM; + break; + } + } + + return err; +} + +status_t MediaCodecSource::onStart(MetaData *params) { + if (mStopping) { + ALOGE("Failed to start while we're stopping"); + return INVALID_OPERATION; + } + + if (mStarted) { + ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio"); + if (mFlags & FLAG_USE_SURFACE_INPUT) { + resume(); + } else { + CHECK(mPuller != NULL); + mPuller->resume(); + } + return OK; + } + + ALOGI("MediaCodecSource (%s) starting", mIsVideo ? "video" : "audio"); + + status_t err = OK; + + if (mFlags & FLAG_USE_SURFACE_INPUT) { + int64_t startTimeUs; + if (!params || !params->findInt64(kKeyTime, &startTimeUs)) { + startTimeUs = -1ll; + } + resume(startTimeUs); + scheduleDoMoreWork(); + } else { + CHECK(mPuller != NULL); + sp<AMessage> notify = new AMessage( + kWhatPullerNotify, mReflector->id()); + err = mPuller->start(params, notify); + if (err != OK) { + mPullerReachedEOS = true; + return err; + } + } + + ALOGI("MediaCodecSource (%s) started", mIsVideo ? "video" : "audio"); + + mStarted = true; + return OK; +} + +void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { + switch (msg->what()) { + case kWhatPullerNotify: + { + MediaBuffer *mbuf; + CHECK(msg->findPointer("accessUnit", (void**)&mbuf)); + + if (mbuf == NULL) { + ALOGI("puller (%s) reached EOS", + mIsVideo ? "video" : "audio"); + mPullerReachedEOS = true; + } + + if (mEncoder == NULL) { + ALOGV("got msg '%s' after encoder shutdown.", + msg->debugString().c_str()); + + if (mbuf != NULL) { + mbuf->release(); + } else { + signalEOS(); + } + break; + } + + mInputBufferQueue.push_back(mbuf); + + feedEncoderInputBuffers(); + scheduleDoMoreWork(); + + break; + } + case kWhatEncoderActivity: + { + mDoMoreWorkPending = false; + + if (mEncoder == NULL) { + break; + } + + status_t err = doMoreWork(); + + if (err == OK) { + scheduleDoMoreWork(); + } else { + // reached EOS, or error + signalEOS(err); + } + + break; + } + case kWhatStart: + { + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp<RefBase> obj; + CHECK(msg->findObject("meta", &obj)); + MetaData *params = static_cast<MetaData *>(obj.get()); + + sp<AMessage> response = new AMessage; + response->setInt32("err", onStart(params)); + response->postReply(replyID); + break; + } + case kWhatStop: + { + ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio"); + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + if (reachedEOS()) { + // if we already reached EOS, reply and return now + ALOGI("MediaCodecSource (%s) already stopped", + mIsVideo ? "video" : "audio"); + (new AMessage)->postReply(replyID); + break; + } + + mStopReplyIDQueue.push_back(replyID); + if (mStopping) { + // nothing to do if we're already stopping, reply will be posted + // to all when we're stopped. + break; + } + + mStopping = true; + + // if using surface, signal source EOS and wait for EOS to come back. + // otherwise, release encoder and post EOS if haven't done already + if (mFlags & FLAG_USE_SURFACE_INPUT) { + mEncoder->signalEndOfInputStream(); + } else { + CHECK(mPuller != NULL); + mPuller->stopAsync(); + signalEOS(); + } + break; + } + case kWhatPause: + { + if (mFlags && FLAG_USE_SURFACE_INPUT) { + suspend(); + } else { + CHECK(mPuller != NULL); + mPuller->pause(); + } + break; + } + default: + TRESPASS(); + } +} + +} // namespace android diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index 05e599b..1287fb1 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -213,7 +213,14 @@ NuCachedSource2::NuCachedSource2( mLooper->setName("NuCachedSource2"); mLooper->registerHandler(mReflector); - mLooper->start(); + + // Since it may not be obvious why our looper thread needs to be + // able to call into java since it doesn't appear to do so at all... + // IMediaHTTPConnection may be (and most likely is) implemented in JAVA + // and a local JAVA IBinder will call directly into JNI methods. + // So whenever we call DataSource::readAt it may end up in a call to + // IMediaHTTPConnection::readAt and therefore call back into JAVA. + mLooper->start(false /* runOnCallingThread */, true /* canCallJava */); Mutex::Autolock autoLock(mLock); (new AMessage(kWhatFetchMore, mReflector->id()))->post(); diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp index 7bc7da2..64f56e9 100644 --- a/media/libstagefright/NuMediaExtractor.cpp +++ b/media/libstagefright/NuMediaExtractor.cpp @@ -58,7 +58,9 @@ NuMediaExtractor::~NuMediaExtractor() { } status_t NuMediaExtractor::setDataSource( - const char *path, const KeyedVector<String8, String8> *headers) { + const sp<IMediaHTTPService> &httpService, + const char *path, + const KeyedVector<String8, String8> *headers) { Mutex::Autolock autoLock(mLock); if (mImpl != NULL) { @@ -66,7 +68,7 @@ status_t NuMediaExtractor::setDataSource( } sp<DataSource> dataSource = - DataSource::CreateFromURI(path, headers); + DataSource::CreateFromURI(httpService, path, headers); if (dataSource == NULL) { return -ENOENT; diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp index af8186c..edd12fc 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -24,6 +24,7 @@ #include <media/stagefright/StagefrightMediaScanner.h> +#include <media/IMediaHTTPService.h> #include <media/mediametadataretriever.h> #include <private/media/VideoFrame.h> @@ -147,7 +148,7 @@ MediaScanResult StagefrightMediaScanner::processFileInternal( status_t status; if (fd < 0) { // couldn't open it locally, maybe the media server can? - status = mRetriever->setDataSource(path); + status = mRetriever->setDataSource(NULL /* httpService */, path); } else { status = mRetriever->setDataSource(fd, 0, 0x7ffffffffffffffL); close(fd); diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 19af4fb..b4f906e 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -20,6 +20,7 @@ #include "include/StagefrightMetadataRetriever.h" +#include <media/IMediaHTTPService.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/ColorConverter.h> #include <media/stagefright/DataSource.h> @@ -50,7 +51,9 @@ StagefrightMetadataRetriever::~StagefrightMetadataRetriever() { } status_t StagefrightMetadataRetriever::setDataSource( - const char *uri, const KeyedVector<String8, String8> *headers) { + const sp<IMediaHTTPService> &httpService, + const char *uri, + const KeyedVector<String8, String8> *headers) { ALOGV("setDataSource(%s)", uri); mParsedMetaData = false; @@ -58,7 +61,7 @@ status_t StagefrightMetadataRetriever::setDataSource( delete mAlbumArt; mAlbumArt = NULL; - mSource = DataSource::CreateFromURI(uri, headers); + mSource = DataSource::CreateFromURI(httpService, uri, headers); if (mSource == NULL) { ALOGE("Unable to create data source for '%s'.", uri); diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk deleted file mode 100644 index f26f386..0000000 --- a/media/libstagefright/chromium_http/Android.mk +++ /dev/null @@ -1,37 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -ifneq ($(TARGET_BUILD_PDK), true) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - DataUriSource.cpp \ - ChromiumHTTPDataSource.cpp \ - support.cpp \ - chromium_http_stub.cpp - -LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright \ - $(TOP)/frameworks/native/include/media/openmax \ - external/chromium \ - external/chromium/android - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_SHARED_LIBRARIES += \ - libstlport \ - libchromium_net \ - libutils \ - libcutils \ - liblog \ - libstagefright_foundation \ - libstagefright \ - libdrmframework - -include external/stlport/libstlport.mk - -LOCAL_MODULE:= libstagefright_chromium_http - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_SHARED_LIBRARY) -endif diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp deleted file mode 100644 index a862d8b..0000000 --- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2011 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 "ChromiumHTTPDataSource" -#include <media/stagefright/foundation/ADebug.h> - -#include "include/ChromiumHTTPDataSource.h" - -#include <media/stagefright/foundation/ALooper.h> -#include <media/stagefright/MediaErrors.h> - -#include "support.h" - -#include <cutils/properties.h> // for property_get - -namespace android { - -ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags) - : mFlags(flags), - mState(DISCONNECTED), - mDelegate(new SfDelegate), - mCurrentOffset(0), - mIOResult(OK), - mContentSize(-1), - mDecryptHandle(NULL), - mDrmManagerClient(NULL) { - mDelegate->setOwner(this); -} - -ChromiumHTTPDataSource::~ChromiumHTTPDataSource() { - disconnect(); - - delete mDelegate; - mDelegate = NULL; - - clearDRMState_l(); - - if (mDrmManagerClient != NULL) { - delete mDrmManagerClient; - mDrmManagerClient = NULL; - } -} - -status_t ChromiumHTTPDataSource::connect( - const char *uri, - const KeyedVector<String8, String8> *headers, - off64_t offset) { - Mutex::Autolock autoLock(mLock); - - uid_t uid; - if (getUID(&uid)) { - mDelegate->setUID(uid); - } - -#if defined(LOG_NDEBUG) && !LOG_NDEBUG - LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "connect on behalf of uid %d", uid); -#endif - - return connect_l(uri, headers, offset); -} - -status_t ChromiumHTTPDataSource::connect_l( - const char *uri, - const KeyedVector<String8, String8> *headers, - off64_t offset) { - if (mState != DISCONNECTED) { - disconnect_l(); - } - -#if defined(LOG_NDEBUG) && !LOG_NDEBUG - LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, - "connect to <URL suppressed> @%lld", offset); -#endif - - mURI = uri; - mContentType = String8("application/octet-stream"); - - if (headers != NULL) { - mHeaders = *headers; - } else { - mHeaders.clear(); - } - - mState = CONNECTING; - mContentSize = -1; - mCurrentOffset = offset; - - mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset); - - while (mState == CONNECTING || mState == DISCONNECTING) { - mCondition.wait(mLock); - } - - return mState == CONNECTED ? OK : mIOResult; -} - -void ChromiumHTTPDataSource::onConnectionEstablished( - int64_t contentSize, const char *contentType) { - Mutex::Autolock autoLock(mLock); - - if (mState != CONNECTING) { - // We may have initiated disconnection. - CHECK_EQ(mState, DISCONNECTING); - return; - } - - mState = CONNECTED; - mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset; - mContentType = String8(contentType); - mCondition.broadcast(); -} - -void ChromiumHTTPDataSource::onConnectionFailed(status_t err) { - Mutex::Autolock autoLock(mLock); - mState = DISCONNECTED; - mCondition.broadcast(); - - // mURI.clear(); - - mIOResult = err; -} - -void ChromiumHTTPDataSource::disconnect() { - Mutex::Autolock autoLock(mLock); - disconnect_l(); -} - -void ChromiumHTTPDataSource::disconnect_l() { - if (mState == DISCONNECTED) { - return; - } - - mState = DISCONNECTING; - mIOResult = -EINTR; - - mDelegate->initiateDisconnect(); - - while (mState == DISCONNECTING) { - mCondition.wait(mLock); - } - - CHECK_EQ((int)mState, (int)DISCONNECTED); -} - -status_t ChromiumHTTPDataSource::initCheck() const { - Mutex::Autolock autoLock(mLock); - - return mState == CONNECTED ? OK : NO_INIT; -} - -ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) { - Mutex::Autolock autoLock(mLock); - - if (mState != CONNECTED) { - return INVALID_OPERATION; - } - -#if 0 - char value[PROPERTY_VALUE_MAX]; - if (property_get("media.stagefright.disable-net", value, 0) - && (!strcasecmp(value, "true") || !strcmp(value, "1"))) { - LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Simulating that the network is down."); - disconnect_l(); - return ERROR_IO; - } -#endif - - if (offset != mCurrentOffset) { - AString tmp = mURI; - KeyedVector<String8, String8> tmpHeaders = mHeaders; - - disconnect_l(); - - status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset); - - if (err != OK) { - return err; - } - } - - mState = READING; - - int64_t startTimeUs = ALooper::GetNowUs(); - - mDelegate->initiateRead(data, size); - - while (mState == READING) { - mCondition.wait(mLock); - } - - if (mIOResult < OK) { - return mIOResult; - } - - if (mState == CONNECTED) { - int64_t delayUs = ALooper::GetNowUs() - startTimeUs; - - // The read operation was successful, mIOResult contains - // the number of bytes read. - addBandwidthMeasurement(mIOResult, delayUs); - - mCurrentOffset += mIOResult; - return mIOResult; - } - - return ERROR_IO; -} - -void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) { - Mutex::Autolock autoLock(mLock); - - mIOResult = size; - - if (mState == READING) { - mState = CONNECTED; - mCondition.broadcast(); - } -} - -status_t ChromiumHTTPDataSource::getSize(off64_t *size) { - Mutex::Autolock autoLock(mLock); - - if (mContentSize < 0) { - return ERROR_UNSUPPORTED; - } - - *size = mContentSize; - - return OK; -} - -uint32_t ChromiumHTTPDataSource::flags() { - return kWantsPrefetching | kIsHTTPBasedSource; -} - -// static -void ChromiumHTTPDataSource::InitiateRead( - ChromiumHTTPDataSource *me, void *data, size_t size) { - me->initiateRead(data, size); -} - -void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) { - mDelegate->initiateRead(data, size); -} - -void ChromiumHTTPDataSource::onDisconnectComplete() { - Mutex::Autolock autoLock(mLock); - CHECK_EQ((int)mState, (int)DISCONNECTING); - - mState = DISCONNECTED; - // mURI.clear(); - mIOResult = -ENOTCONN; - - mCondition.broadcast(); -} - -sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization(const char* mime) { - Mutex::Autolock autoLock(mLock); - - if (mDrmManagerClient == NULL) { - mDrmManagerClient = new DrmManagerClient(); - } - - if (mDrmManagerClient == NULL) { - return NULL; - } - - if (mDecryptHandle == NULL) { - /* Note if redirect occurs, mUri is the redirect uri instead of the - * original one - */ - mDecryptHandle = mDrmManagerClient->openDecryptSession( - String8(mURI.c_str()), mime); - } - - if (mDecryptHandle == NULL) { - delete mDrmManagerClient; - mDrmManagerClient = NULL; - } - - return mDecryptHandle; -} - -void ChromiumHTTPDataSource::getDrmInfo( - sp<DecryptHandle> &handle, DrmManagerClient **client) { - Mutex::Autolock autoLock(mLock); - - handle = mDecryptHandle; - *client = mDrmManagerClient; -} - -String8 ChromiumHTTPDataSource::getUri() { - Mutex::Autolock autoLock(mLock); - - return String8(mURI.c_str()); -} - -String8 ChromiumHTTPDataSource::getMIMEType() const { - Mutex::Autolock autoLock(mLock); - - return mContentType; -} - -void ChromiumHTTPDataSource::clearDRMState_l() { - if (mDecryptHandle != NULL) { - // To release mDecryptHandle - CHECK(mDrmManagerClient); - mDrmManagerClient->closeDecryptSession(mDecryptHandle); - mDecryptHandle = NULL; - } -} - -status_t ChromiumHTTPDataSource::reconnectAtOffset(off64_t offset) { - Mutex::Autolock autoLock(mLock); - - if (mURI.empty()) { - return INVALID_OPERATION; - } - - LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnecting..."); - status_t err = connect_l(mURI.c_str(), &mHeaders, offset); - if (err != OK) { - LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnect failed w/ err 0x%08x", err); - } - - return err; -} - -// static -status_t ChromiumHTTPDataSource::UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - return SfDelegate::UpdateProxyConfig(host, port, exclusionList); -} - -} // namespace android - diff --git a/media/libstagefright/chromium_http/DataUriSource.cpp b/media/libstagefright/chromium_http/DataUriSource.cpp deleted file mode 100644 index ecf3fa1..0000000 --- a/media/libstagefright/chromium_http/DataUriSource.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#include <include/DataUriSource.h> - -#include <net/base/data_url.h> -#include <googleurl/src/gurl.h> - - -namespace android { - -DataUriSource::DataUriSource(const char *uri) : - mDataUri(uri), - mInited(NO_INIT) { - - // Copy1: const char *uri -> String8 mDataUri. - std::string mimeTypeStr, unusedCharsetStr, dataStr; - // Copy2: String8 mDataUri -> std::string - const bool ret = net::DataURL::Parse( - GURL(std::string(mDataUri.string())), - &mimeTypeStr, &unusedCharsetStr, &dataStr); - // Copy3: std::string dataStr -> AString mData - mData.setTo(dataStr.data(), dataStr.length()); - mInited = ret ? OK : UNKNOWN_ERROR; - - // The chromium data url implementation defaults to using "text/plain" - // if no mime type is specified. We prefer to leave this unspecified - // instead, since the mime type is sniffed in most cases. - if (mimeTypeStr != "text/plain") { - mMimeType = mimeTypeStr.c_str(); - } -} - -ssize_t DataUriSource::readAt(off64_t offset, void *out, size_t size) { - if (mInited != OK) { - return mInited; - } - - const off64_t length = mData.size(); - if (offset >= length) { - return UNKNOWN_ERROR; - } - - const char *dataBuf = mData.c_str(); - const size_t bytesToCopy = - offset + size >= length ? (length - offset) : size; - - if (bytesToCopy > 0) { - memcpy(out, dataBuf + offset, bytesToCopy); - } - - return bytesToCopy; -} - -} // namespace android diff --git a/media/libstagefright/chromium_http/chromium_http_stub.cpp b/media/libstagefright/chromium_http/chromium_http_stub.cpp deleted file mode 100644 index 289f6de..0000000 --- a/media/libstagefright/chromium_http/chromium_http_stub.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -#include <dlfcn.h> - -#include <include/chromium_http_stub.h> -#include <include/ChromiumHTTPDataSource.h> -#include <include/DataUriSource.h> - -namespace android { - -HTTPBase *createChromiumHTTPDataSource(uint32_t flags) { - return new ChromiumHTTPDataSource(flags); -} - -status_t UpdateChromiumHTTPDataSourceProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - return ChromiumHTTPDataSource::UpdateProxyConfig(host, port, exclusionList); -} - -DataSource *createDataUriSource(const char *uri) { - return new DataUriSource(uri); -} - -} diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp deleted file mode 100644 index 0a8e3e3..0000000 --- a/media/libstagefright/chromium_http/support.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (C) 2011 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 "ChromiumHTTPDataSourceSupport" -#include <utils/Log.h> - -#include <media/stagefright/foundation/AString.h> - -#include "support.h" - -#include "android/net/android_network_library_impl.h" -#include "base/logging.h" -#include "base/threading/thread.h" -#include "net/base/cert_verifier.h" -#include "net/base/cookie_monster.h" -#include "net/base/host_resolver.h" -#include "net/base/ssl_config_service.h" -#include "net/http/http_auth_handler_factory.h" -#include "net/http/http_cache.h" -#include "net/proxy/proxy_config_service_android.h" - -#include "include/ChromiumHTTPDataSource.h" - -#include <cutils/log.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/Utils.h> -#include <string> - -namespace android { - -static Mutex gNetworkThreadLock; -static base::Thread *gNetworkThread = NULL; -static scoped_refptr<SfRequestContext> gReqContext; -static scoped_ptr<net::NetworkChangeNotifier> gNetworkChangeNotifier; - -bool logMessageHandler( - int severity, - const char* file, - int line, - size_t message_start, - const std::string& str) { - int androidSeverity = ANDROID_LOG_VERBOSE; - switch(severity) { - case logging::LOG_FATAL: - androidSeverity = ANDROID_LOG_FATAL; - break; - case logging::LOG_ERROR_REPORT: - case logging::LOG_ERROR: - androidSeverity = ANDROID_LOG_ERROR; - break; - case logging::LOG_WARNING: - androidSeverity = ANDROID_LOG_WARN; - break; - default: - androidSeverity = ANDROID_LOG_VERBOSE; - break; - } - android_printLog(androidSeverity, "chromium-libstagefright", - "%s:%d: %s", file, line, str.c_str()); - return false; -} - -struct AutoPrioritySaver { - AutoPrioritySaver() - : mTID(androidGetTid()), - mPrevPriority(androidGetThreadPriority(mTID)) { - androidSetThreadPriority(mTID, ANDROID_PRIORITY_NORMAL); - } - - ~AutoPrioritySaver() { - androidSetThreadPriority(mTID, mPrevPriority); - } - -private: - pid_t mTID; - int mPrevPriority; - - DISALLOW_EVIL_CONSTRUCTORS(AutoPrioritySaver); -}; - -static void InitializeNetworkThreadIfNecessary() { - Mutex::Autolock autoLock(gNetworkThreadLock); - - if (gNetworkThread == NULL) { - // Make sure any threads spawned by the chromium framework are - // running at normal priority instead of inheriting this thread's. - AutoPrioritySaver saver; - - gNetworkThread = new base::Thread("network"); - base::Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - CHECK(gNetworkThread->StartWithOptions(options)); - - gReqContext = new SfRequestContext; - - gNetworkChangeNotifier.reset(net::NetworkChangeNotifier::Create()); - - net::AndroidNetworkLibrary::RegisterSharedInstance( - new SfNetworkLibrary); - logging::SetLogMessageHandler(logMessageHandler); - } -} - -static void MY_LOGI(const char *s) { - LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "%s", s); -} - -static void MY_LOGV(const char *s) { -#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0 - LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "%s", s); -#endif -} - -SfNetLog::SfNetLog() - : mNextID(1) { -} - -void SfNetLog::AddEntry( - EventType type, - const base::TimeTicks &time, - const Source &source, - EventPhase phase, - EventParameters *params) { -#if 0 - MY_LOGI(StringPrintf( - "AddEntry time=%s type=%s source=%s phase=%s\n", - TickCountToString(time).c_str(), - EventTypeToString(type), - SourceTypeToString(source.type), - EventPhaseToString(phase)).c_str()); -#endif -} - -uint32 SfNetLog::NextID() { - return mNextID++; -} - -net::NetLog::LogLevel SfNetLog::GetLogLevel() const { - return LOG_BASIC; -} - -//////////////////////////////////////////////////////////////////////////////// - -SfRequestContext::SfRequestContext() { - mUserAgent = MakeUserAgent().c_str(); - - set_net_log(new SfNetLog()); - - set_host_resolver( - net::CreateSystemHostResolver( - net::HostResolver::kDefaultParallelism, - NULL /* resolver_proc */, - net_log())); - - set_ssl_config_service( - net::SSLConfigService::CreateSystemSSLConfigService()); - - mProxyConfigService = new net::ProxyConfigServiceAndroid; - - set_proxy_service(net::ProxyService::CreateWithoutProxyResolver( - mProxyConfigService, net_log())); - - set_http_transaction_factory(new net::HttpCache( - host_resolver(), - new net::CertVerifier(), - dnsrr_resolver(), - dns_cert_checker(), - proxy_service(), - ssl_config_service(), - net::HttpAuthHandlerFactory::CreateDefault(host_resolver()), - network_delegate(), - net_log(), - NULL)); // backend_factory - - set_cookie_store(new net::CookieMonster(NULL, NULL)); -} - -const std::string &SfRequestContext::GetUserAgent(const GURL &url) const { - return mUserAgent; -} - -status_t SfRequestContext::updateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - Mutex::Autolock autoLock(mProxyConfigLock); - - if (host == NULL || *host == '\0') { - MY_LOGV("updateProxyConfig NULL"); - - std::string proxy; - std::string exList; - mProxyConfigService->UpdateProxySettings(proxy, exList); - } else { -#if !defined(LOG_NDEBUG) || LOG_NDEBUG == 0 - LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, - "updateProxyConfig %s:%d, exclude '%s'", - host, port, exclusionList); -#endif - - std::string proxy = StringPrintf("%s:%d", host, port).c_str(); - std::string exList = exclusionList; - mProxyConfigService->UpdateProxySettings(proxy, exList); - } - - return OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -SfNetworkLibrary::SfNetworkLibrary() {} - -SfNetworkLibrary::VerifyResult SfNetworkLibrary::VerifyX509CertChain( - const std::vector<std::string>& cert_chain, - const std::string& hostname, - const std::string& auth_type) { - return VERIFY_OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -SfDelegate::SfDelegate() - : mOwner(NULL), - mURLRequest(NULL), - mReadBuffer(new net::IOBufferWithSize(8192)), - mNumBytesRead(0), - mNumBytesTotal(0), - mDataDestination(NULL), - mAtEOS(false) { - InitializeNetworkThreadIfNecessary(); -} - -SfDelegate::~SfDelegate() { - CHECK(mURLRequest == NULL); -} - -// static -status_t SfDelegate::UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - InitializeNetworkThreadIfNecessary(); - - return gReqContext->updateProxyConfig(host, port, exclusionList); -} - -void SfDelegate::setOwner(ChromiumHTTPDataSource *owner) { - mOwner = owner; -} - -void SfDelegate::setUID(uid_t uid) { - gReqContext->setUID(uid); -} - -bool SfDelegate::getUID(uid_t *uid) const { - return gReqContext->getUID(uid); -} - -void SfDelegate::OnReceivedRedirect( - net::URLRequest *request, const GURL &new_url, bool *defer_redirect) { - MY_LOGV("OnReceivedRedirect"); -} - -void SfDelegate::OnAuthRequired( - net::URLRequest *request, net::AuthChallengeInfo *auth_info) { - MY_LOGV("OnAuthRequired"); - - inherited::OnAuthRequired(request, auth_info); -} - -void SfDelegate::OnCertificateRequested( - net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info) { - MY_LOGV("OnCertificateRequested"); - - inherited::OnCertificateRequested(request, cert_request_info); -} - -void SfDelegate::OnSSLCertificateError( - net::URLRequest *request, int cert_error, net::X509Certificate *cert) { - fprintf(stderr, "OnSSLCertificateError cert_error=%d\n", cert_error); - - inherited::OnSSLCertificateError(request, cert_error, cert); -} - -void SfDelegate::OnGetCookies(net::URLRequest *request, bool blocked_by_policy) { - MY_LOGV("OnGetCookies"); -} - -void SfDelegate::OnSetCookie( - net::URLRequest *request, - const std::string &cookie_line, - const net::CookieOptions &options, - bool blocked_by_policy) { - MY_LOGV("OnSetCookie"); -} - -void SfDelegate::OnResponseStarted(net::URLRequest *request) { - if (request->status().status() != net::URLRequestStatus::SUCCESS) { - MY_LOGI(StringPrintf( - "Request failed with status %d and os_error %d", - request->status().status(), - request->status().os_error()).c_str()); - - delete mURLRequest; - mURLRequest = NULL; - - mOwner->onConnectionFailed(ERROR_IO); - return; - } else if (mRangeRequested && request->GetResponseCode() != 206) { - MY_LOGI(StringPrintf( - "We requested a content range, but server didn't " - "support that. (responded with %d)", - request->GetResponseCode()).c_str()); - - delete mURLRequest; - mURLRequest = NULL; - - mOwner->onConnectionFailed(-EPIPE); - return; - } else if ((request->GetResponseCode() / 100) != 2) { - MY_LOGI(StringPrintf( - "Server responded with http status %d", - request->GetResponseCode()).c_str()); - - delete mURLRequest; - mURLRequest = NULL; - - mOwner->onConnectionFailed(ERROR_IO); - return; - } - - MY_LOGV("OnResponseStarted"); - - std::string headers; - request->GetAllResponseHeaders(&headers); - - MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str()); - - std::string contentType; - request->GetResponseHeaderByName("Content-Type", &contentType); - - mOwner->onConnectionEstablished( - request->GetExpectedContentSize(), contentType.c_str()); -} - -void SfDelegate::OnReadCompleted(net::URLRequest *request, int bytes_read) { - if (bytes_read == -1) { - MY_LOGI(StringPrintf( - "OnReadCompleted, read failed, status %d", - request->status().status()).c_str()); - - mOwner->onReadCompleted(ERROR_IO); - return; - } - - MY_LOGV(StringPrintf("OnReadCompleted, read %d bytes", bytes_read).c_str()); - - if (bytes_read < 0) { - MY_LOGI(StringPrintf( - "Read failed w/ status %d\n", - request->status().status()).c_str()); - - mOwner->onReadCompleted(ERROR_IO); - return; - } else if (bytes_read == 0) { - mAtEOS = true; - mOwner->onReadCompleted(mNumBytesRead); - return; - } - - CHECK_GT(bytes_read, 0); - CHECK_LE(mNumBytesRead + bytes_read, mNumBytesTotal); - - memcpy((uint8_t *)mDataDestination + mNumBytesRead, - mReadBuffer->data(), - bytes_read); - - mNumBytesRead += bytes_read; - - readMore(request); -} - -void SfDelegate::readMore(net::URLRequest *request) { - while (mNumBytesRead < mNumBytesTotal) { - size_t copy = mNumBytesTotal - mNumBytesRead; - if (copy > mReadBuffer->size()) { - copy = mReadBuffer->size(); - } - - int n; - if (request->Read(mReadBuffer, copy, &n)) { - MY_LOGV(StringPrintf("Read %d bytes directly.", n).c_str()); - - CHECK_LE((size_t)n, copy); - - memcpy((uint8_t *)mDataDestination + mNumBytesRead, - mReadBuffer->data(), - n); - - mNumBytesRead += n; - - if (n == 0) { - mAtEOS = true; - break; - } - } else { - MY_LOGV("readMore pending read"); - - if (request->status().status() != net::URLRequestStatus::IO_PENDING) { - MY_LOGI(StringPrintf( - "Direct read failed w/ status %d\n", - request->status().status()).c_str()); - - mOwner->onReadCompleted(ERROR_IO); - return; - } - - return; - } - } - - mOwner->onReadCompleted(mNumBytesRead); -} - -void SfDelegate::initiateConnection( - const char *uri, - const KeyedVector<String8, String8> *headers, - off64_t offset) { - GURL url(uri); - - MessageLoop *loop = gNetworkThread->message_loop(); - loop->PostTask( - FROM_HERE, - NewRunnableFunction( - &SfDelegate::OnInitiateConnectionWrapper, - this, - url, - headers, - offset)); - -} - -// static -void SfDelegate::OnInitiateConnectionWrapper( - SfDelegate *me, GURL url, - const KeyedVector<String8, String8> *headers, - off64_t offset) { - me->onInitiateConnection(url, headers, offset); -} - -void SfDelegate::onInitiateConnection( - const GURL &url, - const KeyedVector<String8, String8> *extra, - off64_t offset) { - CHECK(mURLRequest == NULL); - - mURLRequest = new net::URLRequest(url, this); - mAtEOS = false; - - mRangeRequested = false; - - if (offset != 0 || extra != NULL) { - net::HttpRequestHeaders headers = - mURLRequest->extra_request_headers(); - - if (offset != 0) { - headers.AddHeaderFromString( - StringPrintf("Range: bytes=%lld-", offset).c_str()); - - mRangeRequested = true; - } - - if (extra != NULL) { - for (size_t i = 0; i < extra->size(); ++i) { - AString s; - s.append(extra->keyAt(i).string()); - s.append(": "); - s.append(extra->valueAt(i).string()); - - headers.AddHeaderFromString(s.c_str()); - } - } - - mURLRequest->SetExtraRequestHeaders(headers); - } - - mURLRequest->set_context(gReqContext); - - mURLRequest->Start(); -} - -void SfDelegate::initiateDisconnect() { - MessageLoop *loop = gNetworkThread->message_loop(); - loop->PostTask( - FROM_HERE, - NewRunnableFunction( - &SfDelegate::OnInitiateDisconnectWrapper, this)); -} - -// static -void SfDelegate::OnInitiateDisconnectWrapper(SfDelegate *me) { - me->onInitiateDisconnect(); -} - -void SfDelegate::onInitiateDisconnect() { - if (mURLRequest == NULL) { - return; - } - - mURLRequest->Cancel(); - - delete mURLRequest; - mURLRequest = NULL; - - mOwner->onDisconnectComplete(); -} - -void SfDelegate::initiateRead(void *data, size_t size) { - MessageLoop *loop = gNetworkThread->message_loop(); - loop->PostTask( - FROM_HERE, - NewRunnableFunction( - &SfDelegate::OnInitiateReadWrapper, this, data, size)); -} - -// static -void SfDelegate::OnInitiateReadWrapper( - SfDelegate *me, void *data, size_t size) { - me->onInitiateRead(data, size); -} - -void SfDelegate::onInitiateRead(void *data, size_t size) { - CHECK(mURLRequest != NULL); - - mNumBytesRead = 0; - mNumBytesTotal = size; - mDataDestination = data; - - if (mAtEOS) { - mOwner->onReadCompleted(0); - return; - } - - readMore(mURLRequest); -} - -} // namespace android - diff --git a/media/libstagefright/chromium_http/support.h b/media/libstagefright/chromium_http/support.h deleted file mode 100644 index 975a1d3..0000000 --- a/media/libstagefright/chromium_http/support.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2011 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 SUPPORT_H_ - -#define SUPPORT_H_ - -#include <assert.h> - -#include "net/base/net_log.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_context.h" -#include "net/base/android_network_library.h" -#include "net/base/io_buffer.h" - -#include <utils/KeyedVector.h> -#include <utils/Mutex.h> -#include <utils/String8.h> - -namespace net { - struct ProxyConfigServiceAndroid; -}; - -namespace android { - -struct SfNetLog : public net::NetLog { - SfNetLog(); - - virtual void AddEntry( - EventType type, - const base::TimeTicks &time, - const Source &source, - EventPhase phase, - EventParameters *params); - - virtual uint32 NextID(); - virtual LogLevel GetLogLevel() const; - -private: - uint32 mNextID; - - DISALLOW_EVIL_CONSTRUCTORS(SfNetLog); -}; - -struct SfRequestContext : public net::URLRequestContext { - SfRequestContext(); - - virtual const std::string &GetUserAgent(const GURL &url) const; - - status_t updateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - -private: - Mutex mProxyConfigLock; - - std::string mUserAgent; - net::ProxyConfigServiceAndroid *mProxyConfigService; - - DISALLOW_EVIL_CONSTRUCTORS(SfRequestContext); -}; - -// This is required for https support, we don't really verify certificates, -// we accept anything... -struct SfNetworkLibrary : public net::AndroidNetworkLibrary { - SfNetworkLibrary(); - - virtual VerifyResult VerifyX509CertChain( - const std::vector<std::string>& cert_chain, - const std::string& hostname, - const std::string& auth_type); - -private: - DISALLOW_EVIL_CONSTRUCTORS(SfNetworkLibrary); -}; - -struct ChromiumHTTPDataSource; - -struct SfDelegate : public net::URLRequest::Delegate { - SfDelegate(); - virtual ~SfDelegate(); - - void initiateConnection( - const char *uri, - const KeyedVector<String8, String8> *headers, - off64_t offset); - - void initiateDisconnect(); - void initiateRead(void *data, size_t size); - - void setOwner(ChromiumHTTPDataSource *mOwner); - - // Gets the UID of the calling process - bool getUID(uid_t *uid) const; - - void setUID(uid_t uid); - - virtual void OnReceivedRedirect( - net::URLRequest *request, const GURL &new_url, bool *defer_redirect); - - virtual void OnAuthRequired( - net::URLRequest *request, net::AuthChallengeInfo *auth_info); - - virtual void OnCertificateRequested( - net::URLRequest *request, net::SSLCertRequestInfo *cert_request_info); - - virtual void OnSSLCertificateError( - net::URLRequest *request, int cert_error, net::X509Certificate *cert); - - virtual void OnGetCookies(net::URLRequest *request, bool blocked_by_policy); - - virtual void OnSetCookie( - net::URLRequest *request, - const std::string &cookie_line, - const net::CookieOptions &options, - bool blocked_by_policy); - - virtual void OnResponseStarted(net::URLRequest *request); - - virtual void OnReadCompleted(net::URLRequest *request, int bytes_read); - - static status_t UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - -private: - typedef Delegate inherited; - - ChromiumHTTPDataSource *mOwner; - - net::URLRequest *mURLRequest; - scoped_refptr<net::IOBufferWithSize> mReadBuffer; - - size_t mNumBytesRead; - size_t mNumBytesTotal; - void *mDataDestination; - - bool mRangeRequested; - bool mAtEOS; - - void readMore(net::URLRequest *request); - - static void OnInitiateConnectionWrapper( - SfDelegate *me, - GURL url, - const KeyedVector<String8, String8> *headers, - off64_t offset); - - static void OnInitiateDisconnectWrapper(SfDelegate *me); - - static void OnInitiateReadWrapper( - SfDelegate *me, void *data, size_t size); - - void onInitiateConnection( - const GURL &url, - const KeyedVector<String8, String8> *headers, - off64_t offset); - - void onInitiateDisconnect(); - void onInitiateRead(void *data, size_t size); - - DISALLOW_EVIL_CONSTRUCTORS(SfDelegate); -}; - -} // namespace android - -#endif // SUPPORT_H_ diff --git a/media/libstagefright/chromium_http_stub.cpp b/media/libstagefright/chromium_http_stub.cpp deleted file mode 100644 index ed8a878..0000000 --- a/media/libstagefright/chromium_http_stub.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -#include <dlfcn.h> - -#include <media/stagefright/DataSource.h> - -#include "include/chromium_http_stub.h" -#include "include/HTTPBase.h" - -namespace android { - -static bool gFirst = true; -static void *gHandle; -static Mutex gLibMutex; - -HTTPBase *(*gLib_createChromiumHTTPDataSource)(uint32_t flags); -DataSource *(*gLib_createDataUriSource)(const char *uri); - -status_t (*gLib_UpdateChromiumHTTPDataSourceProxyConfig)( - const char *host, int32_t port, const char *exclusionList); - -static bool load_libstagefright_chromium_http() { - Mutex::Autolock autoLock(gLibMutex); - void *sym; - - if (!gFirst) { - return (gHandle != NULL); - } - - gFirst = false; - - gHandle = dlopen("libstagefright_chromium_http.so", RTLD_NOW); - if (gHandle == NULL) { - return false; - } - - sym = dlsym(gHandle, "createChromiumHTTPDataSource"); - if (sym == NULL) { - gHandle = NULL; - return false; - } - gLib_createChromiumHTTPDataSource = (HTTPBase *(*)(uint32_t))sym; - - sym = dlsym(gHandle, "createDataUriSource"); - if (sym == NULL) { - gHandle = NULL; - return false; - } - gLib_createDataUriSource = (DataSource *(*)(const char *))sym; - - sym = dlsym(gHandle, "UpdateChromiumHTTPDataSourceProxyConfig"); - if (sym == NULL) { - gHandle = NULL; - return false; - } - gLib_UpdateChromiumHTTPDataSourceProxyConfig = - (status_t (*)(const char *, int32_t, const char *))sym; - - return true; -} - -HTTPBase *createChromiumHTTPDataSource(uint32_t flags) { - if (!load_libstagefright_chromium_http()) { - return NULL; - } - - return gLib_createChromiumHTTPDataSource(flags); -} - -status_t UpdateChromiumHTTPDataSourceProxyConfig( - const char *host, int32_t port, const char *exclusionList) { - if (!load_libstagefright_chromium_http()) { - return INVALID_OPERATION; - } - - return gLib_UpdateChromiumHTTPDataSourceProxyConfig( - host, port, exclusionList); -} - -DataSource *createDataUriSource(const char *uri) { - if (!load_libstagefright_chromium_http()) { - return NULL; - } - - return gLib_createDataUriSource(uri); -} - -} diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index 877e3cb..61df65e 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -335,6 +335,9 @@ void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) { // depend on fragments from the last one decoded. pvmp3_InitDecoder(mConfig, mDecoderBuf); mIsFirst = true; + mSignalledError = false; + mSawInputEos = false; + mSignalledOutputEos = false; } } diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk new file mode 100644 index 0000000..a6b481f --- /dev/null +++ b/media/libstagefright/http/Android.mk @@ -0,0 +1,26 @@ +LOCAL_PATH:= $(call my-dir) + +ifneq ($(TARGET_BUILD_PDK), true) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + HTTPHelper.cpp \ + +LOCAL_C_INCLUDES:= \ + $(TOP)/frameworks/av/media/libstagefright \ + $(TOP)/frameworks/native/include/media/openmax \ + $(TOP)/frameworks/base/core/jni \ + +LOCAL_SHARED_LIBRARIES := \ + libstagefright liblog libutils libbinder libstagefright_foundation \ + libandroid_runtime \ + libmedia + +LOCAL_MODULE:= libstagefright_http_support + +LOCAL_CFLAGS += -Wno-multichar + +include $(BUILD_SHARED_LIBRARY) + +endif diff --git a/media/libstagefright/http/HTTPHelper.cpp b/media/libstagefright/http/HTTPHelper.cpp new file mode 100644 index 0000000..77845e2 --- /dev/null +++ b/media/libstagefright/http/HTTPHelper.cpp @@ -0,0 +1,70 @@ +/* + * 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 "HTTPHelper" +#include <utils/Log.h> + +#include "HTTPHelper.h" + +#include "android_runtime/AndroidRuntime.h" +#include "android_util_Binder.h" +#include <media/IMediaHTTPService.h> +#include <media/stagefright/foundation/ADebug.h> +#include <nativehelper/ScopedLocalRef.h> +#include "jni.h" + +namespace android { + +sp<IMediaHTTPService> CreateHTTPServiceInCurrentJavaContext() { + if (AndroidRuntime::getJavaVM() == NULL) { + ALOGE("CreateHTTPServiceInCurrentJavaContext called outside " + "JAVA environment."); + return NULL; + } + + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + ScopedLocalRef<jclass> clazz( + env, env->FindClass("android/media/MediaHTTPService")); + CHECK(clazz.get() != NULL); + + jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "()V"); + CHECK(constructID != NULL); + + ScopedLocalRef<jobject> httpServiceObj( + env, env->NewObject(clazz.get(), constructID)); + + sp<IMediaHTTPService> httpService; + if (httpServiceObj.get() != NULL) { + jmethodID asBinderID = + env->GetMethodID(clazz.get(), "asBinder", "()Landroid/os/IBinder;"); + CHECK(asBinderID != NULL); + + ScopedLocalRef<jobject> httpServiceBinderObj( + env, env->CallObjectMethod(httpServiceObj.get(), asBinderID)); + CHECK(httpServiceBinderObj.get() != NULL); + + sp<IBinder> binder = + ibinderForJavaObject(env, httpServiceBinderObj.get()); + + httpService = interface_cast<IMediaHTTPService>(binder); + } + + return httpService; +} + +} // namespace android diff --git a/media/libstagefright/include/chromium_http_stub.h b/media/libstagefright/http/HTTPHelper.h index e0651a4..8aef115 100644 --- a/media/libstagefright/include/chromium_http_stub.h +++ b/media/libstagefright/http/HTTPHelper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * 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. @@ -14,21 +14,18 @@ * limitations under the License. */ -#ifndef CHROMIUM_HTTP_STUB_H_ -#define CHROMIUM_HTTP_STUB_H_ +#ifndef HTTP_HELPER_H_ -#include <include/HTTPBase.h> -#include <media/stagefright/DataSource.h> +#define HTTP_HELPER_H_ + +#include <utils/RefBase.h> namespace android { -extern "C" { -HTTPBase *createChromiumHTTPDataSource(uint32_t flags); -status_t UpdateChromiumHTTPDataSourceProxyConfig( - const char *host, int32_t port, const char *exclusionList); +struct IMediaHTTPService; + +sp<IMediaHTTPService> CreateHTTPServiceInCurrentJavaContext(); -DataSource *createDataUriSource(const char *uri); -} -} +} // namespace android -#endif +#endif // HTTP_HELPER_H_ diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp new file mode 100644 index 0000000..157d967 --- /dev/null +++ b/media/libstagefright/http/MediaHTTP.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2013 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 "MediaHTTP" +#include <utils/Log.h> + +#include <media/stagefright/MediaHTTP.h> + +#include <binder/IServiceManager.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/ALooper.h> +#include <media/stagefright/Utils.h> + +#include <media/IMediaHTTPConnection.h> + +namespace android { + +MediaHTTP::MediaHTTP(const sp<IMediaHTTPConnection> &conn) + : mInitCheck(NO_INIT), + mHTTPConnection(conn), + mCachedSizeValid(false), + mCachedSize(0ll), + mDrmManagerClient(NULL) { + mInitCheck = OK; +} + +MediaHTTP::~MediaHTTP() { + clearDRMState_l(); +} + +status_t MediaHTTP::connect( + const char *uri, + const KeyedVector<String8, String8> *headers, + off64_t /* offset */) { + if (mInitCheck != OK) { + return mInitCheck; + } + + KeyedVector<String8, String8> extHeaders; + if (headers != NULL) { + extHeaders = *headers; + } + extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str())); + + bool success = mHTTPConnection->connect(uri, &extHeaders); + + mLastHeaders = extHeaders; + mLastURI = uri; + + mCachedSizeValid = false; + + return success ? OK : UNKNOWN_ERROR; +} + +void MediaHTTP::disconnect() { + if (mInitCheck != OK) { + return; + } + + mHTTPConnection->disconnect(); +} + +status_t MediaHTTP::initCheck() const { + return mInitCheck; +} + +ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) { + if (mInitCheck != OK) { + return mInitCheck; + } + + int64_t startTimeUs = ALooper::GetNowUs(); + + size_t numBytesRead = 0; + while (numBytesRead < size) { + size_t copy = size - numBytesRead; + + if (copy > 64 * 1024) { + // limit the buffer sizes transferred across binder boundaries + // to avoid spurious transaction failures. + copy = 64 * 1024; + } + + ssize_t n = mHTTPConnection->readAt( + offset + numBytesRead, (uint8_t *)data + numBytesRead, copy); + + if (n < 0) { + return n; + } else if (n == 0) { + break; + } + + numBytesRead += n; + } + + int64_t delayUs = ALooper::GetNowUs() - startTimeUs; + + addBandwidthMeasurement(numBytesRead, delayUs); + + return numBytesRead; +} + +status_t MediaHTTP::getSize(off64_t *size) { + if (mInitCheck != OK) { + return mInitCheck; + } + + // Caching the returned size so that it stays valid even after a + // disconnect. NuCachedSource2 relies on this. + + if (!mCachedSizeValid) { + mCachedSize = mHTTPConnection->getSize(); + mCachedSizeValid = true; + } + + *size = mCachedSize; + + return *size < 0 ? *size : OK; +} + +uint32_t MediaHTTP::flags() { + return kWantsPrefetching | kIsHTTPBasedSource; +} + +status_t MediaHTTP::reconnectAtOffset(off64_t offset) { + return connect(mLastURI.c_str(), &mLastHeaders, offset); +} + +// DRM... + +sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) { + if (mDrmManagerClient == NULL) { + mDrmManagerClient = new DrmManagerClient(); + } + + if (mDrmManagerClient == NULL) { + return NULL; + } + + if (mDecryptHandle == NULL) { + mDecryptHandle = mDrmManagerClient->openDecryptSession( + String8(mLastURI.c_str()), mime); + } + + if (mDecryptHandle == NULL) { + delete mDrmManagerClient; + mDrmManagerClient = NULL; + } + + return mDecryptHandle; +} + +void MediaHTTP::getDrmInfo( + sp<DecryptHandle> &handle, DrmManagerClient **client) { + handle = mDecryptHandle; + *client = mDrmManagerClient; +} + +String8 MediaHTTP::getUri() { + return String8(mLastURI.c_str()); +} + +String8 MediaHTTP::getMIMEType() const { + if (mInitCheck != OK) { + return String8("application/octet-stream"); + } + + String8 mimeType; + status_t err = mHTTPConnection->getMIMEType(&mimeType); + + if (err != OK) { + return String8("application/octet-stream"); + } + + return mimeType; +} + +void MediaHTTP::clearDRMState_l() { + if (mDecryptHandle != NULL) { + // To release mDecryptHandle + CHECK(mDrmManagerClient); + mDrmManagerClient->closeDecryptSession(mDecryptHandle); + mDecryptHandle = NULL; + } +} + +} // namespace android diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 233db44..149a817 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -27,6 +27,8 @@ #include "mpeg2ts/AnotherPacketSource.h" #include <cutils/properties.h> +#include <media/IMediaHTTPConnection.h> +#include <media/IMediaHTTPService.h> #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> @@ -34,6 +36,7 @@ #include <media/stagefright/DataSource.h> #include <media/stagefright/FileSource.h> #include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaHTTP.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/Utils.h> @@ -44,17 +47,13 @@ namespace android { LiveSession::LiveSession( - const sp<AMessage> ¬ify, uint32_t flags, bool uidValid, uid_t uid) + const sp<AMessage> ¬ify, uint32_t flags, + const sp<IMediaHTTPService> &httpService) : mNotify(notify), mFlags(flags), - mUIDValid(uidValid), - mUID(uid), + mHTTPService(httpService), mInPreparationPhase(true), - mHTTPDataSource( - HTTPBase::Create( - (mFlags & kFlagIncognito) - ? HTTPBase::kFlagIncognito - : 0)), + mHTTPDataSource(new MediaHTTP(mHTTPService->makeHTTPConnection())), mPrevBandwidthIndex(-1), mStreamMask(0), mCheckBandwidthGeneration(0), @@ -62,10 +61,6 @@ LiveSession::LiveSession( mRealTimeBaseUs(0ll), mReconfigurationInProgress(false), mDisconnectReplyID(0) { - if (mUIDValid) { - mHTTPDataSource->setUID(mUID); - } - mPacketSources.add( STREAMTYPE_AUDIO, new AnotherPacketSource(NULL /* meta */)); diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 99b480a8..ee10e70 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -28,6 +28,7 @@ struct ABuffer; struct AnotherPacketSource; struct DataSource; struct HTTPBase; +struct IMediaHTTPService; struct LiveDataSource; struct M3UParser; struct PlaylistFetcher; @@ -40,7 +41,8 @@ struct LiveSession : public AHandler { }; LiveSession( const sp<AMessage> ¬ify, - uint32_t flags = 0, bool uidValid = false, uid_t uid = 0); + uint32_t flags, + const sp<IMediaHTTPService> &httpService); enum StreamType { STREAMTYPE_AUDIO = 1, @@ -107,8 +109,7 @@ private: sp<AMessage> mNotify; uint32_t mFlags; - bool mUIDValid; - uid_t mUID; + sp<IMediaHTTPService> mHTTPService; bool mInPreparationPhase; diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 271df8e..a81bbba 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -63,6 +63,7 @@ struct AwesomePlayer { void setUID(uid_t uid); status_t setDataSource( + const sp<IMediaHTTPService> &httpService, const char *uri, const KeyedVector<String8, String8> *headers = NULL); @@ -159,6 +160,7 @@ private: SystemTimeSource mSystemTimeSource; TimeSource *mTimeSource; + sp<IMediaHTTPService> mHTTPService; String8 mUri; KeyedVector<String8, String8> mUriHeaders; @@ -247,6 +249,7 @@ private: sp<MediaExtractor> mExtractor; status_t setDataSource_l( + const sp<IMediaHTTPService> &httpService, const char *uri, const KeyedVector<String8, String8> *headers = NULL); diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h deleted file mode 100644 index 785f939..0000000 --- a/media/libstagefright/include/ChromiumHTTPDataSource.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2011 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 CHROME_HTTP_DATA_SOURCE_H_ - -#define CHROME_HTTP_DATA_SOURCE_H_ - -#include <media/stagefright/foundation/AString.h> -#include <utils/threads.h> - -#include "HTTPBase.h" - -namespace android { - -struct SfDelegate; - -struct ChromiumHTTPDataSource : public HTTPBase { - ChromiumHTTPDataSource(uint32_t flags = 0); - - virtual status_t connect( - const char *uri, - const KeyedVector<String8, String8> *headers = NULL, - off64_t offset = 0); - - virtual void disconnect(); - - virtual status_t initCheck() const; - - virtual ssize_t readAt(off64_t offset, void *data, size_t size); - virtual status_t getSize(off64_t *size); - virtual uint32_t flags(); - - virtual sp<DecryptHandle> DrmInitialization(const char *mime); - - virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client); - - virtual String8 getUri(); - - virtual String8 getMIMEType() const; - - virtual status_t reconnectAtOffset(off64_t offset); - - static status_t UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - -protected: - virtual ~ChromiumHTTPDataSource(); - -private: - friend struct SfDelegate; - - enum State { - DISCONNECTED, - CONNECTING, - CONNECTED, - READING, - DISCONNECTING - }; - - const uint32_t mFlags; - - mutable Mutex mLock; - Condition mCondition; - - State mState; - - SfDelegate *mDelegate; - - AString mURI; - KeyedVector<String8, String8> mHeaders; - - off64_t mCurrentOffset; - - // Any connection error or the result of a read operation - // (for the lattter this is the number of bytes read, if successful). - ssize_t mIOResult; - - int64_t mContentSize; - - String8 mContentType; - - sp<DecryptHandle> mDecryptHandle; - DrmManagerClient *mDrmManagerClient; - - void disconnect_l(); - - status_t connect_l( - const char *uri, - const KeyedVector<String8, String8> *headers, - off64_t offset); - - static void InitiateRead( - ChromiumHTTPDataSource *me, void *data, size_t size); - - void initiateRead(void *data, size_t size); - - void onConnectionEstablished( - int64_t contentSize, const char *contentType); - - void onConnectionFailed(status_t err); - void onReadCompleted(ssize_t size); - void onDisconnectComplete(); - - void clearDRMState_l(); - - DISALLOW_EVIL_CONSTRUCTORS(ChromiumHTTPDataSource); -}; - -} // namespace android - -#endif // CHROME_HTTP_DATA_SOURCE_H_ diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h index d4b7f9f..1c3cd5e 100644 --- a/media/libstagefright/include/HTTPBase.h +++ b/media/libstagefright/include/HTTPBase.h @@ -48,14 +48,6 @@ struct HTTPBase : public DataSource { virtual status_t setBandwidthStatCollectFreq(int32_t freqMs); - static status_t UpdateProxyConfig( - const char *host, int32_t port, const char *exclusionList); - - void setUID(uid_t uid); - bool getUID(uid_t *uid) const; - - static sp<HTTPBase> Create(uint32_t flags = 0); - static void RegisterSocketUserTag(int sockfd, uid_t uid, uint32_t kTag); static void UnRegisterSocketUserTag(int sockfd); @@ -87,9 +79,6 @@ private: int32_t mPrevEstimatedBandWidthKbps; int32_t mBandWidthCollectFreqMs; - bool mUIDValid; - uid_t mUID; - DISALLOW_EVIL_CONSTRUCTORS(HTTPBase); }; diff --git a/media/libstagefright/include/SDPLoader.h b/media/libstagefright/include/SDPLoader.h index ca59dc0..2c4f543 100644 --- a/media/libstagefright/include/SDPLoader.h +++ b/media/libstagefright/include/SDPLoader.h @@ -25,6 +25,7 @@ namespace android { struct HTTPBase; +struct IMediaHTTPService; struct SDPLoader : public AHandler { enum Flags { @@ -34,7 +35,10 @@ struct SDPLoader : public AHandler { enum { kWhatSDPLoaded = 'sdpl' }; - SDPLoader(const sp<AMessage> ¬ify, uint32_t flags = 0, bool uidValid = false, uid_t uid = 0); + SDPLoader( + const sp<AMessage> ¬ify, + uint32_t flags, + const sp<IMediaHTTPService> &httpService); void load(const char* url, const KeyedVector<String8, String8> *headers); @@ -55,8 +59,6 @@ private: sp<AMessage> mNotify; const char* mUrl; uint32_t mFlags; - bool mUIDValid; - uid_t mUID; sp<ALooper> mNetLooper; bool mCancelled; diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h index b02ed0e..6632c27 100644 --- a/media/libstagefright/include/StagefrightMetadataRetriever.h +++ b/media/libstagefright/include/StagefrightMetadataRetriever.h @@ -33,6 +33,7 @@ struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface { virtual ~StagefrightMetadataRetriever(); virtual status_t setDataSource( + const sp<IMediaHTTPService> &httpService, const char *url, const KeyedVector<String8, String8> *headers); diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index d260d0f..dcb1cda 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -716,41 +716,61 @@ bool MatroskaExtractor::isLiveStreaming() const { return mIsLiveStreaming; } +static int bytesForSize(size_t size) { + // use at most 28 bits (4 times 7) + CHECK(size <= 0xfffffff); + + if (size > 0x1fffff) { + return 4; + } else if (size > 0x3fff) { + return 3; + } else if (size > 0x7f) { + return 2; + } + return 1; +} + +static void storeSize(uint8_t *data, size_t &idx, size_t size) { + int numBytes = bytesForSize(size); + idx += numBytes; + + data += idx; + size_t next = 0; + while (numBytes--) { + *--data = (size & 0x7f) | next; + size >>= 7; + next = 0x80; + } +} + static void addESDSFromCodecPrivate( const sp<MetaData> &meta, bool isAudio, const void *priv, size_t privSize) { - static const uint8_t kStaticESDS[] = { - 0x03, 22, - 0x00, 0x00, // ES_ID - 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag - - 0x04, 17, - 0x40, // ObjectTypeIndication - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - 0x05, - // CodecSpecificInfo (with size prefix) follows - }; - // Make sure all sizes can be coded in a single byte. - CHECK(privSize + 22 - 2 < 128); - size_t esdsSize = sizeof(kStaticESDS) + privSize + 1; + int privSizeBytesRequired = bytesForSize(privSize); + int esdsSize2 = 14 + privSizeBytesRequired + privSize; + int esdsSize2BytesRequired = bytesForSize(esdsSize2); + int esdsSize1 = 4 + esdsSize2BytesRequired + esdsSize2; + int esdsSize1BytesRequired = bytesForSize(esdsSize1); + size_t esdsSize = 1 + esdsSize1BytesRequired + esdsSize1; uint8_t *esds = new uint8_t[esdsSize]; - memcpy(esds, kStaticESDS, sizeof(kStaticESDS)); - uint8_t *ptr = esds + sizeof(kStaticESDS); - *ptr++ = privSize; - memcpy(ptr, priv, privSize); - - // Increment by codecPrivateSize less 2 bytes that are accounted for - // already in lengths of 22/17 - esds[1] += privSize - 2; - esds[6] += privSize - 2; - - // Set ObjectTypeIndication. - esds[7] = isAudio ? 0x40 // Audio ISO/IEC 14496-3 - : 0x20; // Visual ISO/IEC 14496-2 + + size_t idx = 0; + esds[idx++] = 0x03; + storeSize(esds, idx, esdsSize1); + esds[idx++] = 0x00; // ES_ID + esds[idx++] = 0x00; // ES_ID + esds[idx++] = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag + esds[idx++] = 0x04; + storeSize(esds, idx, esdsSize2); + esds[idx++] = isAudio ? 0x40 // Audio ISO/IEC 14496-3 + : 0x20; // Visual ISO/IEC 14496-2 + for (int i = 0; i < 12; i++) { + esds[idx++] = 0x00; + } + esds[idx++] = 0x05; + storeSize(esds, idx, privSize); + memcpy(esds + idx, priv, privSize); meta->setData(kKeyESDS, 0, esds, esdsSize); diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp index 20fa7ce..1e6de55 100644 --- a/media/libstagefright/omx/GraphicBufferSource.cpp +++ b/media/libstagefright/omx/GraphicBufferSource.cpp @@ -45,6 +45,7 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance, mMaxTimestampGapUs(-1ll), mPrevOriginalTimeUs(-1ll), mPrevModifiedTimeUs(-1ll), + mSkipFramesBeforeNs(-1ll), mRepeatLastFrameGeneration(0), mRepeatLastFrameTimestamp(-1ll), mLatestSubmittedBufferId(-1), @@ -414,7 +415,18 @@ bool GraphicBufferSource::fillCodecBuffer_l() { mBufferSlot[item.mBuf] = item.mGraphicBuffer; } - err = submitBuffer_l(item, cbi); + err = UNKNOWN_ERROR; + + // only submit sample if start time is unspecified, or sample + // is queued after the specified start time + if (mSkipFramesBeforeNs < 0ll || item.mTimestamp >= mSkipFramesBeforeNs) { + // if start time is set, offset time stamp by start time + if (mSkipFramesBeforeNs > 0) { + item.mTimestamp -= mSkipFramesBeforeNs; + } + err = submitBuffer_l(item, cbi); + } + if (err != OK) { ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf); mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber, @@ -762,6 +774,14 @@ status_t GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) { return OK; } + +void GraphicBufferSource::setSkipFramesBeforeUs(int64_t skipFramesBeforeUs) { + Mutex::Autolock autoLock(mMutex); + + mSkipFramesBeforeNs = + (skipFramesBeforeUs > 0) ? (skipFramesBeforeUs * 1000) : -1ll; +} + void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatRepeatLastFrame: diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h index 3b0e454..153f2a0 100644 --- a/media/libstagefright/omx/GraphicBufferSource.h +++ b/media/libstagefright/omx/GraphicBufferSource.h @@ -118,6 +118,10 @@ public: // of suspension on input. status_t setMaxTimestampGapUs(int64_t maxGapUs); + // Sets the start time us (in system time), samples before which should + // be dropped and not submitted to encoder + void setSkipFramesBeforeUs(int64_t startTimeUs); + protected: // BufferQueue::ConsumerListener interface, called when a new frame of // data is available. If we're executing and a codec buffer is @@ -223,16 +227,17 @@ private: enum { kRepeatLastFrameCount = 10, }; - int64_t mRepeatAfterUs; - int64_t mMaxTimestampGapUs; KeyedVector<int64_t, int64_t> mOriginalTimeUs; + int64_t mMaxTimestampGapUs; int64_t mPrevOriginalTimeUs; int64_t mPrevModifiedTimeUs; + int64_t mSkipFramesBeforeNs; sp<ALooper> mLooper; sp<AHandlerReflector<GraphicBufferSource> > mReflector; + int64_t mRepeatAfterUs; int32_t mRepeatLastFrameGeneration; int64_t mRepeatLastFrameTimestamp; int32_t mRepeatLastFrameCount; diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 6c5c857..dba522f 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -850,6 +850,7 @@ status_t OMXNodeInstance::setInternalOption( case IOMX::INTERNAL_OPTION_SUSPEND: case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY: case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: + case IOMX::INTERNAL_OPTION_START_TIME: { const sp<GraphicBufferSource> &bufferSource = getGraphicBufferSource(); @@ -874,7 +875,8 @@ status_t OMXNodeInstance::setInternalOption( int64_t delayUs = *(int64_t *)data; return bufferSource->setRepeatPreviousFrameDelayUs(delayUs); - } else { + } else if (type == + IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP){ if (size != sizeof(int64_t)) { return INVALID_OPERATION; } @@ -882,6 +884,14 @@ status_t OMXNodeInstance::setInternalOption( int64_t maxGapUs = *(int64_t *)data; return bufferSource->setMaxTimestampGapUs(maxGapUs); + } else { // IOMX::INTERNAL_OPTION_START_TIME + if (size != sizeof(int64_t)) { + return INVALID_OPERATION; + } + + int64_t skipFramesBeforeUs = *(int64_t *)data; + + bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs); } return OK; diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp index 4bee808..499545e 100644 --- a/media/libstagefright/omx/tests/OMXHarness.cpp +++ b/media/libstagefright/omx/tests/OMXHarness.cpp @@ -25,6 +25,7 @@ #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <binder/MemoryDealer.h> +#include <media/IMediaHTTPService.h> #include <media/IMediaPlayerService.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALooper.h> @@ -241,7 +242,8 @@ private: }; static sp<MediaExtractor> CreateExtractorFromURI(const char *uri) { - sp<DataSource> source = DataSource::CreateFromURI(uri); + sp<DataSource> source = + DataSource::CreateFromURI(NULL /* httpService */, uri); if (source == NULL) { return NULL; diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp index 462c384..09f52bc 100644 --- a/media/libstagefright/rtsp/APacketSource.cpp +++ b/media/libstagefright/rtsp/APacketSource.cpp @@ -23,7 +23,7 @@ #include "ARawAudioAssembler.h" #include "ASessionDescription.h" -#include "avc_utils.h" +#include "include/avc_utils.h" #include <ctype.h> diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp index efde7a9..4054da6 100644 --- a/media/libstagefright/rtsp/ARTSPConnection.cpp +++ b/media/libstagefright/rtsp/ARTSPConnection.cpp @@ -33,7 +33,7 @@ #include <openssl/md5.h> #include <sys/socket.h> -#include "HTTPBase.h" +#include "include/HTTPBase.h" namespace android { diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk index e77c69c..02e44f4 100644 --- a/media/libstagefright/rtsp/Android.mk +++ b/media/libstagefright/rtsp/Android.mk @@ -20,7 +20,7 @@ LOCAL_SRC_FILES:= \ SDPLoader.cpp \ LOCAL_C_INCLUDES:= \ - $(TOP)/frameworks/av/media/libstagefright/include \ + $(TOP)/frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/external/openssl/include diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp index ed3fa7e..ce1e89d 100644 --- a/media/libstagefright/rtsp/SDPLoader.cpp +++ b/media/libstagefright/rtsp/SDPLoader.cpp @@ -18,11 +18,13 @@ #define LOG_TAG "SDPLoader" #include <utils/Log.h> -#include "SDPLoader.h" +#include "include/SDPLoader.h" #include "ASessionDescription.h" -#include "HTTPBase.h" +#include <media/IMediaHTTPConnection.h> +#include <media/IMediaHTTPService.h> +#include <media/stagefright/MediaHTTP.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> @@ -30,22 +32,15 @@ namespace android { -SDPLoader::SDPLoader(const sp<AMessage> ¬ify, uint32_t flags, bool uidValid, uid_t uid) +SDPLoader::SDPLoader( + const sp<AMessage> ¬ify, + uint32_t flags, + const sp<IMediaHTTPService> &httpService) : mNotify(notify), mFlags(flags), - mUIDValid(uidValid), - mUID(uid), mNetLooper(new ALooper), mCancelled(false), - mHTTPDataSource( - HTTPBase::Create( - (mFlags & kFlagIncognito) - ? HTTPBase::kFlagIncognito - : 0)) { - if (mUIDValid) { - mHTTPDataSource->setUID(mUID); - } - + mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) { mNetLooper->setName("sdp net"); mNetLooper->start(false /* runOnCallingThread */, false /* canCallJava */, @@ -130,7 +125,7 @@ void SDPLoader::onLoad(const sp<AMessage> &msg) { ssize_t readSize = mHTTPDataSource->readAt(0, buffer->data(), sdpSize); if (readSize < 0) { - ALOGE("Failed to read SDP, error code = %ld", readSize); + ALOGE("Failed to read SDP, error code = %d", readSize); err = UNKNOWN_ERROR; } else { desc = new ASessionDescription; diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp index 49ffcd6..ddedad7 100644 --- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp +++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp @@ -746,9 +746,8 @@ TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuYV12BufferNpotWriteMediaS CHECK(fd >= 0); sp<MediaRecorder> mr = SurfaceMediaSourceGLTest::setUpMediaRecorder(fd, - VIDEO_SOURCE_GRALLOC_BUFFER, - OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, - mYuvTexHeight, 30); + VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, + mYuvTexWidth, mYuvTexHeight, 30); // get the reference to the surfacemediasource living in // mediaserver that is created by stagefrightrecorder sp<IGraphicBufferProducer> iST = mr->querySurfaceMediaSourceFromMediaServer(); @@ -880,7 +879,7 @@ TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaSameImageEachBufNpotWrite) { } CHECK(fd >= 0); - sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_GRALLOC_BUFFER, + sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30); // get the reference to the surfacemediasource living in @@ -923,7 +922,7 @@ TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaDiffImageEachBufNpotWrite) { } CHECK(fd >= 0); - sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_GRALLOC_BUFFER, + sp<MediaRecorder> mr = setUpMediaRecorder(fd, VIDEO_SOURCE_SURFACE, OUTPUT_FORMAT_MPEG_4, VIDEO_ENCODER_H264, mYuvTexWidth, mYuvTexHeight, 30); // get the reference to the surfacemediasource living in diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp index 12fd7f4..05d6d02 100644 --- a/media/libstagefright/timedtext/TimedTextDriver.cpp +++ b/media/libstagefright/timedtext/TimedTextDriver.cpp @@ -20,6 +20,7 @@ #include <binder/IPCThreadState.h> +#include <media/IMediaHTTPService.h> #include <media/mediaplayer.h> #include <media/MediaPlayerInterface.h> #include <media/stagefright/DataSource.h> @@ -40,7 +41,8 @@ namespace android { TimedTextDriver::TimedTextDriver( - const wp<MediaPlayerBase> &listener) + const wp<MediaPlayerBase> &listener, + const sp<IMediaHTTPService> &httpService) : mLooper(new ALooper), mListener(listener), mState(UNINITIALIZED), @@ -207,7 +209,7 @@ status_t TimedTextDriver::addOutOfBandTextSource( } sp<DataSource> dataSource = - DataSource::CreateFromURI(uri); + DataSource::CreateFromURI(mHTTPService, uri); return createOutOfBandTextSource(trackIndex, mimeType, dataSource); } diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp index 286ea13..1a5acba 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp +++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp @@ -29,6 +29,7 @@ #include <binder/IServiceManager.h> #include <cutils/properties.h> #include <media/IHDCP.h> +#include <media/IMediaHTTPService.h> #include <media/stagefright/foundation/ABitReader.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> @@ -749,7 +750,8 @@ status_t WifiDisplaySource::PlaybackSession::setupMediaPacketizer( mExtractor = new NuMediaExtractor; - status_t err = mExtractor->setDataSource(mMediaPath.c_str()); + status_t err = mExtractor->setDataSource( + NULL /* httpService */, mMediaPath.c_str()); if (err != OK) { return err; diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp index d5207d5..a347951 100644 --- a/media/mediaserver/main_mediaserver.cpp +++ b/media/mediaserver/main_mediaserver.cpp @@ -37,7 +37,7 @@ using namespace android; -int main(int argc, char** argv) +int main(int argc __unused, char** argv) { signal(SIGPIPE, SIG_IGN); char value[PROPERTY_VALUE_MAX]; |