summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/Android.mk7
-rw-r--r--media/libmedia/AudioEffect.cpp4
-rw-r--r--media/libmedia/AudioRecord.cpp106
-rw-r--r--media/libmedia/AudioSystem.cpp81
-rw-r--r--media/libmedia/AudioTrack.cpp326
-rw-r--r--media/libmedia/AudioTrackShared.cpp25
-rw-r--r--media/libmedia/CharacterEncodingDetector.cpp364
-rw-r--r--media/libmedia/CharacterEncodingDetector.h61
-rw-r--r--media/libmedia/CharacterEncodingDetectorTables.h2092
-rw-r--r--media/libmedia/IAudioFlinger.cpp97
-rw-r--r--media/libmedia/IAudioRecord.cpp3
-rw-r--r--media/libmedia/IAudioTrack.cpp6
-rw-r--r--media/libmedia/IEffect.cpp3
-rw-r--r--media/libmedia/IMediaDeathNotifier.cpp2
-rw-r--r--media/libmedia/IMediaHTTPConnection.cpp158
-rw-r--r--media/libmedia/IMediaHTTPService.cpp58
-rw-r--r--media/libmedia/IMediaMetadataRetriever.cpp19
-rw-r--r--media/libmedia/IMediaPlayer.cpp19
-rw-r--r--media/libmedia/IMediaPlayerService.cpp68
-rw-r--r--media/libmedia/MediaProfiles.cpp20
-rw-r--r--media/libmedia/MediaScannerClient.cpp202
-rw-r--r--media/libmedia/SoundPool.cpp24
-rw-r--r--media/libmedia/autodetect.cpp885
-rw-r--r--media/libmedia/autodetect.h37
-rw-r--r--media/libmedia/mediametadataretriever.cpp9
-rw-r--r--media/libmedia/mediaplayer.cpp29
-rw-r--r--media/libmediaplayerservice/HDCP.cpp6
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp25
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h22
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp7
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.h5
-rw-r--r--media/libmediaplayerservice/MidiFile.cpp4
-rw-r--r--media/libmediaplayerservice/MidiFile.h4
-rw-r--r--media/libmediaplayerservice/MidiMetadataRetriever.cpp8
-rw-r--r--media/libmediaplayerservice/MidiMetadataRetriever.h4
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp6
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.h4
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp350
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h36
-rw-r--r--media/libmediaplayerservice/TestPlayerStub.cpp6
-rw-r--r--media/libmediaplayerservice/TestPlayerStub.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.cpp7
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.h5
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp11
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.h8
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp14
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp6
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/RTSPSource.cpp5
-rw-r--r--media/libmediaplayerservice/nuplayer/RTSPSource.h2
-rw-r--r--media/libnbaio/AudioBufferProviderSource.cpp4
-rw-r--r--media/libnbaio/AudioStreamInSource.cpp4
-rw-r--r--media/libnbaio/AudioStreamOutSink.cpp4
-rw-r--r--media/libnbaio/MonoPipe.cpp2
-rw-r--r--media/libnbaio/NBAIO.cpp41
-rw-r--r--media/libnbaio/NBLog.cpp2
-rw-r--r--media/libnbaio/Pipe.cpp2
-rw-r--r--media/libnbaio/PipeReader.cpp2
-rw-r--r--media/libstagefright/ACodec.cpp78
-rw-r--r--media/libstagefright/Android.mk9
-rw-r--r--media/libstagefright/AudioSource.cpp2
-rw-r--r--media/libstagefright/AwesomePlayer.cpp41
-rw-r--r--media/libstagefright/CameraSourceTimeLapse.cpp3
-rw-r--r--media/libstagefright/DataSource.cpp18
-rw-r--r--media/libstagefright/HTTPBase.cpp48
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp159
-rw-r--r--media/libstagefright/MPEG4Writer.cpp24
-rw-r--r--media/libstagefright/MediaCodecSource.cpp881
-rw-r--r--media/libstagefright/NuCachedSource2.cpp9
-rw-r--r--media/libstagefright/NuMediaExtractor.cpp6
-rw-r--r--media/libstagefright/SkipCutBuffer.cpp3
-rw-r--r--media/libstagefright/StagefrightMediaScanner.cpp3
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp7
-rw-r--r--media/libstagefright/chromium_http/Android.mk37
-rw-r--r--media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp350
-rw-r--r--media/libstagefright/chromium_http/DataUriSource.cpp68
-rw-r--r--media/libstagefright/chromium_http/chromium_http_stub.cpp38
-rw-r--r--media/libstagefright/chromium_http/support.cpp558
-rw-r--r--media/libstagefright/chromium_http/support.h178
-rw-r--r--media/libstagefright/chromium_http_stub.cpp102
-rw-r--r--media/libstagefright/codecs/aacdec/SoftAAC2.cpp230
-rw-r--r--media/libstagefright/codecs/aacdec/SoftAAC2.h2
-rw-r--r--media/libstagefright/codecs/mp3dec/SoftMP3.cpp117
-rw-r--r--media/libstagefright/codecs/mp3dec/SoftMP3.h2
-rw-r--r--media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp79
-rw-r--r--media/libstagefright/codecs/vorbis/dec/SoftVorbis.h2
-rw-r--r--media/libstagefright/http/Android.mk26
-rw-r--r--media/libstagefright/http/HTTPHelper.cpp70
-rw-r--r--media/libstagefright/http/HTTPHelper.h (renamed from media/libstagefright/include/chromium_http_stub.h)23
-rw-r--r--media/libstagefright/http/MediaHTTP.cpp201
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp19
-rw-r--r--media/libstagefright/httplive/LiveSession.h7
-rw-r--r--media/libstagefright/httplive/PlaylistFetcher.cpp136
-rw-r--r--media/libstagefright/httplive/PlaylistFetcher.h7
-rw-r--r--media/libstagefright/id3/ID3.cpp79
-rw-r--r--media/libstagefright/include/AwesomePlayer.h3
-rw-r--r--media/libstagefright/include/ChromiumHTTPDataSource.h124
-rw-r--r--media/libstagefright/include/HTTPBase.h11
-rw-r--r--media/libstagefright/include/SDPLoader.h8
-rw-r--r--media/libstagefright/include/StagefrightMetadataRetriever.h1
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp80
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.cpp48
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.cpp128
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.h30
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp36
-rw-r--r--media/libstagefright/omx/tests/OMXHarness.cpp4
-rw-r--r--media/libstagefright/rtsp/APacketSource.cpp2
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.cpp2
-rw-r--r--media/libstagefright/rtsp/Android.mk2
-rw-r--r--media/libstagefright/rtsp/SDPLoader.cpp25
-rw-r--r--media/libstagefright/tests/SurfaceMediaSource_test.cpp9
-rw-r--r--media/libstagefright/timedtext/TimedTextDriver.cpp6
-rw-r--r--media/libstagefright/timedtext/test/Android.mk8
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.cpp4
-rw-r--r--media/libstagefright/wifi-display/source/TSPacketizer.cpp2
-rw-r--r--media/mediaserver/Android.mk1
-rw-r--r--media/mediaserver/main_mediaserver.cpp2
118 files changed, 5794 insertions, 3687 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 56e7787..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 \
@@ -44,7 +46,7 @@ LOCAL_SRC_FILES:= \
IAudioPolicyService.cpp \
MediaScanner.cpp \
MediaScannerClient.cpp \
- autodetect.cpp \
+ CharacterEncodingDetector.cpp \
IMediaDeathNotifier.cpp \
MediaProfiles.cpp \
IEffect.cpp \
@@ -65,7 +67,7 @@ LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiat
# Consider a separate a library for SingleStateQueueInstantiations.
LOCAL_SHARED_LIBRARIES := \
- libui liblog libcutils libutils libbinder libsonivox libicuuc libexpat \
+ libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
libcamera_client libstagefright_foundation \
libgui libdl libaudioutils
@@ -77,6 +79,7 @@ LOCAL_C_INCLUDES := \
$(call include-path-for, graphics corecg) \
$(TOP)/frameworks/native/include/media/openmax \
external/icu4c/common \
+ external/icu4c/i18n \
$(call include-path-for, audio-effects) \
$(call include-path-for, audio-utils)
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 666fafa..541cb51 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -52,7 +52,7 @@ status_t AudioRecord::getMinFrameCount(
}
if (size == 0) {
- ALOGE("Unsupported configuration: sampleRate %u, format %d, channelMask %#x",
+ ALOGE("Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
sampleRate, format, channelMask);
return BAD_VALUE;
}
@@ -71,7 +71,7 @@ status_t AudioRecord::getMinFrameCount(
// ---------------------------------------------------------------------------
AudioRecord::AudioRecord()
- : mStatus(NO_INIT), mSessionId(0),
+ : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT)
{
}
@@ -87,8 +87,8 @@ AudioRecord::AudioRecord(
int notificationFrames,
int sessionId,
transfer_type transferType,
- audio_input_flags_t flags)
- : mStatus(NO_INIT), mSessionId(0),
+ audio_input_flags_t flags __unused)
+ : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
mPreviousSchedulingGroup(SP_DEFAULT),
mProxy(NULL)
@@ -191,12 +191,12 @@ status_t AudioRecord::set(
// validate parameters
if (!audio_is_valid_format(format)) {
- ALOGE("Invalid format %d", format);
+ ALOGE("Invalid format %#x", format);
return BAD_VALUE;
}
// Temporary restriction: AudioFlinger currently supports 16-bit PCM only
if (format != AUDIO_FORMAT_PCM_16_BIT) {
- ALOGE("Format %d is not supported", format);
+ ALOGE("Format %#x is not supported", format);
return BAD_VALUE;
}
mFormat = format;
@@ -228,12 +228,13 @@ 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;
- if (sessionId == 0 ) {
+ if (sessionId == AUDIO_SESSION_ALLOCATE) {
mSessionId = AudioSystem::newAudioSessionId();
} else {
mSessionId = sessionId;
@@ -244,7 +245,7 @@ status_t AudioRecord::set(
// create the IAudioRecord
status = openRecord_l(0 /*epoch*/);
- if (status) {
+ if (status != NO_ERROR) {
return status;
}
@@ -255,9 +256,6 @@ status_t AudioRecord::set(
mStatus = NO_ERROR;
- // Update buffer size in case it has been limited by AudioFlinger during track creation
- mFrameCount = mCblk->frameCount_;
-
mActive = false;
mCbf = cbf;
mRefreshRemaining = true;
@@ -289,6 +287,9 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
// reset current position as seen by client to 0
mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
+ // force refresh of remaining frames by processAudioBuffer() as last
+ // read before stop could be partial.
+ mRefreshRemaining = true;
mNewPosition = mProxy->getPosition() + mUpdatePeriod;
int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
@@ -352,6 +353,7 @@ bool AudioRecord::stopped() const
status_t AudioRecord::setMarkerPosition(uint32_t marker)
{
+ // The only purpose of setting marker position is to get a callback
if (mCbf == NULL) {
return INVALID_OPERATION;
}
@@ -377,6 +379,7 @@ status_t AudioRecord::getMarkerPosition(uint32_t *marker) const
status_t AudioRecord::setPositionUpdatePeriod(uint32_t updatePeriod)
{
+ // The only purpose of setting position update period is to get a callback
if (mCbf == NULL) {
return INVALID_OPERATION;
}
@@ -412,7 +415,7 @@ status_t AudioRecord::getPosition(uint32_t *position) const
return NO_ERROR;
}
-unsigned int AudioRecord::getInputFramesLost() const
+uint32_t AudioRecord::getInputFramesLost() const
{
// no need to check mActive, because if inactive this will return 0, which is what we want
return AudioSystem::getInputFramesLost(getInput());
@@ -447,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;
}
}
@@ -461,24 +465,31 @@ status_t AudioRecord::openRecord_l(size_t epoch)
ALOGE("Could not get audio input for record source %d", mInputSource);
return BAD_VALUE;
}
+ {
+ // 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 = 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,
mSampleRate, mFormat,
mChannelMask,
- mFrameCount,
+ &temp,
&trackFlags,
tid,
&mSessionId,
&status);
- ALOGE_IF(originalSessionId != 0 && mSessionId != originalSessionId,
+ ALOGE_IF(originalSessionId != AUDIO_SESSION_ALLOCATE && mSessionId != originalSessionId,
"session ID changed from %d to %d", originalSessionId, mSessionId);
if (record == 0 || status != NO_ERROR) {
ALOGE("AudioFlinger could not create record track, status: %d", status);
- AudioSystem::releaseInput(input);
- return status;
+ goto release;
}
+ // AudioFlinger now owns the reference to the I/O handle,
+ // so we are no longer responsible for releasing it.
+
sp<IMemory> iMem = record->getCblk();
if (iMem == 0) {
ALOGE("Could not get control block");
@@ -493,11 +504,24 @@ status_t AudioRecord::openRecord_l(size_t epoch)
mAudioRecord->asBinder()->unlinkToDeath(mDeathNotifier, this);
mDeathNotifier.clear();
}
+
+ // We retain a copy of the I/O handle, but don't own the reference
mInput = input;
mAudioRecord = record;
mCblkMemory = iMem;
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 < 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;
+ }
+
// FIXME missing fast track frameCount logic
mAwaitBoost = false;
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
@@ -521,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);
@@ -530,6 +556,14 @@ status_t AudioRecord::openRecord_l(size_t epoch)
mAudioRecord->asBinder()->linkToDeath(mDeathNotifier, this);
return NO_ERROR;
+ }
+
+release:
+ AudioSystem::releaseInput(input);
+ if (status == NO_ERROR) {
+ status = NO_INIT;
+ }
+ return status;
}
status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -545,13 +579,13 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
}
const struct timespec *requested;
+ struct timespec timeout;
if (waitCount == -1) {
requested = &ClientProxy::kForever;
} else if (waitCount == 0) {
requested = &ClientProxy::kNonBlocking;
} else if (waitCount > 0) {
long long ms = WAIT_PERIOD_MS * (long long) waitCount;
- struct timespec timeout;
timeout.tv_sec = ms / 1000;
timeout.tv_nsec = (int) (ms % 1000) * 1000000;
requested = &timeout;
@@ -591,6 +625,9 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *r
if (newSequence == oldSequence) {
status = restoreRecord_l("obtainBuffer");
if (status != NO_ERROR) {
+ buffer.mFrameCount = 0;
+ buffer.mRaw = NULL;
+ buffer.mNonContig = 0;
break;
}
}
@@ -692,7 +729,7 @@ ssize_t AudioRecord::read(void* buffer, size_t userSize)
// -------------------------------------------------------------------------
-nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
+nsecs_t AudioRecord::processAudioBuffer()
{
mLock.lock();
if (mAwaitBoost) {
@@ -767,10 +804,10 @@ nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
mRetryOnPartialBuffer = false;
}
size_t misalignment = mProxy->getMisalignment();
- int32_t sequence = mSequence;
+ uint32_t sequence = mSequence;
// These fields don't need to be cached, because they are assigned only by set():
- // mTransfer, mCbf, mUserData, mSampleRate
+ // mTransfer, mCbf, mUserData, mSampleRate, mFrameSize
mLock.unlock();
@@ -844,8 +881,8 @@ nsecs_t AudioRecord::processAudioBuffer(const sp<AudioRecordThread>& thread)
"obtainBuffer() err=%d frameCount=%u", err, audioBuffer.frameCount);
requested = &ClientProxy::kNonBlocking;
size_t avail = audioBuffer.frameCount + nonContig;
- ALOGV("obtainBuffer(%u) returned %u = %u + %u",
- mRemainingFrames, avail, audioBuffer.frameCount, nonContig);
+ ALOGV("obtainBuffer(%u) returned %u = %u + %u err %d",
+ mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
if (err != NO_ERROR) {
if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) {
break;
@@ -954,7 +991,7 @@ status_t AudioRecord::restoreRecord_l(const char *from)
// =========================================================================
-void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who)
+void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
{
sp<AudioRecord> audioRecord = mAudioRecord.promote();
if (audioRecord != 0) {
@@ -966,7 +1003,8 @@ void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who)
// =========================================================================
AudioRecord::AudioRecordThread::AudioRecordThread(AudioRecord& receiver, bool bCanCallJava)
- : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL)
+ : Thread(bCanCallJava), mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
+ mIgnoreNextPausedInt(false)
{
}
@@ -983,6 +1021,10 @@ bool AudioRecord::AudioRecordThread::threadLoop()
// caller will check for exitPending()
return true;
}
+ if (mIgnoreNextPausedInt) {
+ mIgnoreNextPausedInt = false;
+ mPausedInt = false;
+ }
if (mPausedInt) {
if (mPausedNs > 0) {
(void) mMyCond.waitRelative(mMyLock, mPausedNs);
@@ -993,7 +1035,7 @@ bool AudioRecord::AudioRecordThread::threadLoop()
return true;
}
}
- nsecs_t ns = mReceiver.processAudioBuffer(this);
+ nsecs_t ns = mReceiver.processAudioBuffer();
switch (ns) {
case 0:
return true;
@@ -1017,12 +1059,7 @@ void AudioRecord::AudioRecordThread::requestExit()
{
// must be in this order to avoid a race condition
Thread::requestExit();
- AutoMutex _l(mMyLock);
- if (mPaused || mPausedInt) {
- mPaused = false;
- mPausedInt = false;
- mMyCond.signal();
- }
+ resume();
}
void AudioRecord::AudioRecordThread::pause()
@@ -1034,6 +1071,7 @@ void AudioRecord::AudioRecordThread::pause()
void AudioRecord::AudioRecordThread::resume()
{
AutoMutex _l(mMyLock);
+ mIgnoreNextPausedInt = true;
if (mPaused || mPausedInt) {
mPaused = false;
mPausedInt = false;
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 8033c2c..72a60ea 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -40,10 +40,10 @@ audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
// Cached values for recording queries, all protected by gLock
-uint32_t AudioSystem::gPrevInSamplingRate = 16000;
-audio_format_t AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT;
-audio_channel_mask_t AudioSystem::gPrevInChannelMask = AUDIO_CHANNEL_IN_MONO;
-size_t AudioSystem::gInBuffSize = 0;
+uint32_t AudioSystem::gPrevInSamplingRate;
+audio_format_t AudioSystem::gPrevInFormat;
+audio_channel_mask_t AudioSystem::gPrevInChannelMask;
+size_t AudioSystem::gInBuffSize = 0; // zero indicates cache is invalid
// establish binder interface to AudioFlinger service
@@ -84,13 +84,15 @@ const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
return DEAD_OBJECT;
}
-status_t AudioSystem::muteMicrophone(bool state) {
+status_t AudioSystem::muteMicrophone(bool state)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setMicMute(state);
}
-status_t AudioSystem::isMicrophoneMuted(bool* state) {
+status_t AudioSystem::isMicrophoneMuted(bool* state)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
*state = af->getMicMute();
@@ -175,13 +177,15 @@ status_t AudioSystem::setMode(audio_mode_t mode)
return af->setMode(mode);
}
-status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
+status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setParameters(ioHandle, keyValuePairs);
}
-String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys) {
+String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& keys)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
String8 result = String8("");
if (af == 0) return result;
@@ -190,6 +194,16 @@ String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& ke
return result;
}
+status_t AudioSystem::setParameters(const String8& keyValuePairs)
+{
+ return setParameters((audio_io_handle_t) 0, keyValuePairs);
+}
+
+String8 AudioSystem::getParameters(const String8& keys)
+{
+ return getParameters((audio_io_handle_t) 0, keys);
+}
+
// convert volume steps to natural log scale
// change this value to change volume scaling
@@ -249,6 +263,11 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output,
*samplingRate = outputDesc->samplingRate;
gLock.unlock();
}
+ if (*samplingRate == 0) {
+ ALOGE("AudioSystem::getSamplingRate failed for output %d stream type %d",
+ output, streamType);
+ return BAD_VALUE;
+ }
ALOGV("getSamplingRate() streamType %d, output %d, sampling rate %u", streamType, output,
*samplingRate);
@@ -289,6 +308,11 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output,
*frameCount = outputDesc->frameCount;
gLock.unlock();
}
+ if (*frameCount == 0) {
+ ALOGE("AudioSystem::getFrameCount failed for output %d stream type %d",
+ output, streamType);
+ return BAD_VALUE;
+ }
ALOGV("getFrameCount() streamType %d, output %d, frameCount %d", streamType, output,
*frameCount);
@@ -313,7 +337,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;
@@ -349,6 +373,12 @@ status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t for
return PERMISSION_DENIED;
}
inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask);
+ if (inBuffSize == 0) {
+ ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %x",
+ sampleRate, format, channelMask);
+ return BAD_VALUE;
+ }
+ // A benign race is possible here: we could overwrite a fresher cache entry
gLock.lock();
// save the request params
gPrevInSamplingRate = sampleRate;
@@ -387,9 +417,10 @@ status_t AudioSystem::getRenderPosition(audio_io_handle_t output, size_t *halFra
return af->getRenderPosition(halFrames, dspFrames, output);
}
-size_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) {
+uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- unsigned int result = 0;
+ uint32_t result = 0;
if (af == 0) return result;
if (ioHandle == 0) return result;
@@ -397,20 +428,23 @@ size_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) {
return result;
}
-int AudioSystem::newAudioSessionId() {
+int AudioSystem::newAudioSessionId()
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return 0;
return af->newAudioSessionId();
}
-void AudioSystem::acquireAudioSessionId(int audioSession) {
+void AudioSystem::acquireAudioSessionId(int audioSession)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af != 0) {
af->acquireAudioSessionId(audioSession);
}
}
-void AudioSystem::releaseAudioSessionId(int audioSession) {
+void AudioSystem::releaseAudioSessionId(int audioSession)
+{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af != 0) {
af->releaseAudioSessionId(audioSession);
@@ -419,7 +453,8 @@ void AudioSystem::releaseAudioSessionId(int audioSession) {
// ---------------------------------------------------------------------------
-void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who __unused)
+{
Mutex::Autolock _l(AudioSystem::gLock);
AudioSystem::gAudioFlinger.clear();
@@ -455,7 +490,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle
OutputDescriptor *outputDesc = new OutputDescriptor(*desc);
gOutputs.add(ioHandle, outputDesc);
- ALOGV("ioConfigChanged() new output samplingRate %u, format %d channel mask %#x frameCount %u "
+ ALOGV("ioConfigChanged() new output samplingRate %u, format %#x channel mask %#x frameCount %u "
"latency %d",
outputDesc->samplingRate, outputDesc->format, outputDesc->channelMask,
outputDesc->frameCount, outputDesc->latency);
@@ -479,7 +514,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle
if (param2 == NULL) break;
desc = (const OutputDescriptor *)param2;
- ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %d channel mask %#x "
+ ALOGV("ioConfigChanged() new config for output %d samplingRate %u, format %#x channel mask %#x "
"frameCount %d latency %d",
ioHandle, desc->samplingRate, desc->format,
desc->channelMask, desc->frameCount, desc->latency);
@@ -496,12 +531,14 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle
}
}
-void AudioSystem::setErrorCallback(audio_error_callback cb) {
+void AudioSystem::setErrorCallback(audio_error_callback cb)
+{
Mutex::Autolock _l(gLock);
gAudioErrorCallback = cb;
}
-bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType) {
+bool AudioSystem::routedToA2dpOutput(audio_stream_type_t streamType)
+{
switch (streamType) {
case AUDIO_STREAM_MUSIC:
case AUDIO_STREAM_VOICE_CALL:
@@ -709,7 +746,8 @@ audio_devices_t AudioSystem::getDevicesForStream(audio_stream_type_t stream)
audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t *desc)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
+ // FIXME change return type to status_t, and return PERMISSION_DENIED here
+ if (aps == 0) return 0;
return aps->getOutputForEffect(desc);
}
@@ -804,7 +842,8 @@ bool AudioSystem::isOffloadSupported(const audio_offload_info_t& info)
// ---------------------------------------------------------------------------
-void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who) {
+void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
+{
Mutex::Autolock _l(AudioSystem::gLock);
AudioSystem::gAudioPolicyService.clear();
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 0609a22..41b4845 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -44,9 +44,6 @@ status_t AudioTrack::getMinFrameCount(
return BAD_VALUE;
}
- // default to 0 in case of error
- *frameCount = 0;
-
// FIXME merge with similar code in createTrack_l(), except we're missing
// some information here that is available in createTrack_l():
// audio_io_handle_t output
@@ -54,16 +51,26 @@ status_t AudioTrack::getMinFrameCount(
// audio_channel_mask_t channelMask
// audio_output_flags_t flags
uint32_t afSampleRate;
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
- return NO_INIT;
+ status_t status;
+ status = AudioSystem::getOutputSamplingRate(&afSampleRate, streamType);
+ if (status != NO_ERROR) {
+ ALOGE("Unable to query output sample rate for stream type %d; status %d",
+ streamType, status);
+ return status;
}
size_t afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
- return NO_INIT;
+ status = AudioSystem::getOutputFrameCount(&afFrameCount, streamType);
+ if (status != NO_ERROR) {
+ ALOGE("Unable to query output frame count for stream type %d; status %d",
+ streamType, status);
+ return status;
}
uint32_t afLatency;
- if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
- return NO_INIT;
+ status = AudioSystem::getOutputLatency(&afLatency, streamType);
+ if (status != NO_ERROR) {
+ ALOGE("Unable to query output latency for stream type %d; status %d",
+ streamType, status);
+ return status;
}
// Ensure that buffer depth covers at least audio hardware latency
@@ -74,6 +81,13 @@ status_t AudioTrack::getMinFrameCount(
*frameCount = (sampleRate == 0) ? afFrameCount * minBufCount :
afFrameCount * minBufCount * sampleRate / afSampleRate;
+ // The formula above should always produce a non-zero value, but return an error
+ // in the unlikely event that it does not, as that's part of the API contract.
+ if (*frameCount == 0) {
+ ALOGE("AudioTrack::getMinFrameCount failed for streamType %d, sampleRate %d",
+ streamType, sampleRate);
+ return BAD_VALUE;
+ }
ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d",
*frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
return NO_ERROR;
@@ -208,6 +222,7 @@ status_t AudioTrack::set(
ALOGE("Invalid transfer type %d", transferType);
return BAD_VALUE;
}
+ mSharedBuffer = sharedBuffer;
mTransfer = transferType;
// FIXME "int" here is legacy and will be replaced by size_t later
@@ -230,19 +245,24 @@ status_t AudioTrack::set(
return INVALID_OPERATION;
}
- mOutput = 0;
-
// handle default values first.
if (streamType == AUDIO_STREAM_DEFAULT) {
streamType = AUDIO_STREAM_MUSIC;
}
+ if (uint32_t(streamType) >= AUDIO_STREAM_CNT) {
+ ALOGE("Invalid stream type %d", streamType);
+ return BAD_VALUE;
+ }
+ mStreamType = streamType;
+ status_t status;
if (sampleRate == 0) {
- uint32_t afSampleRate;
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
- return NO_INIT;
+ status = AudioSystem::getOutputSamplingRate(&sampleRate, streamType);
+ if (status != NO_ERROR) {
+ ALOGE("Could not get output sample rate for stream type %d; status %d",
+ streamType, status);
+ return status;
}
- sampleRate = afSampleRate;
}
mSampleRate = sampleRate;
@@ -250,13 +270,16 @@ status_t AudioTrack::set(
if (format == AUDIO_FORMAT_DEFAULT) {
format = AUDIO_FORMAT_PCM_16_BIT;
}
- if (channelMask == 0) {
- channelMask = AUDIO_CHANNEL_OUT_STEREO;
- }
// validate parameters
if (!audio_is_valid_format(format)) {
- ALOGE("Invalid format %d", format);
+ ALOGE("Invalid format %#x", format);
+ return BAD_VALUE;
+ }
+ mFormat = format;
+
+ if (!audio_is_output_channel(channelMask)) {
+ ALOGE("Invalid channel mask %#x", channelMask);
return BAD_VALUE;
}
@@ -282,10 +305,6 @@ status_t AudioTrack::set(
flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
}
- if (!audio_is_output_channel(channelMask)) {
- ALOGE("Invalid channel mask %#x", channelMask);
- return BAD_VALUE;
- }
mChannelMask = channelMask;
uint32_t channelCount = popcount(channelMask);
mChannelCount = channelCount;
@@ -298,21 +317,20 @@ status_t AudioTrack::set(
mFrameSizeAF = sizeof(uint8_t);
}
- audio_io_handle_t output = AudioSystem::getOutput(
- streamType,
- sampleRate, format, channelMask,
- flags,
- offloadInfo);
-
- if (output == 0) {
- ALOGE("Could not get audio output for stream type %d", streamType);
- return BAD_VALUE;
+ // Make copy of input parameter offloadInfo so that in the future:
+ // (a) createTrack_l doesn't need it as an input parameter
+ // (b) we can support re-creation of offloaded tracks
+ if (offloadInfo != NULL) {
+ mOffloadInfoCopy = *offloadInfo;
+ mOffloadInfo = &mOffloadInfoCopy;
+ } else {
+ mOffloadInfo = NULL;
}
mVolume[LEFT] = 1.0f;
mVolume[RIGHT] = 1.0f;
mSendLevel = 0.0f;
- mFrameCount = frameCount;
+ // mFrameCount is initialized in createTrack_l
mReqFrameCount = frameCount;
mNotificationFramesReq = notificationFrames;
mNotificationFramesAct = 0;
@@ -332,14 +350,7 @@ status_t AudioTrack::set(
}
// create the IAudioTrack
- status_t status = createTrack_l(streamType,
- sampleRate,
- format,
- frameCount,
- flags,
- sharedBuffer,
- output,
- 0 /*epoch*/);
+ status = createTrack_l(0 /*epoch*/);
if (status != NO_ERROR) {
if (mAudioTrackThread != 0) {
@@ -347,17 +358,20 @@ status_t AudioTrack::set(
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
+ // Use of direct and offloaded output streams is ref counted by audio policy manager.
+#if 0 // FIXME This should no longer be needed
//Use of direct and offloaded output streams is ref counted by audio policy manager.
// As getOutput was called above and resulted in an output stream to be opened,
// we need to release it.
- AudioSystem::releaseOutput(output);
+ if (mOutput != 0) {
+ AudioSystem::releaseOutput(mOutput);
+ mOutput = 0;
+ }
+#endif
return status;
}
mStatus = NO_ERROR;
- mStreamType = streamType;
- mFormat = format;
- mSharedBuffer = sharedBuffer;
mState = STATE_STOPPED;
mUserData = user;
mLoopPeriod = 0;
@@ -369,7 +383,6 @@ status_t AudioTrack::set(
mSequence = 1;
mObservedSequence = mSequence;
mInUnderrun = false;
- mOutput = output;
return NO_ERROR;
}
@@ -445,12 +458,11 @@ status_t AudioTrack::start()
void AudioTrack::stop()
{
AutoMutex lock(mLock);
- // FIXME pause then stop should not be a nop
- if (mState != STATE_ACTIVE) {
+ if (mState != STATE_ACTIVE && mState != STATE_PAUSED) {
return;
}
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
mState = STATE_STOPPING;
} else {
mState = STATE_STOPPED;
@@ -472,7 +484,7 @@ void AudioTrack::stop()
sp<AudioTrackThread> t = mAudioTrackThread;
if (t != 0) {
- if (!isOffloaded()) {
+ if (!isOffloaded_l()) {
t->pause();
}
} else {
@@ -510,7 +522,7 @@ void AudioTrack::flush_l()
mRefreshRemaining = true;
mState = STATE_FLUSHED;
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
mProxy->interrupt();
}
mProxy->flush();
@@ -543,7 +555,7 @@ status_t AudioTrack::setVolume(float left, float right)
mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
mAudioTrack->signal();
}
return NO_ERROR;
@@ -607,7 +619,7 @@ uint32_t AudioTrack::getSampleRate() const
// sample rate can be updated during playback by the offloaded decoder so we need to
// query the HAL and update if needed.
// FIXME use Proxy return channel to update the rate from server and avoid polling here
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
if (mOutput != 0) {
uint32_t sampleRate = 0;
status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate);
@@ -691,6 +703,7 @@ status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod)
AutoMutex lock(mLock);
mNewPosition = mProxy->getPosition() + updatePeriod;
mUpdatePeriod = updatePeriod;
+
return NO_ERROR;
}
@@ -744,7 +757,7 @@ status_t AudioTrack::getPosition(uint32_t *position) const
}
AutoMutex lock(mLock);
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
uint32_t dspFrames = 0;
if (mOutput != 0) {
@@ -793,23 +806,12 @@ status_t AudioTrack::reload()
return NO_ERROR;
}
-audio_io_handle_t AudioTrack::getOutput()
+audio_io_handle_t AudioTrack::getOutput() const
{
AutoMutex lock(mLock);
return mOutput;
}
-// must be called with mLock held
-audio_io_handle_t AudioTrack::getOutput_l()
-{
- if (mOutput) {
- return mOutput;
- } else {
- return AudioSystem::getOutput(mStreamType,
- mSampleRate, mFormat, mChannelMask, mFlags);
- }
-}
-
status_t AudioTrack::attachAuxEffect(int effectId)
{
AutoMutex lock(mLock);
@@ -823,15 +825,7 @@ status_t AudioTrack::attachAuxEffect(int effectId)
// -------------------------------------------------------------------------
// must be called with mLock held
-status_t AudioTrack::createTrack_l(
- audio_stream_type_t streamType,
- uint32_t sampleRate,
- audio_format_t format,
- size_t frameCount,
- audio_output_flags_t flags,
- const sp<IMemory>& sharedBuffer,
- audio_io_handle_t output,
- size_t epoch)
+status_t AudioTrack::createTrack_l(size_t epoch)
{
status_t status;
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -840,41 +834,52 @@ status_t AudioTrack::createTrack_l(
return NO_INIT;
}
+ audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat,
+ mChannelMask, mFlags, mOffloadInfo);
+ if (output == 0) {
+ ALOGE("Could not get audio output for stream type %d, sample rate %u, format %#x, "
+ "channel mask %#x, flags %#x",
+ mStreamType, mSampleRate, mFormat, mChannelMask, mFlags);
+ return BAD_VALUE;
+ }
+ {
+ // 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.
+
// Not all of these values are needed under all conditions, but it is easier to get them all
uint32_t afLatency;
- status = AudioSystem::getLatency(output, streamType, &afLatency);
+ status = AudioSystem::getLatency(output, mStreamType, &afLatency);
if (status != NO_ERROR) {
ALOGE("getLatency(%d) failed status %d", output, status);
- return NO_INIT;
+ goto release;
}
size_t afFrameCount;
- status = AudioSystem::getFrameCount(output, streamType, &afFrameCount);
+ status = AudioSystem::getFrameCount(output, mStreamType, &afFrameCount);
if (status != NO_ERROR) {
- ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status);
- return NO_INIT;
+ ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, mStreamType, status);
+ goto release;
}
uint32_t afSampleRate;
- status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate);
+ status = AudioSystem::getSamplingRate(output, mStreamType, &afSampleRate);
if (status != NO_ERROR) {
- ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType, status);
- return NO_INIT;
+ ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, mStreamType, status);
+ goto release;
}
// Client decides whether the track is TIMED (see below), but can only express a preference
// for FAST. Server will perform additional tests.
- if ((flags & AUDIO_OUTPUT_FLAG_FAST) && !(
+ if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !(
// either of these use cases:
// use case 1: shared buffer
- (sharedBuffer != 0) ||
+ (mSharedBuffer != 0) ||
// use case 2: callback handler
(mCbf != NULL))) {
ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client");
// once denied, do not request again if IAudioTrack is re-created
- flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
- mFlags = flags;
+ mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
}
ALOGV("createTrack_l() output %d afLatency %d", output, afLatency);
@@ -885,43 +890,45 @@ status_t AudioTrack::createTrack_l(
// n = 3 normal track, with sample rate conversion
// (pessimistic; some non-1:1 conversion ratios don't actually need triple-buffering)
// n > 3 very high latency or very small notification interval; nBuffering is ignored
- const uint32_t nBuffering = (sampleRate == afSampleRate) ? 2 : 3;
+ const uint32_t nBuffering = (mSampleRate == afSampleRate) ? 2 : 3;
mNotificationFramesAct = mNotificationFramesReq;
- if (!audio_is_linear_pcm(format)) {
+ size_t frameCount = mReqFrameCount;
+ if (!audio_is_linear_pcm(mFormat)) {
- if (sharedBuffer != 0) {
+ if (mSharedBuffer != 0) {
// Same comment as below about ignoring frameCount parameter for set()
- frameCount = sharedBuffer->size();
+ frameCount = mSharedBuffer->size();
} else if (frameCount == 0) {
frameCount = afFrameCount;
}
if (mNotificationFramesAct != frameCount) {
mNotificationFramesAct = frameCount;
}
- } else if (sharedBuffer != 0) {
+ } else if (mSharedBuffer != 0) {
// Ensure that buffer alignment matches channel count
// 8-bit data in shared memory is not currently supported by AudioFlinger
- size_t alignment = /* format == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2;
+ size_t alignment = /* mFormat == AUDIO_FORMAT_PCM_8_BIT ? 1 : */ 2;
if (mChannelCount > 1) {
// More than 2 channels does not require stronger alignment than stereo
alignment <<= 1;
}
- if (((size_t)sharedBuffer->pointer() & (alignment - 1)) != 0) {
+ if (((size_t)mSharedBuffer->pointer() & (alignment - 1)) != 0) {
ALOGE("Invalid buffer alignment: address %p, channel count %u",
- sharedBuffer->pointer(), mChannelCount);
- return BAD_VALUE;
+ mSharedBuffer->pointer(), mChannelCount);
+ status = BAD_VALUE;
+ goto release;
}
// When initializing a shared buffer AudioTrack via constructors,
// there's no frameCount parameter.
// But when initializing a shared buffer AudioTrack via set(),
// there _is_ a frameCount parameter. We silently ignore it.
- frameCount = sharedBuffer->size()/mChannelCount/sizeof(int16_t);
+ frameCount = mSharedBuffer->size()/mChannelCount/sizeof(int16_t);
- } else if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) {
+ } else if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
// FIXME move these calculations and associated checks to server
@@ -933,10 +940,10 @@ status_t AudioTrack::createTrack_l(
minBufCount = nBuffering;
}
- size_t minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate;
+ size_t minFrameCount = (afFrameCount*mSampleRate*minBufCount)/afSampleRate;
ALOGV("minFrameCount: %u, afFrameCount=%d, minBufCount=%d, sampleRate=%u, afSampleRate=%u"
", afLatency=%d",
- minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency);
+ minFrameCount, afFrameCount, minBufCount, mSampleRate, afSampleRate, afLatency);
if (frameCount == 0) {
frameCount = minFrameCount;
@@ -961,26 +968,28 @@ status_t AudioTrack::createTrack_l(
}
pid_t tid = -1;
- if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
trackFlags |= IAudioFlinger::TRACK_FAST;
if (mAudioTrackThread != 0) {
tid = mAudioTrackThread->getTid();
}
}
- if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
trackFlags |= IAudioFlinger::TRACK_OFFLOAD;
}
- sp<IAudioTrack> track = audioFlinger->createTrack(streamType,
- sampleRate,
+ size_t temp = frameCount; // temp may be replaced by a revised value of frameCount,
+ // but we will still need the original value also
+ sp<IAudioTrack> track = audioFlinger->createTrack(mStreamType,
+ mSampleRate,
// AudioFlinger only sees 16-bit PCM
- format == AUDIO_FORMAT_PCM_8_BIT ?
- AUDIO_FORMAT_PCM_16_BIT : format,
+ mFormat == AUDIO_FORMAT_PCM_8_BIT ?
+ AUDIO_FORMAT_PCM_16_BIT : mFormat,
mChannelMask,
- frameCount,
+ &temp,
&trackFlags,
- sharedBuffer,
+ mSharedBuffer,
output,
tid,
&mSessionId,
@@ -990,13 +999,21 @@ status_t AudioTrack::createTrack_l(
if (track == 0) {
ALOGE("AudioFlinger could not create track, status: %d", status);
- return status;
+ goto release;
}
+ // AudioFlinger now owns the reference to the I/O handle,
+ // so we are no longer responsible for releasing it.
+
sp<IMemory> iMem = track->getCblk();
if (iMem == 0) {
ALOGE("Could not get control block");
return NO_INIT;
}
+ void *iMemPointer = iMem->pointer();
+ if (iMemPointer == NULL) {
+ ALOGE("Could not get control block pointer");
+ return NO_INIT;
+ }
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
@@ -1004,9 +1021,9 @@ status_t AudioTrack::createTrack_l(
}
mAudioTrack = track;
mCblkMemory = iMem;
- audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMem->pointer());
+ audio_track_cblk_t* cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
mCblk = cblk;
- size_t temp = cblk->frameCount_;
+ // note that temp is the (possibly revised) value of frameCount
if (temp < frameCount || (frameCount == 0 && temp == 0)) {
// In current design, AudioTrack client checks and ensures frame count validity before
// passing it to AudioFlinger so AudioFlinger should not return a different value except
@@ -1015,11 +1032,11 @@ status_t AudioTrack::createTrack_l(
}
frameCount = temp;
mAwaitBoost = false;
- if (flags & AUDIO_OUTPUT_FLAG_FAST) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
if (trackFlags & IAudioFlinger::TRACK_FAST) {
ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", frameCount);
mAwaitBoost = true;
- if (sharedBuffer == 0) {
+ if (mSharedBuffer == 0) {
// Theoretically double-buffering is not required for fast tracks,
// due to tighter scheduling. But in practice, to accommodate kernels with
// scheduling jitter, and apps with computation jitter, we use double-buffering.
@@ -1030,26 +1047,27 @@ status_t AudioTrack::createTrack_l(
} else {
ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", frameCount);
// once denied, do not request again if IAudioTrack is re-created
- flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST);
- mFlags = flags;
- if (sharedBuffer == 0) {
+ mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
+ if (mSharedBuffer == 0) {
if (mNotificationFramesAct == 0 || mNotificationFramesAct > frameCount/nBuffering) {
mNotificationFramesAct = frameCount/nBuffering;
}
}
}
}
- if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
if (trackFlags & IAudioFlinger::TRACK_OFFLOAD) {
ALOGV("AUDIO_OUTPUT_FLAG_OFFLOAD successful");
} else {
ALOGW("AUDIO_OUTPUT_FLAG_OFFLOAD denied by server");
- flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
- mFlags = flags;
- return NO_INIT;
+ mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+ // FIXME This is a warning, not an error, so don't return error status
+ //return NO_INIT;
}
}
+ // We retain a copy of the I/O handle, but don't own the reference
+ mOutput = output;
mRefreshRemaining = true;
// Starting address of buffers in shared memory. If there is a shared buffer, buffers
@@ -1057,15 +1075,15 @@ status_t AudioTrack::createTrack_l(
// immediately after the control block. This address is for the mapping within client
// address space. AudioFlinger::TrackBase::mBuffer is for the server address space.
void* buffers;
- if (sharedBuffer == 0) {
+ if (mSharedBuffer == 0) {
buffers = (char*)cblk + sizeof(audio_track_cblk_t);
} else {
- buffers = sharedBuffer->pointer();
+ buffers = mSharedBuffer->pointer();
}
mAudioTrack->attachAuxEffect(mAuxEffectId);
// FIXME don't believe this lie
- mLatency = afLatency + (1000*frameCount) / sampleRate;
+ mLatency = afLatency + (1000*frameCount) / mSampleRate;
mFrameCount = frameCount;
// If IAudioTrack is re-created, don't let the requested frameCount
// decrease. This can confuse clients that cache frameCount().
@@ -1074,7 +1092,7 @@ status_t AudioTrack::createTrack_l(
}
// update proxy
- if (sharedBuffer == 0) {
+ if (mSharedBuffer == 0) {
mStaticProxy.clear();
mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
} else {
@@ -1092,6 +1110,14 @@ status_t AudioTrack::createTrack_l(
mAudioTrack->asBinder()->linkToDeath(mDeathNotifier, this);
return NO_ERROR;
+ }
+
+release:
+ AudioSystem::releaseOutput(output);
+ if (status == NO_ERROR) {
+ status = NO_INIT;
+ }
+ return status;
}
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
@@ -1107,13 +1133,13 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
}
const struct timespec *requested;
+ struct timespec timeout;
if (waitCount == -1) {
requested = &ClientProxy::kForever;
} else if (waitCount == 0) {
requested = &ClientProxy::kNonBlocking;
} else if (waitCount > 0) {
long long ms = WAIT_PERIOD_MS * (long long) waitCount;
- struct timespec timeout;
timeout.tv_sec = ms / 1000;
timeout.tv_nsec = (int) (ms % 1000) * 1000000;
requested = &timeout;
@@ -1344,7 +1370,7 @@ status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform,
// -------------------------------------------------------------------------
-nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
+nsecs_t AudioTrack::processAudioBuffer()
{
// Currently the AudioTrack thread is not created if there are no callbacks.
// Would it ever make sense to run the thread, even without callbacks?
@@ -1382,7 +1408,7 @@ nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
// for offloaded tracks restoreTrack_l() will just update the sequence and clear
// AudioSystem cache. We should not exit here but after calling the callback so
// that the upper layers can recreate the track
- if (!isOffloaded() || (mSequence == mObservedSequence)) {
+ if (!isOffloaded_l() || (mSequence == mObservedSequence)) {
status_t status = restoreTrack_l("processAudioBuffer");
mLock.unlock();
// Run again immediately, but with a new IAudioTrack
@@ -1603,7 +1629,6 @@ nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
size_t reqSize = audioBuffer.size;
mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
size_t writtenSize = audioBuffer.size;
- size_t writtenFrames = writtenSize / mFrameSize;
// Sanity check on returned size
if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
@@ -1669,22 +1694,19 @@ nsecs_t AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
status_t AudioTrack::restoreTrack_l(const char *from)
{
ALOGW("dead IAudioTrack, %s, creating a new one from %s()",
- isOffloaded() ? "Offloaded" : "PCM", from);
+ isOffloaded_l() ? "Offloaded" : "PCM", from);
++mSequence;
status_t result;
// refresh the audio configuration cache in this process to make sure we get new
- // output parameters in getOutput_l() and createTrack_l()
+ // output parameters in createTrack_l()
AudioSystem::clearAudioConfigCache();
- if (isOffloaded()) {
+ if (isOffloaded_l()) {
+ // FIXME re-creation of offloaded tracks is not yet implemented
return DEAD_OBJECT;
}
- // force new output query from audio policy manager;
- mOutput = 0;
- audio_io_handle_t output = getOutput_l();
-
// if the new IAudioTrack is created, createTrack_l() will modify the
// following member variables: mAudioTrack, mCblkMemory and mCblk.
// It will also delete the strong references on previous IAudioTrack and IMemory
@@ -1692,14 +1714,7 @@ status_t AudioTrack::restoreTrack_l(const char *from)
// take the frames that will be lost by track recreation into account in saved position
size_t position = mProxy->getPosition() + mProxy->getFramesFilled();
size_t bufferPosition = mStaticProxy != NULL ? mStaticProxy->getBufferPosition() : 0;
- result = createTrack_l(mStreamType,
- mSampleRate,
- mFormat,
- mReqFrameCount, // so that frame count never goes down
- mFlags,
- mSharedBuffer,
- output,
- position /*epoch*/);
+ result = createTrack_l(position /*epoch*/);
if (result == NO_ERROR) {
// continue playback from last known position, but
@@ -1727,10 +1742,16 @@ status_t AudioTrack::restoreTrack_l(const char *from)
}
}
if (result != NO_ERROR) {
+ // Use of direct and offloaded output streams is ref counted by audio policy manager.
+#if 0 // FIXME This should no longer be needed
//Use of direct and offloaded output streams is ref counted by audio policy manager.
// As getOutput was called above and resulted in an output stream to be opened,
// we need to release it.
- AudioSystem::releaseOutput(output);
+ if (mOutput != 0) {
+ AudioSystem::releaseOutput(mOutput);
+ mOutput = 0;
+ }
+#endif
ALOGW("restoreTrack_l() failed status %d", result);
mState = STATE_STOPPED;
}
@@ -1763,14 +1784,21 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
String8 AudioTrack::getParameters(const String8& keys)
{
- if (mOutput) {
- return AudioSystem::getParameters(mOutput, keys);
+ audio_io_handle_t output = getOutput();
+ if (output != 0) {
+ return AudioSystem::getParameters(output, keys);
} else {
return String8::empty();
}
}
-status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
+bool AudioTrack::isOffloaded() const
+{
+ AutoMutex lock(mLock);
+ return isOffloaded_l();
+}
+
+status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const
{
const size_t SIZE = 256;
@@ -1800,7 +1828,7 @@ uint32_t AudioTrack::getUnderrunFrames() const
// =========================================================================
-void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who)
+void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
{
sp<AudioTrack> audioTrack = mAudioTrack.promote();
if (audioTrack != 0) {
@@ -1844,7 +1872,7 @@ bool AudioTrack::AudioTrackThread::threadLoop()
return true;
}
}
- nsecs_t ns = mReceiver.processAudioBuffer(this);
+ nsecs_t ns = mReceiver.processAudioBuffer();
switch (ns) {
case 0:
return true;
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index caa7900..fdd1a12 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -26,7 +26,7 @@ extern "C" {
namespace android {
audio_track_cblk_t::audio_track_cblk_t()
- : mServer(0), frameCount_(0), mFutex(0), mMinimum(0),
+ : mServer(0), mFutex(0), mMinimum(0),
mVolumeLR(0x10001000), mSampleRate(0), mSendLevel(0), mFlags(0)
{
memset(&u, 0, sizeof(u));
@@ -475,9 +475,14 @@ void StaticAudioTrackClientProxy::flush()
void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount)
{
+ // This can only happen on a 64-bit client
+ if (loopStart > UINT32_MAX || loopEnd > UINT32_MAX) {
+ // FIXME Should return an error status
+ return;
+ }
StaticAudioTrackState newState;
- newState.mLoopStart = loopStart;
- newState.mLoopEnd = loopEnd;
+ newState.mLoopStart = (uint32_t) loopStart;
+ newState.mLoopEnd = (uint32_t) loopEnd;
newState.mLoopCount = loopCount;
mBufferPosition = loopStart;
(void) mMutator.push(newState);
@@ -487,7 +492,7 @@ size_t StaticAudioTrackClientProxy::getBufferPosition()
{
size_t bufferPosition;
if (mMutator.ack()) {
- bufferPosition = mCblk->u.mStatic.mBufferPosition;
+ bufferPosition = (size_t) mCblk->u.mStatic.mBufferPosition;
if (bufferPosition > mFrameCount) {
bufferPosition = mFrameCount;
}
@@ -622,7 +627,7 @@ void ServerProxy::releaseBuffer(Buffer* buffer)
if (half == 0) {
half = 1;
}
- size_t minimum = cblk->mMinimum;
+ size_t minimum = (size_t) cblk->mMinimum;
if (minimum == 0) {
minimum = mIsOut ? half : 1;
} else if (minimum > half) {
@@ -760,12 +765,13 @@ ssize_t StaticAudioTrackServerProxy::pollPosition()
mIsShutdown = true;
return (ssize_t) NO_INIT;
}
- mCblk->u.mStatic.mBufferPosition = position;
+ // This may overflow, but client is not supposed to rely on it
+ mCblk->u.mStatic.mBufferPosition = (uint32_t) position;
}
return (ssize_t) position;
}
-status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
+status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush __unused)
{
if (mIsShutdown) {
buffer->mFrameCount = 0;
@@ -836,7 +842,8 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
mPosition = newPosition;
cblk->mServer += stepCount;
- cblk->u.mStatic.mBufferPosition = newPosition;
+ // This may overflow, but client is not supposed to rely on it
+ cblk->u.mStatic.mBufferPosition = (uint32_t) newPosition;
if (setFlags != 0) {
(void) android_atomic_or(setFlags, &cblk->mFlags);
// this would be a good place to wake a futex
@@ -847,7 +854,7 @@ void StaticAudioTrackServerProxy::releaseBuffer(Buffer* buffer)
buffer->mNonContig = 0;
}
-void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
+void StaticAudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount __unused)
{
// Unlike AudioTrackServerProxy::tallyUnderrunFrames() used for streaming tracks,
// we don't have a location to count underrun frames. The underrun frame counter
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
new file mode 100644
index 0000000..eb091ac
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -0,0 +1,364 @@
+/*
+ * 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 "CharacterEncodingDector"
+#include <utils/Log.h>
+
+#include "CharacterEncodingDetector.h"
+#include "CharacterEncodingDetectorTables.h"
+
+#include "utils/Vector.h"
+#include "StringArray.h"
+
+#include "unicode/ucnv.h"
+#include "unicode/ucsdet.h"
+#include "unicode/ustring.h"
+
+namespace android {
+
+CharacterEncodingDetector::CharacterEncodingDetector() {
+
+ UErrorCode status = U_ZERO_ERROR;
+ mUtf8Conv = ucnv_open("UTF-8", &status);
+ if (U_FAILURE(status)) {
+ ALOGE("could not create UConverter for UTF-8");
+ mUtf8Conv = NULL;
+ }
+}
+
+CharacterEncodingDetector::~CharacterEncodingDetector() {
+ ucnv_close(mUtf8Conv);
+}
+
+void CharacterEncodingDetector::addTag(const char *name, const char *value) {
+ mNames.push_back(name);
+ mValues.push_back(value);
+}
+
+size_t CharacterEncodingDetector::size() {
+ return mNames.size();
+}
+
+status_t CharacterEncodingDetector::getTag(int index, const char **name, const char**value) {
+ if (index >= mNames.size()) {
+ return BAD_VALUE;
+ }
+
+ *name = mNames.getEntry(index);
+ *value = mValues.getEntry(index);
+ return OK;
+}
+
+static bool isPrintableAscii(const char *value, size_t len) {
+ for (size_t i = 0; i < len; i++) {
+ if ((value[i] & 0x80) || value[i] < 0x20 || value[i] == 0x7f) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void CharacterEncodingDetector::detectAndConvert() {
+
+ int size = mNames.size();
+ ALOGV("%d tags before conversion", size);
+ for (int i = 0; i < size; i++) {
+ ALOGV("%s: %s", mNames.getEntry(i), mValues.getEntry(i));
+ }
+
+ if (size && mUtf8Conv) {
+
+ UErrorCode status = U_ZERO_ERROR;
+ UCharsetDetector *csd = ucsdet_open(&status);
+ const UCharsetMatch *ucm;
+
+ // try combined detection of artist/album/title etc.
+ char buf[1024];
+ buf[0] = 0;
+ int idx;
+ for (int i = 0; i < size; i++) {
+ const char *name = mNames.getEntry(i);
+ const char *value = mValues.getEntry(i);
+ if (!isPrintableAscii(value, strlen(value)) && (
+ !strcmp(name, "artist") ||
+ !strcmp(name, "albumartist") ||
+ !strcmp(name, "composer") ||
+ !strcmp(name, "genre") ||
+ !strcmp(name, "album") ||
+ !strcmp(name, "title"))) {
+ strlcat(buf, value, sizeof(buf));
+ // separate tags by space so ICU's ngram detector can do its job
+ strlcat(buf, " ", sizeof(buf));
+ }
+ }
+ ucsdet_setText(csd, buf, strlen(buf), &status);
+
+ int32_t matches;
+ const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
+ const char *combinedenc = "???";
+
+ const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf), ucma, matches);
+
+ if (bestCombinedMatch != NULL) {
+ combinedenc = ucsdet_getName(bestCombinedMatch, &status);
+ }
+
+ for (int i = 0; i < size; i++) {
+ const char *name = mNames.getEntry(i);
+ uint8_t* src = (uint8_t *)mValues.getEntry(i);
+ int len = strlen((char *)src);
+ uint8_t* dest = src;
+
+ ALOGV("@@@ checking %s", name);
+ const char *s = mValues.getEntry(i);
+ int32_t inputLength = strlen(s);
+ const char *enc;
+
+ if (!strcmp(name, "artist") ||
+ !strcmp(name, "albumartist") ||
+ !strcmp(name, "composer") ||
+ !strcmp(name, "genre") ||
+ !strcmp(name, "album") ||
+ !strcmp(name, "title")) {
+ // use encoding determined from the combination of artist/album/title etc.
+ enc = combinedenc;
+ } else {
+ ucsdet_setText(csd, s, inputLength, &status);
+ ucm = ucsdet_detect(csd, &status);
+ if (!ucm) {
+ mValues.setEntry(i, "???");
+ continue;
+ }
+ enc = ucsdet_getName(ucm, &status);
+ ALOGV("@@@@ recognized charset: %s for %s confidence %d",
+ enc, mNames.getEntry(i), ucsdet_getConfidence(ucm, &status));
+ }
+
+ if (strcmp(enc,"UTF-8") != 0) {
+ // only convert if the source encoding isn't already UTF-8
+ ALOGV("@@@ using converter %s for %s", enc, mNames.getEntry(i));
+ UConverter *conv = ucnv_open(enc, &status);
+ if (U_FAILURE(status)) {
+ ALOGE("could not create UConverter for %s", enc);
+ continue;
+ }
+
+ // convert from native encoding to UTF-8
+ const char* source = mValues.getEntry(i);
+ int targetLength = len * 3 + 1;
+ char* buffer = new char[targetLength];
+ // don't normally check for NULL, but in this case targetLength may be large
+ if (!buffer)
+ break;
+ char* target = buffer;
+
+ ucnv_convertEx(mUtf8Conv, conv, &target, target + targetLength,
+ &source, source + strlen(source),
+ NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
+
+ if (U_FAILURE(status)) {
+ ALOGE("ucnv_convertEx failed: %d", status);
+ mValues.setEntry(i, "???");
+ } else {
+ // zero terminate
+ *target = 0;
+ mValues.setEntry(i, buffer);
+ }
+
+ delete[] buffer;
+
+ ucnv_close(conv);
+ }
+ }
+
+ for (int i = size - 1; i >= 0; --i) {
+ if (strlen(mValues.getEntry(i)) == 0) {
+ ALOGV("erasing %s because entry is empty", mNames.getEntry(i));
+ mNames.erase(i);
+ mValues.erase(i);
+ }
+ }
+
+ ucsdet_close(csd);
+ }
+}
+
+/*
+ * When ICU detects multiple encoding matches, apply additional heuristics to determine
+ * which one is the best match, since ICU can't always be trusted to make the right choice.
+ *
+ * What this method does is:
+ * - decode the input using each of the matches found
+ * - recalculate the starting confidence level for multibyte encodings using a different
+ * algorithm and larger frequent character lists than ICU
+ * - devalue encoding where the conversion contains unlikely characters (symbols, reserved, etc)
+ * - pick the highest match
+ */
+const UCharsetMatch *CharacterEncodingDetector::getPreferred(
+ const char *input, size_t len, const UCharsetMatch** ucma, size_t nummatches) {
+
+ Vector<const UCharsetMatch*> matches;
+ UErrorCode status = U_ZERO_ERROR;
+
+ ALOGV("%d matches", nummatches);
+ for (size_t i = 0; i < nummatches; i++) {
+ const char *encname = ucsdet_getName(ucma[i], &status);
+ int confidence = ucsdet_getConfidence(ucma[i], &status);
+ ALOGV("%d: %s %d", i, encname, confidence);
+ matches.push_back(ucma[i]);
+ }
+
+ size_t num = matches.size();
+ if (num == 0) {
+ return NULL;
+ }
+ if (num == 1) {
+ return matches[0];
+ }
+
+ ALOGV("considering %d matches", num);
+
+ // keep track of how many "special" characters result when converting the input using each
+ // encoding
+ Vector<int> newconfidence;
+ for (size_t i = 0; i < num; i++) {
+ const uint16_t *freqdata = NULL;
+ float freqcoverage = 0;
+ status = U_ZERO_ERROR;
+ const char *encname = ucsdet_getName(matches[i], &status);
+ int confidence = ucsdet_getConfidence(matches[i], &status);
+ if (!strcmp("GB18030", encname)) {
+ freqdata = frequent_zhCN;
+ freqcoverage = frequent_zhCN_coverage;
+ } else if (!strcmp("Big5", encname)) {
+ freqdata = frequent_zhTW;
+ freqcoverage = frequent_zhTW_coverage;
+ } else if (!strcmp("EUC-KR", encname)) {
+ freqdata = frequent_ko;
+ freqcoverage = frequent_ko_coverage;
+ } else if (!strcmp("EUC-JP", encname)) {
+ freqdata = frequent_ja;
+ freqcoverage = frequent_ja_coverage;
+ } else if (!strcmp("Shift_JIS", encname)) {
+ freqdata = frequent_ja;
+ freqcoverage = frequent_ja_coverage;
+ }
+
+ ALOGV("%d: %s %d", i, encname, confidence);
+ UConverter *conv = ucnv_open(encname, &status);
+ const char *source = input;
+ const char *sourceLimit = input + len;
+ status = U_ZERO_ERROR;
+ int demerit = 0;
+ int frequentchars = 0;
+ int totalchars = 0;
+ while (true) {
+ // demerit the current encoding for each "special" character found after conversion.
+ // The amount of demerit is somewhat arbitrarily chosen.
+ int inchar;
+ if (source != sourceLimit) {
+ inchar = (source[0] << 8) + source[1];
+ }
+ UChar32 c = ucnv_getNextUChar(conv, &source, sourceLimit, &status);
+ if (!U_SUCCESS(status)) {
+ break;
+ }
+ if (c < 0x20 || (c >= 0x7f && c <= 0x009f)) {
+ ALOGV("control character %x", c);
+ demerit += 100;
+ } else if ((c >= 0xa0 && c <= 0xbe) // symbols, superscripts
+ || (c == 0xd7) || (c == 0xf7) // multiplication and division signs
+ || (c >= 0x2000 && c <= 0x209f)) { // punctuation, superscripts
+ ALOGV("unlikely character %x", c);
+ demerit += 10;
+ } else if (c >= 0xe000 && c <= 0xf8ff) {
+ ALOGV("private use character %x", c);
+ demerit += 30;
+ } else if (c >= 0x2190 && c <= 0x2bff) {
+ // this range comprises various symbol ranges that are unlikely to appear in
+ // music file metadata.
+ ALOGV("symbol %x", c);
+ demerit += 10;
+ } else if (c == 0xfffd) {
+ ALOGV("replacement character");
+ demerit += 50;
+ } else if (c >= 0xfff0 && c <= 0xfffc) {
+ ALOGV("unicode special %x", c);
+ demerit += 50;
+ } else if (freqdata != NULL) {
+ totalchars++;
+ if (isFrequent(freqdata, c)) {
+ frequentchars++;
+ }
+ }
+ }
+ if (freqdata != NULL && totalchars != 0) {
+ int myconfidence = 10 + float((100 * frequentchars) / totalchars) / freqcoverage;
+ ALOGV("ICU confidence: %d, my confidence: %d (%d %d)", confidence, myconfidence,
+ totalchars, frequentchars);
+ if (myconfidence > 100) myconfidence = 100;
+ if (myconfidence < 0) myconfidence = 0;
+ confidence = myconfidence;
+ }
+ ALOGV("%d-%d=%d", confidence, demerit, confidence - demerit);
+ newconfidence.push_back(confidence - demerit);
+ ucnv_close(conv);
+ if (i == 0 && (confidence - demerit) == 100) {
+ // no need to check any further, we'll end up using this match anyway
+ break;
+ }
+ }
+
+ // find match with highest confidence after adjusting for unlikely characters
+ int highest = newconfidence[0];
+ size_t highestidx = 0;
+ num = newconfidence.size();
+ for (size_t i = 1; i < num; i++) {
+ if (newconfidence[i] > highest) {
+ highest = newconfidence[i];
+ highestidx = i;
+ }
+ }
+ status = U_ZERO_ERROR;
+ ALOGV("selecting '%s' w/ %d confidence", ucsdet_getName(matches[highestidx], &status), highest);
+ return matches[highestidx];
+}
+
+
+bool CharacterEncodingDetector::isFrequent(const uint16_t *values, uint32_t c) {
+
+ int start = 0;
+ int end = 511; // All the tables have 512 entries
+ int mid = (start+end)/2;
+
+ while(start <= end) {
+ if(c == values[mid]) {
+ return true;
+ } else if (c > values[mid]) {
+ start = mid + 1;
+ } else {
+ end = mid - 1;
+ }
+
+ mid = (start + end) / 2;
+ }
+
+ return false;
+}
+
+
+} // namespace android
diff --git a/media/libmedia/CharacterEncodingDetector.h b/media/libmedia/CharacterEncodingDetector.h
new file mode 100644
index 0000000..3655a91
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetector.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef _CHARACTER_ENCODING_DETECTOR_H
+#define _CHARACTER_ENCODING_DETECTOR_H
+
+#include <media/mediascanner.h>
+
+#include "StringArray.h"
+
+#include "unicode/ucnv.h"
+#include "unicode/ucsdet.h"
+#include "unicode/ustring.h"
+
+namespace android {
+
+class CharacterEncodingDetector {
+
+ public:
+ CharacterEncodingDetector();
+ ~CharacterEncodingDetector();
+
+ void addTag(const char *name, const char *value);
+ size_t size();
+
+ void detectAndConvert();
+ status_t getTag(int index, const char **name, const char**value);
+
+ private:
+ const UCharsetMatch *getPreferred(
+ const char *input, size_t len, const UCharsetMatch** ucma, size_t matches);
+
+ bool isFrequent(const uint16_t *values, uint32_t c);
+
+ // cached name and value strings, for native encoding support.
+ // TODO: replace these with byte blob arrays that don't require the data to be
+ // singlenullbyte-terminated
+ StringArray mNames;
+ StringArray mValues;
+
+ UConverter* mUtf8Conv;
+};
+
+
+
+}; // namespace android
+
+#endif
diff --git a/media/libmedia/CharacterEncodingDetectorTables.h b/media/libmedia/CharacterEncodingDetectorTables.h
new file mode 100644
index 0000000..1fe1137
--- /dev/null
+++ b/media/libmedia/CharacterEncodingDetectorTables.h
@@ -0,0 +1,2092 @@
+/*
+ * 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.
+ */
+
+// The 512 most frequently occuring characters for the zhCN language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_zhCN[] = {
+ 0x4E00, // 一, #2
+ 0x4E07, // 万, #306
+ 0x4E09, // 三, #138
+ 0x4E0A, // 上, #16
+ 0x4E0B, // 下, #25
+ 0x4E0D, // 不, #7
+ 0x4E0E, // 与, #133
+ 0x4E13, // 专, #151
+ 0x4E16, // 世, #346
+ 0x4E1A, // 业, #39
+ 0x4E1C, // 东, #197
+ 0x4E24, // 两, #376
+ 0x4E2A, // 个, #23
+ 0x4E2D, // 中, #4
+ 0x4E3A, // 为, #31
+ 0x4E3B, // 主, #95
+ 0x4E3E, // 举, #418
+ 0x4E48, // 么, #93
+ 0x4E4B, // 之, #131
+ 0x4E50, // 乐, #130
+ 0x4E5F, // 也, #145
+ 0x4E66, // 书, #283
+ 0x4E70, // 买, #483
+ 0x4E86, // 了, #13
+ 0x4E8B, // 事, #168
+ 0x4E8C, // 二, #218
+ 0x4E8E, // 于, #64
+ 0x4E94, // 五, #430
+ 0x4E9A, // 亚, #468
+ 0x4E9B, // 些, #366
+ 0x4EA4, // 交, #243
+ 0x4EA7, // 产, #86
+ 0x4EAB, // 享, #345
+ 0x4EAC, // 京, #206
+ 0x4EBA, // 人, #3
+ 0x4EC0, // 什, #287
+ 0x4ECB, // 介, #478
+ 0x4ECE, // 从, #381
+ 0x4ED6, // 他, #129
+ 0x4EE3, // 代, #241
+ 0x4EE5, // 以, #51
+ 0x4EEC, // 们, #83
+ 0x4EF6, // 件, #141
+ 0x4EF7, // 价, #140
+ 0x4EFB, // 任, #383
+ 0x4F01, // 企, #439
+ 0x4F18, // 优, #374
+ 0x4F1A, // 会, #29
+ 0x4F20, // 传, #222
+ 0x4F46, // 但, #451
+ 0x4F4D, // 位, #208
+ 0x4F53, // 体, #98
+ 0x4F55, // 何, #339
+ 0x4F5C, // 作, #44
+ 0x4F60, // 你, #76
+ 0x4F7F, // 使, #272
+ 0x4F9B, // 供, #375
+ 0x4FDD, // 保, #180
+ 0x4FE1, // 信, #84
+ 0x4FEE, // 修, #437
+ 0x503C, // 值, #450
+ 0x505A, // 做, #368
+ 0x5065, // 健, #484
+ 0x50CF, // 像, #487
+ 0x513F, // 儿, #326
+ 0x5143, // 元, #202
+ 0x5148, // 先, #485
+ 0x5149, // 光, #254
+ 0x514B, // 克, #503
+ 0x514D, // 免, #349
+ 0x5165, // 入, #156
+ 0x5168, // 全, #47
+ 0x516C, // 公, #35
+ 0x5171, // 共, #448
+ 0x5173, // 关, #49
+ 0x5176, // 其, #195
+ 0x5177, // 具, #329
+ 0x5185, // 内, #109
+ 0x518C, // 册, #225
+ 0x519B, // 军, #466
+ 0x51FA, // 出, #53
+ 0x51FB, // 击, #359
+ 0x5206, // 分, #22
+ 0x5217, // 列, #410
+ 0x521B, // 创, #399
+ 0x5229, // 利, #296
+ 0x522B, // 别, #372
+ 0x5230, // 到, #33
+ 0x5236, // 制, #192
+ 0x524D, // 前, #117
+ 0x529B, // 力, #173
+ 0x529E, // 办, #436
+ 0x529F, // 功, #455
+ 0x52A0, // 加, #97
+ 0x52A1, // 务, #100
+ 0x52A8, // 动, #46
+ 0x52A9, // 助, #365
+ 0x5305, // 包, #331
+ 0x5316, // 化, #155
+ 0x5317, // 北, #194
+ 0x533A, // 区, #105
+ 0x533B, // 医, #234
+ 0x5341, // 十, #294
+ 0x534E, // 华, #205
+ 0x5355, // 单, #259
+ 0x5357, // 南, #182
+ 0x535A, // 博, #153
+ 0x5361, // 卡, #332
+ 0x539F, // 原, #271
+ 0x53BB, // 去, #282
+ 0x53C2, // 参, #500
+ 0x53CA, // 及, #255
+ 0x53CB, // 友, #186
+ 0x53CD, // 反, #422
+ 0x53D1, // 发, #15
+ 0x53D7, // 受, #507
+ 0x53D8, // 变, #395
+ 0x53E3, // 口, #293
+ 0x53EA, // 只, #340
+ 0x53EF, // 可, #45
+ 0x53F0, // 台, #267
+ 0x53F7, // 号, #121
+ 0x53F8, // 司, #150
+ 0x5404, // 各, #491
+ 0x5408, // 合, #115
+ 0x540C, // 同, #189
+ 0x540D, // 名, #127
+ 0x540E, // 后, #75
+ 0x5411, // 向, #459
+ 0x5427, // 吧, #353
+ 0x544A, // 告, #318
+ 0x5458, // 员, #232
+ 0x5468, // 周, #347
+ 0x548C, // 和, #43
+ 0x54C1, // 品, #36
+ 0x5546, // 商, #148
+ 0x5668, // 器, #228
+ 0x56DB, // 四, #352
+ 0x56DE, // 回, #38
+ 0x56E0, // 因, #355
+ 0x56E2, // 团, #412
+ 0x56ED, // 园, #470
+ 0x56FD, // 国, #12
+ 0x56FE, // 图, #32
+ 0x5728, // 在, #10
+ 0x5730, // 地, #30
+ 0x573A, // 场, #177
+ 0x575B, // 坛, #364
+ 0x578B, // 型, #274
+ 0x57CE, // 城, #172
+ 0x57FA, // 基, #315
+ 0x58EB, // 士, #434
+ 0x58F0, // 声, #397
+ 0x5904, // 处, #416
+ 0x5907, // 备, #270
+ 0x590D, // 复, #122
+ 0x5916, // 外, #190
+ 0x591A, // 多, #40
+ 0x5927, // 大, #8
+ 0x5929, // 天, #52
+ 0x592A, // 太, #456
+ 0x5934, // 头, #258
+ 0x5973, // 女, #65
+ 0x597D, // 好, #62
+ 0x5982, // 如, #135
+ 0x5A31, // 娱, #452
+ 0x5B50, // 子, #37
+ 0x5B57, // 字, #285
+ 0x5B66, // 学, #19
+ 0x5B89, // 安, #144
+ 0x5B8C, // 完, #469
+ 0x5B9A, // 定, #179
+ 0x5B9D, // 宝, #188
+ 0x5B9E, // 实, #154
+ 0x5BA2, // 客, #174
+ 0x5BB6, // 家, #26
+ 0x5BB9, // 容, #307
+ 0x5BC6, // 密, #471
+ 0x5BF9, // 对, #90
+ 0x5BFC, // 导, #348
+ 0x5C06, // 将, #265
+ 0x5C0F, // 小, #28
+ 0x5C11, // 少, #379
+ 0x5C14, // 尔, #490
+ 0x5C31, // 就, #101
+ 0x5C55, // 展, #291
+ 0x5C71, // 山, #239
+ 0x5DDE, // 州, #227
+ 0x5DE5, // 工, #73
+ 0x5DF1, // 己, #480
+ 0x5DF2, // 已, #310
+ 0x5E02, // 市, #78
+ 0x5E03, // 布, #350
+ 0x5E08, // 师, #277
+ 0x5E16, // 帖, #396
+ 0x5E26, // 带, #449
+ 0x5E2E, // 帮, #461
+ 0x5E38, // 常, #319
+ 0x5E73, // 平, #217
+ 0x5E74, // 年, #20
+ 0x5E76, // 并, #440
+ 0x5E7F, // 广, #166
+ 0x5E93, // 库, #446
+ 0x5E94, // 应, #187
+ 0x5E97, // 店, #320
+ 0x5EA6, // 度, #114
+ 0x5EB7, // 康, #499
+ 0x5EFA, // 建, #211
+ 0x5F00, // 开, #72
+ 0x5F0F, // 式, #207
+ 0x5F15, // 引, #495
+ 0x5F20, // 张, #385
+ 0x5F3A, // 强, #404
+ 0x5F53, // 当, #233
+ 0x5F55, // 录, #146
+ 0x5F62, // 形, #494
+ 0x5F69, // 彩, #356
+ 0x5F71, // 影, #214
+ 0x5F88, // 很, #300
+ 0x5F97, // 得, #193
+ 0x5FAE, // 微, #245
+ 0x5FC3, // 心, #70
+ 0x5FEB, // 快, #324
+ 0x6001, // 态, #508
+ 0x600E, // 怎, #370
+ 0x6027, // 性, #99
+ 0x603B, // 总, #398
+ 0x606F, // 息, #176
+ 0x60A8, // 您, #251
+ 0x60C5, // 情, #87
+ 0x60F3, // 想, #290
+ 0x610F, // 意, #184
+ 0x611F, // 感, #253
+ 0x620F, // 戏, #237
+ 0x6210, // 成, #71
+ 0x6211, // 我, #11
+ 0x6216, // 或, #321
+ 0x6218, // 战, #369
+ 0x6237, // 户, #215
+ 0x623F, // 房, #236
+ 0x6240, // 所, #147
+ 0x624B, // 手, #55
+ 0x624D, // 才, #407
+ 0x6253, // 打, #281
+ 0x6280, // 技, #203
+ 0x6295, // 投, #408
+ 0x62A4, // 护, #502
+ 0x62A5, // 报, #113
+ 0x62DB, // 招, #363
+ 0x6301, // 持, #403
+ 0x6307, // 指, #414
+ 0x636E, // 据, #409
+ 0x6392, // 排, #377
+ 0x63A5, // 接, #266
+ 0x63A8, // 推, #244
+ 0x63D0, // 提, #181
+ 0x641C, // 搜, #301
+ 0x64AD, // 播, #401
+ 0x652F, // 支, #400
+ 0x6536, // 收, #158
+ 0x653E, // 放, #317
+ 0x653F, // 政, #380
+ 0x6548, // 效, #496
+ 0x6559, // 教, #170
+ 0x6570, // 数, #136
+ 0x6587, // 文, #21
+ 0x6599, // 料, #295
+ 0x65AF, // 斯, #473
+ 0x65B0, // 新, #14
+ 0x65B9, // 方, #68
+ 0x65C5, // 旅, #457
+ 0x65E0, // 无, #164
+ 0x65E5, // 日, #50
+ 0x65F6, // 时, #18
+ 0x660E, // 明, #132
+ 0x6613, // 易, #428
+ 0x661F, // 星, #240
+ 0x662F, // 是, #6
+ 0x663E, // 显, #486
+ 0x66F4, // 更, #103
+ 0x6700, // 最, #61
+ 0x6708, // 月, #80
+ 0x6709, // 有, #5
+ 0x670D, // 服, #94
+ 0x671F, // 期, #139
+ 0x672C, // 本, #56
+ 0x672F, // 术, #216
+ 0x673A, // 机, #27
+ 0x6743, // 权, #250
+ 0x6761, // 条, #309
+ 0x6765, // 来, #42
+ 0x677F, // 板, #505
+ 0x6797, // 林, #475
+ 0x679C, // 果, #212
+ 0x67E5, // 查, #165
+ 0x6807, // 标, #269
+ 0x6821, // 校, #462
+ 0x6837, // 样, #314
+ 0x683C, // 格, #238
+ 0x6848, // 案, #378
+ 0x697C, // 楼, #342
+ 0x6A21, // 模, #413
+ 0x6B21, // 次, #263
+ 0x6B22, // 欢, #443
+ 0x6B3E, // 款, #358
+ 0x6B63, // 正, #219
+ 0x6B64, // 此, #362
+ 0x6BD4, // 比, #298
+ 0x6C11, // 民, #279
+ 0x6C14, // 气, #303
+ 0x6C34, // 水, #163
+ 0x6C42, // 求, #373
+ 0x6C5F, // 江, #336
+ 0x6CA1, // 没, #229
+ 0x6CBB, // 治, #425
+ 0x6CD5, // 法, #85
+ 0x6CE8, // 注, #119
+ 0x6D3B, // 活, #231
+ 0x6D41, // 流, #280
+ 0x6D4B, // 测, #460
+ 0x6D77, // 海, #124
+ 0x6D88, // 消, #415
+ 0x6DF1, // 深, #477
+ 0x6E05, // 清, #311
+ 0x6E38, // 游, #81
+ 0x6E90, // 源, #325
+ 0x706B, // 火, #498
+ 0x70B9, // 点, #58
+ 0x70ED, // 热, #183
+ 0x7136, // 然, #308
+ 0x7167, // 照, #431
+ 0x7231, // 爱, #223
+ 0x7247, // 片, #128
+ 0x7248, // 版, #91
+ 0x724C, // 牌, #429
+ 0x7269, // 物, #169
+ 0x7279, // 特, #224
+ 0x738B, // 王, #351
+ 0x73A9, // 玩, #476
+ 0x73B0, // 现, #125
+ 0x7403, // 球, #367
+ 0x7406, // 理, #69
+ 0x751F, // 生, #24
+ 0x7528, // 用, #17
+ 0x7531, // 由, #441
+ 0x7535, // 电, #34
+ 0x7537, // 男, #275
+ 0x754C, // 界, #419
+ 0x75C5, // 病, #371
+ 0x767B, // 登, #204
+ 0x767D, // 白, #338
+ 0x767E, // 百, #157
+ 0x7684, // 的, #1
+ 0x76D8, // 盘, #493
+ 0x76EE, // 目, #261
+ 0x76F4, // 直, #391
+ 0x76F8, // 相, #143
+ 0x7701, // 省, #464
+ 0x770B, // 看, #54
+ 0x771F, // 真, #249
+ 0x7740, // 着, #302
+ 0x77E5, // 知, #142
+ 0x7801, // 码, #257
+ 0x7814, // 研, #387
+ 0x793A, // 示, #334
+ 0x793E, // 社, #343
+ 0x795E, // 神, #330
+ 0x798F, // 福, #509
+ 0x79BB, // 离, #454
+ 0x79CD, // 种, #278
+ 0x79D1, // 科, #126
+ 0x79EF, // 积, #390
+ 0x7A0B, // 程, #209
+ 0x7A76, // 究, #504
+ 0x7A7A, // 空, #312
+ 0x7ACB, // 立, #393
+ 0x7AD9, // 站, #107
+ 0x7AE0, // 章, #304
+ 0x7B2C, // 第, #96
+ 0x7B49, // 等, #210
+ 0x7B54, // 答, #256
+ 0x7B80, // 简, #474
+ 0x7BA1, // 管, #221
+ 0x7C7B, // 类, #246
+ 0x7CBE, // 精, #226
+ 0x7CFB, // 系, #89
+ 0x7D22, // 索, #354
+ 0x7EA2, // 红, #417
+ 0x7EA7, // 级, #178
+ 0x7EBF, // 线, #108
+ 0x7EC4, // 组, #389
+ 0x7EC6, // 细, #442
+ 0x7ECF, // 经, #74
+ 0x7ED3, // 结, #333
+ 0x7ED9, // 给, #384
+ 0x7EDC, // 络, #472
+ 0x7EDF, // 统, #344
+ 0x7F16, // 编, #424
+ 0x7F51, // 网, #9
+ 0x7F6E, // 置, #411
+ 0x7F8E, // 美, #60
+ 0x8001, // 老, #292
+ 0x8003, // 考, #288
+ 0x8005, // 者, #106
+ 0x800C, // 而, #297
+ 0x8054, // 联, #159
+ 0x80B2, // 育, #327
+ 0x80FD, // 能, #59
+ 0x81EA, // 自, #77
+ 0x8272, // 色, #198
+ 0x8282, // 节, #361
+ 0x82B1, // 花, #299
+ 0x82F1, // 英, #316
+ 0x8350, // 荐, #402
+ 0x836F, // 药, #481
+ 0x8425, // 营, #394
+ 0x85CF, // 藏, #337
+ 0x884C, // 行, #41
+ 0x8868, // 表, #104
+ 0x88AB, // 被, #289
+ 0x88C5, // 装, #161
+ 0x897F, // 西, #199
+ 0x8981, // 要, #48
+ 0x89C1, // 见, #360
+ 0x89C2, // 观, #423
+ 0x89C4, // 规, #453
+ 0x89C6, // 视, #120
+ 0x89E3, // 解, #264
+ 0x8A00, // 言, #433
+ 0x8BA1, // 计, #191
+ 0x8BA4, // 认, #482
+ 0x8BA9, // 让, #421
+ 0x8BAE, // 议, #427
+ 0x8BAF, // 讯, #388
+ 0x8BB0, // 记, #273
+ 0x8BBA, // 论, #66
+ 0x8BBE, // 设, #162
+ 0x8BC1, // 证, #201
+ 0x8BC4, // 评, #111
+ 0x8BC6, // 识, #463
+ 0x8BD5, // 试, #323
+ 0x8BDD, // 话, #247
+ 0x8BE2, // 询, #432
+ 0x8BE5, // 该, #447
+ 0x8BE6, // 详, #497
+ 0x8BED, // 语, #268
+ 0x8BF4, // 说, #112
+ 0x8BF7, // 请, #213
+ 0x8BFB, // 读, #341
+ 0x8C03, // 调, #438
+ 0x8D22, // 财, #488
+ 0x8D28, // 质, #386
+ 0x8D2D, // 购, #260
+ 0x8D34, // 贴, #510
+ 0x8D39, // 费, #242
+ 0x8D44, // 资, #116
+ 0x8D77, // 起, #220
+ 0x8D85, // 超, #406
+ 0x8DEF, // 路, #235
+ 0x8EAB, // 身, #262
+ 0x8F66, // 车, #82
+ 0x8F6C, // 转, #322
+ 0x8F7D, // 载, #175
+ 0x8FBE, // 达, #435
+ 0x8FC7, // 过, #118
+ 0x8FD0, // 运, #357
+ 0x8FD1, // 近, #492
+ 0x8FD8, // 还, #171
+ 0x8FD9, // 这, #57
+ 0x8FDB, // 进, #160
+ 0x8FDE, // 连, #489
+ 0x9009, // 选, #328
+ 0x901A, // 通, #137
+ 0x901F, // 速, #458
+ 0x9020, // 造, #511
+ 0x9053, // 道, #79
+ 0x90A3, // 那, #305
+ 0x90E8, // 部, #102
+ 0x90FD, // 都, #167
+ 0x914D, // 配, #479
+ 0x9152, // 酒, #444
+ 0x91CC, // 里, #196
+ 0x91CD, // 重, #230
+ 0x91CF, // 量, #248
+ 0x91D1, // 金, #134
+ 0x9500, // 销, #465
+ 0x957F, // 长, #152
+ 0x95E8, // 门, #185
+ 0x95EE, // 问, #92
+ 0x95F4, // 间, #88
+ 0x95FB, // 闻, #313
+ 0x9605, // 阅, #467
+ 0x9633, // 阳, #420
+ 0x9645, // 际, #501
+ 0x9650, // 限, #286
+ 0x9662, // 院, #276
+ 0x96C6, // 集, #284
+ 0x9700, // 需, #405
+ 0x9762, // 面, #123
+ 0x97F3, // 音, #335
+ 0x9875, // 页, #63
+ 0x9879, // 项, #506
+ 0x9891, // 频, #200
+ 0x9898, // 题, #110
+ 0x98CE, // 风, #252
+ 0x98DF, // 食, #445
+ 0x9996, // 首, #149
+ 0x9999, // 香, #512
+ 0x9A6C, // 马, #392
+ 0x9A8C, // 验, #382
+ 0x9AD8, // 高, #67
+ 0x9F99, // 龙, #426
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_zhCN_coverage=0.718950369339973;
+
+// The 512 most frequently occuring characters for the zhTW language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_zhTW[] = {
+ 0x4E00, // 一, #2
+ 0x4E09, // 三, #131
+ 0x4E0A, // 上, #12
+ 0x4E0B, // 下, #37
+ 0x4E0D, // 不, #6
+ 0x4E16, // 世, #312
+ 0x4E26, // 並, #434
+ 0x4E2D, // 中, #9
+ 0x4E3B, // 主, #97
+ 0x4E4B, // 之, #55
+ 0x4E5F, // 也, #95
+ 0x4E86, // 了, #19
+ 0x4E8B, // 事, #128
+ 0x4E8C, // 二, #187
+ 0x4E94, // 五, #339
+ 0x4E9B, // 些, #435
+ 0x4E9E, // 亞, #432
+ 0x4EA4, // 交, #264
+ 0x4EAB, // 享, #160
+ 0x4EBA, // 人, #3
+ 0x4EC0, // 什, #483
+ 0x4ECA, // 今, #380
+ 0x4ECB, // 介, #468
+ 0x4ED6, // 他, #65
+ 0x4EE3, // 代, #284
+ 0x4EE5, // 以, #26
+ 0x4EF6, // 件, #234
+ 0x4EFB, // 任, #381
+ 0x4EFD, // 份, #447
+ 0x4F46, // 但, #281
+ 0x4F4D, // 位, #202
+ 0x4F4F, // 住, #471
+ 0x4F55, // 何, #334
+ 0x4F5C, // 作, #56
+ 0x4F60, // 你, #64
+ 0x4F7F, // 使, #236
+ 0x4F86, // 來, #38
+ 0x4F9B, // 供, #397
+ 0x4FBF, // 便, #440
+ 0x4FC2, // 係, #506
+ 0x4FDD, // 保, #161
+ 0x4FE1, // 信, #268
+ 0x4FEE, // 修, #473
+ 0x500B, // 個, #27
+ 0x5011, // 們, #109
+ 0x505A, // 做, #383
+ 0x5065, // 健, #415
+ 0x5099, // 備, #461
+ 0x50B3, // 傳, #277
+ 0x50CF, // 像, #403
+ 0x50F9, // 價, #93
+ 0x512A, // 優, #396
+ 0x5143, // 元, #158
+ 0x5148, // 先, #382
+ 0x5149, // 光, #216
+ 0x514D, // 免, #321
+ 0x5152, // 兒, #374
+ 0x5165, // 入, #58
+ 0x5167, // 內, #106
+ 0x5168, // 全, #67
+ 0x5169, // 兩, #322
+ 0x516C, // 公, #53
+ 0x516D, // 六, #493
+ 0x5171, // 共, #456
+ 0x5176, // 其, #148
+ 0x5177, // 具, #328
+ 0x518A, // 冊, #360
+ 0x518D, // 再, #311
+ 0x51FA, // 出, #44
+ 0x5206, // 分, #15
+ 0x5217, // 列, #259
+ 0x5225, // 別, #361
+ 0x5229, // 利, #251
+ 0x5230, // 到, #29
+ 0x5247, // 則, #511
+ 0x524D, // 前, #82
+ 0x5275, // 創, #409
+ 0x529B, // 力, #176
+ 0x529F, // 功, #430
+ 0x52A0, // 加, #87
+ 0x52A9, // 助, #465
+ 0x52D5, // 動, #48
+ 0x52D9, // 務, #102
+ 0x5305, // 包, #248
+ 0x5316, // 化, #223
+ 0x5317, // 北, #145
+ 0x5340, // 區, #60
+ 0x5341, // 十, #242
+ 0x5357, // 南, #261
+ 0x535A, // 博, #484
+ 0x5361, // 卡, #327
+ 0x5370, // 印, #498
+ 0x5373, // 即, #351
+ 0x539F, // 原, #237
+ 0x53BB, // 去, #190
+ 0x53C3, // 參, #444
+ 0x53C8, // 又, #426
+ 0x53CA, // 及, #136
+ 0x53CB, // 友, #142
+ 0x53D6, // 取, #422
+ 0x53D7, // 受, #410
+ 0x53E3, // 口, #357
+ 0x53EA, // 只, #250
+ 0x53EF, // 可, #35
+ 0x53F0, // 台, #34
+ 0x53F8, // 司, #226
+ 0x5403, // 吃, #362
+ 0x5404, // 各, #454
+ 0x5408, // 合, #147
+ 0x540C, // 同, #173
+ 0x540D, // 名, #108
+ 0x544A, // 告, #186
+ 0x548C, // 和, #130
+ 0x54C1, // 品, #23
+ 0x54E1, // 員, #150
+ 0x5546, // 商, #75
+ 0x554F, // 問, #120
+ 0x559C, // 喜, #502
+ 0x55AE, // 單, #210
+ 0x55CE, // 嗎, #443
+ 0x5668, // 器, #305
+ 0x56DB, // 四, #318
+ 0x56DE, // 回, #59
+ 0x56E0, // 因, #253
+ 0x570B, // 國, #21
+ 0x5712, // 園, #345
+ 0x5716, // 圖, #73
+ 0x5718, // 團, #338
+ 0x5728, // 在, #11
+ 0x5730, // 地, #50
+ 0x578B, // 型, #270
+ 0x57CE, // 城, #466
+ 0x57FA, // 基, #349
+ 0x5831, // 報, #127
+ 0x5834, // 場, #165
+ 0x58EB, // 士, #372
+ 0x5916, // 外, #152
+ 0x591A, // 多, #54
+ 0x5927, // 大, #8
+ 0x5929, // 天, #43
+ 0x592A, // 太, #343
+ 0x5947, // 奇, #325
+ 0x5973, // 女, #85
+ 0x5979, // 她, #420
+ 0x597D, // 好, #22
+ 0x5982, // 如, #144
+ 0x5B50, // 子, #46
+ 0x5B57, // 字, #275
+ 0x5B78, // 學, #49
+ 0x5B89, // 安, #239
+ 0x5B8C, // 完, #320
+ 0x5B9A, // 定, #159
+ 0x5BA2, // 客, #188
+ 0x5BB6, // 家, #31
+ 0x5BB9, // 容, #244
+ 0x5BE6, // 實, #198
+ 0x5BF6, // 寶, #367
+ 0x5C07, // 將, #232
+ 0x5C08, // 專, #133
+ 0x5C0B, // 尋, #352
+ 0x5C0D, // 對, #126
+ 0x5C0E, // 導, #418
+ 0x5C0F, // 小, #20
+ 0x5C11, // 少, #368
+ 0x5C31, // 就, #63
+ 0x5C55, // 展, #341
+ 0x5C71, // 山, #273
+ 0x5DE5, // 工, #121
+ 0x5DF1, // 己, #402
+ 0x5DF2, // 已, #299
+ 0x5E02, // 市, #81
+ 0x5E2B, // 師, #262
+ 0x5E36, // 帶, #470
+ 0x5E38, // 常, #303
+ 0x5E73, // 平, #297
+ 0x5E74, // 年, #30
+ 0x5E97, // 店, #171
+ 0x5EA6, // 度, #220
+ 0x5EB7, // 康, #441
+ 0x5EE3, // 廣, #279
+ 0x5EFA, // 建, #254
+ 0x5F0F, // 式, #155
+ 0x5F15, // 引, #346
+ 0x5F35, // 張, #366
+ 0x5F37, // 強, #437
+ 0x5F71, // 影, #94
+ 0x5F88, // 很, #177
+ 0x5F8C, // 後, #66
+ 0x5F97, // 得, #113
+ 0x5F9E, // 從, #436
+ 0x5FC3, // 心, #57
+ 0x5FEB, // 快, #292
+ 0x6027, // 性, #175
+ 0x606F, // 息, #378
+ 0x60A8, // 您, #252
+ 0x60C5, // 情, #123
+ 0x60F3, // 想, #178
+ 0x610F, // 意, #168
+ 0x611B, // 愛, #125
+ 0x611F, // 感, #211
+ 0x61C9, // 應, #164
+ 0x6210, // 成, #86
+ 0x6211, // 我, #7
+ 0x6216, // 或, #199
+ 0x6230, // 戰, #438
+ 0x6232, // 戲, #309
+ 0x6236, // 戶, #497
+ 0x623F, // 房, #274
+ 0x6240, // 所, #79
+ 0x624B, // 手, #68
+ 0x624D, // 才, #400
+ 0x6253, // 打, #278
+ 0x627E, // 找, #449
+ 0x6280, // 技, #332
+ 0x6295, // 投, #425
+ 0x62C9, // 拉, #500
+ 0x62CD, // 拍, #398
+ 0x6307, // 指, #407
+ 0x6392, // 排, #458
+ 0x63A5, // 接, #326
+ 0x63A8, // 推, #153
+ 0x63D0, // 提, #235
+ 0x641C, // 搜, #314
+ 0x6469, // 摩, #472
+ 0x6536, // 收, #249
+ 0x6539, // 改, #508
+ 0x653E, // 放, #331
+ 0x653F, // 政, #295
+ 0x6559, // 教, #184
+ 0x6574, // 整, #394
+ 0x6578, // 數, #134
+ 0x6587, // 文, #16
+ 0x6599, // 料, #167
+ 0x65AF, // 斯, #476
+ 0x65B0, // 新, #10
+ 0x65B9, // 方, #96
+ 0x65BC, // 於, #70
+ 0x65C5, // 旅, #289
+ 0x65E5, // 日, #18
+ 0x660E, // 明, #118
+ 0x6613, // 易, #482
+ 0x661F, // 星, #205
+ 0x662F, // 是, #5
+ 0x6642, // 時, #13
+ 0x66F4, // 更, #149
+ 0x66F8, // 書, #209
+ 0x6700, // 最, #51
+ 0x6703, // 會, #14
+ 0x6708, // 月, #25
+ 0x6709, // 有, #4
+ 0x670D, // 服, #99
+ 0x671F, // 期, #139
+ 0x672A, // 未, #404
+ 0x672C, // 本, #45
+ 0x6771, // 東, #221
+ 0x677F, // 板, #364
+ 0x6797, // 林, #330
+ 0x679C, // 果, #179
+ 0x67E5, // 查, #283
+ 0x683C, // 格, #157
+ 0x6848, // 案, #392
+ 0x689D, // 條, #406
+ 0x696D, // 業, #103
+ 0x6A02, // 樂, #116
+ 0x6A13, // 樓, #411
+ 0x6A19, // 標, #384
+ 0x6A23, // 樣, #306
+ 0x6A5F, // 機, #40
+ 0x6AA2, // 檢, #359
+ 0x6B0A, // 權, #228
+ 0x6B21, // 次, #227
+ 0x6B3E, // 款, #276
+ 0x6B4C, // 歌, #496
+ 0x6B61, // 歡, #427
+ 0x6B63, // 正, #206
+ 0x6B64, // 此, #247
+ 0x6BCF, // 每, #391
+ 0x6BD4, // 比, #257
+ 0x6C11, // 民, #230
+ 0x6C23, // 氣, #200
+ 0x6C34, // 水, #140
+ 0x6C42, // 求, #501
+ 0x6C92, // 沒, #162
+ 0x6CD5, // 法, #89
+ 0x6D3B, // 活, #124
+ 0x6D41, // 流, #315
+ 0x6D77, // 海, #258
+ 0x6D88, // 消, #342
+ 0x6E05, // 清, #329
+ 0x6E2F, // 港, #293
+ 0x6F14, // 演, #491
+ 0x7063, // 灣, #195
+ 0x70BA, // 為, #39
+ 0x7121, // 無, #107
+ 0x7136, // 然, #215
+ 0x7167, // 照, #376
+ 0x71B1, // 熱, #245
+ 0x7247, // 片, #90
+ 0x7248, // 版, #112
+ 0x724C, // 牌, #467
+ 0x7269, // 物, #110
+ 0x7279, // 特, #183
+ 0x738B, // 王, #287
+ 0x73A9, // 玩, #354
+ 0x73FE, // 現, #143
+ 0x7403, // 球, #350
+ 0x7406, // 理, #105
+ 0x751F, // 生, #24
+ 0x7522, // 產, #201
+ 0x7528, // 用, #17
+ 0x7531, // 由, #288
+ 0x7537, // 男, #298
+ 0x754C, // 界, #399
+ 0x7559, // 留, #218
+ 0x756B, // 畫, #412
+ 0x7576, // 當, #185
+ 0x767B, // 登, #138
+ 0x767C, // 發, #28
+ 0x767D, // 白, #377
+ 0x767E, // 百, #393
+ 0x7684, // 的, #1
+ 0x76EE, // 目, #271
+ 0x76F4, // 直, #379
+ 0x76F8, // 相, #98
+ 0x770B, // 看, #52
+ 0x771F, // 真, #180
+ 0x773C, // 眼, #433
+ 0x77E5, // 知, #170
+ 0x78BC, // 碼, #481
+ 0x793A, // 示, #353
+ 0x793E, // 社, #333
+ 0x795E, // 神, #304
+ 0x7968, // 票, #477
+ 0x798F, // 福, #494
+ 0x79C1, // 私, #507
+ 0x79D1, // 科, #280
+ 0x7A0B, // 程, #272
+ 0x7A2E, // 種, #337
+ 0x7A4D, // 積, #385
+ 0x7A7A, // 空, #324
+ 0x7ACB, // 立, #286
+ 0x7AD9, // 站, #117
+ 0x7AE0, // 章, #141
+ 0x7B2C, // 第, #135
+ 0x7B49, // 等, #240
+ 0x7BA1, // 管, #340
+ 0x7BC0, // 節, #431
+ 0x7BC7, // 篇, #479
+ 0x7C21, // 簡, #499
+ 0x7CBE, // 精, #213
+ 0x7CFB, // 系, #212
+ 0x7D04, // 約, #462
+ 0x7D05, // 紅, #452
+ 0x7D1A, // 級, #267
+ 0x7D30, // 細, #486
+ 0x7D44, // 組, #335
+ 0x7D50, // 結, #243
+ 0x7D66, // 給, #355
+ 0x7D71, // 統, #375
+ 0x7D93, // 經, #111
+ 0x7DB2, // 網, #32
+ 0x7DDA, // 線, #151
+ 0x7E23, // 縣, #439
+ 0x7E3D, // 總, #370
+ 0x7F8E, // 美, #41
+ 0x7FA9, // 義, #504
+ 0x8001, // 老, #290
+ 0x8003, // 考, #428
+ 0x8005, // 者, #92
+ 0x800C, // 而, #217
+ 0x805E, // 聞, #181
+ 0x806F, // 聯, #310
+ 0x8072, // 聲, #413
+ 0x80A1, // 股, #390
+ 0x80B2, // 育, #453
+ 0x80FD, // 能, #71
+ 0x8166, // 腦, #408
+ 0x81EA, // 自, #61
+ 0x81F3, // 至, #344
+ 0x8207, // 與, #84
+ 0x8209, // 舉, #463
+ 0x8272, // 色, #192
+ 0x82B1, // 花, #255
+ 0x82F1, // 英, #348
+ 0x83EF, // 華, #196
+ 0x842C, // 萬, #316
+ 0x843D, // 落, #308
+ 0x8457, // 著, #233
+ 0x85A6, // 薦, #401
+ 0x85CF, // 藏, #503
+ 0x85DD, // 藝, #488
+ 0x8655, // 處, #419
+ 0x865F, // 號, #191
+ 0x884C, // 行, #47
+ 0x8853, // 術, #395
+ 0x8868, // 表, #77
+ 0x88AB, // 被, #291
+ 0x88DD, // 裝, #256
+ 0x88E1, // 裡, #369
+ 0x88FD, // 製, #510
+ 0x897F, // 西, #300
+ 0x8981, // 要, #36
+ 0x898B, // 見, #307
+ 0x8996, // 視, #204
+ 0x89BA, // 覺, #450
+ 0x89BD, // 覽, #387
+ 0x89C0, // 觀, #365
+ 0x89E3, // 解, #323
+ 0x8A00, // 言, #169
+ 0x8A02, // 訂, #423
+ 0x8A08, // 計, #225
+ 0x8A0A, // 訊, #156
+ 0x8A0E, // 討, #373
+ 0x8A18, // 記, #222
+ 0x8A2D, // 設, #174
+ 0x8A3B, // 註, #356
+ 0x8A55, // 評, #246
+ 0x8A66, // 試, #448
+ 0x8A71, // 話, #229
+ 0x8A72, // 該, #446
+ 0x8A8D, // 認, #464
+ 0x8A9E, // 語, #371
+ 0x8AAA, // 說, #91
+ 0x8ABF, // 調, #509
+ 0x8ACB, // 請, #119
+ 0x8AD6, // 論, #114
+ 0x8B1D, // 謝, #389
+ 0x8B49, // 證, #429
+ 0x8B58, // 識, #416
+ 0x8B70, // 議, #485
+ 0x8B77, // 護, #475
+ 0x8B80, // 讀, #386
+ 0x8B8A, // 變, #388
+ 0x8B93, // 讓, #336
+ 0x8CA8, // 貨, #313
+ 0x8CB7, // 買, #260
+ 0x8CBB, // 費, #203
+ 0x8CC7, // 資, #62
+ 0x8CE3, // 賣, #294
+ 0x8CEA, // 質, #457
+ 0x8CFC, // 購, #189
+ 0x8D77, // 起, #214
+ 0x8D85, // 超, #296
+ 0x8DDF, // 跟, #489
+ 0x8DEF, // 路, #137
+ 0x8EAB, // 身, #197
+ 0x8ECA, // 車, #76
+ 0x8F09, // 載, #301
+ 0x8F49, // 轉, #282
+ 0x8FD1, // 近, #414
+ 0x9001, // 送, #363
+ 0x9019, // 這, #42
+ 0x901A, // 通, #207
+ 0x901F, // 速, #495
+ 0x9020, // 造, #455
+ 0x9023, // 連, #285
+ 0x9032, // 進, #231
+ 0x904A, // 遊, #132
+ 0x904B, // 運, #219
+ 0x904E, // 過, #101
+ 0x9053, // 道, #146
+ 0x9054, // 達, #417
+ 0x9078, // 選, #182
+ 0x9084, // 還, #154
+ 0x908A, // 邊, #487
+ 0x90A3, // 那, #269
+ 0x90E8, // 部, #78
+ 0x90FD, // 都, #104
+ 0x914D, // 配, #421
+ 0x9152, // 酒, #512
+ 0x91AB, // 醫, #358
+ 0x91CD, // 重, #224
+ 0x91CF, // 量, #319
+ 0x91D1, // 金, #115
+ 0x9304, // 錄, #302
+ 0x9577, // 長, #172
+ 0x9580, // 門, #193
+ 0x958B, // 開, #72
+ 0x9593, // 間, #80
+ 0x95B1, // 閱, #405
+ 0x95DC, // 關, #74
+ 0x963F, // 阿, #460
+ 0x9650, // 限, #265
+ 0x9662, // 院, #474
+ 0x9664, // 除, #478
+ 0x969B, // 際, #459
+ 0x96C6, // 集, #347
+ 0x96E2, // 離, #442
+ 0x96FB, // 電, #33
+ 0x9700, // 需, #445
+ 0x975E, // 非, #451
+ 0x9762, // 面, #129
+ 0x97F3, // 音, #194
+ 0x9801, // 頁, #83
+ 0x982D, // 頭, #238
+ 0x984C, // 題, #122
+ 0x985E, // 類, #163
+ 0x98A8, // 風, #266
+ 0x98DF, // 食, #208
+ 0x9910, // 餐, #469
+ 0x9928, // 館, #424
+ 0x9996, // 首, #166
+ 0x9999, // 香, #263
+ 0x99AC, // 馬, #317
+ 0x9A57, // 驗, #492
+ 0x9AD4, // 體, #100
+ 0x9AD8, // 高, #88
+ 0x9EBC, // 麼, #241
+ 0x9EC3, // 黃, #480
+ 0x9ED1, // 黑, #490
+ 0x9EDE, // 點, #69
+ 0x9F8D, // 龍, #505
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_zhTW_coverage=0.704841200026877;
+
+// The 512 most frequently occuring characters for the ja language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_ja[] = {
+ 0x3005, // 々, #352
+ 0x3041, // ぁ, #486
+ 0x3042, // あ, #50
+ 0x3044, // い, #2
+ 0x3046, // う, #33
+ 0x3048, // え, #83
+ 0x304A, // お, #37
+ 0x304B, // か, #21
+ 0x304C, // が, #17
+ 0x304D, // き, #51
+ 0x304E, // ぎ, #324
+ 0x304F, // く, #38
+ 0x3050, // ぐ, #334
+ 0x3051, // け, #60
+ 0x3052, // げ, #296
+ 0x3053, // こ, #34
+ 0x3054, // ご, #100
+ 0x3055, // さ, #31
+ 0x3056, // ざ, #378
+ 0x3057, // し, #4
+ 0x3058, // じ, #121
+ 0x3059, // す, #12
+ 0x305A, // ず, #215
+ 0x305B, // せ, #86
+ 0x305D, // そ, #68
+ 0x305F, // た, #11
+ 0x3060, // だ, #42
+ 0x3061, // ち, #67
+ 0x3063, // っ, #23
+ 0x3064, // つ, #73
+ 0x3066, // て, #7
+ 0x3067, // で, #6
+ 0x3068, // と, #14
+ 0x3069, // ど, #75
+ 0x306A, // な, #8
+ 0x306B, // に, #5
+ 0x306D, // ね, #123
+ 0x306E, // の, #1
+ 0x306F, // は, #16
+ 0x3070, // ば, #150
+ 0x3071, // ぱ, #259
+ 0x3072, // ひ, #364
+ 0x3073, // び, #266
+ 0x3075, // ふ, #484
+ 0x3076, // ぶ, #330
+ 0x3078, // へ, #146
+ 0x3079, // べ, #207
+ 0x307B, // ほ, #254
+ 0x307E, // ま, #18
+ 0x307F, // み, #74
+ 0x3080, // む, #285
+ 0x3081, // め, #78
+ 0x3082, // も, #32
+ 0x3083, // ゃ, #111
+ 0x3084, // や, #85
+ 0x3086, // ゆ, #392
+ 0x3087, // ょ, #224
+ 0x3088, // よ, #63
+ 0x3089, // ら, #29
+ 0x308A, // り, #28
+ 0x308B, // る, #9
+ 0x308C, // れ, #35
+ 0x308D, // ろ, #127
+ 0x308F, // わ, #88
+ 0x3092, // を, #19
+ 0x3093, // ん, #22
+ 0x30A1, // ァ, #193
+ 0x30A2, // ア, #27
+ 0x30A3, // ィ, #70
+ 0x30A4, // イ, #15
+ 0x30A6, // ウ, #89
+ 0x30A7, // ェ, #134
+ 0x30A8, // エ, #81
+ 0x30A9, // ォ, #225
+ 0x30AA, // オ, #76
+ 0x30AB, // カ, #52
+ 0x30AC, // ガ, #147
+ 0x30AD, // キ, #66
+ 0x30AE, // ギ, #246
+ 0x30AF, // ク, #25
+ 0x30B0, // グ, #39
+ 0x30B1, // ケ, #137
+ 0x30B2, // ゲ, #200
+ 0x30B3, // コ, #46
+ 0x30B4, // ゴ, #183
+ 0x30B5, // サ, #64
+ 0x30B6, // ザ, #221
+ 0x30B7, // シ, #48
+ 0x30B8, // ジ, #55
+ 0x30B9, // ス, #13
+ 0x30BA, // ズ, #103
+ 0x30BB, // セ, #109
+ 0x30BC, // ゼ, #499
+ 0x30BD, // ソ, #175
+ 0x30BF, // タ, #45
+ 0x30C0, // ダ, #104
+ 0x30C1, // チ, #71
+ 0x30C3, // ッ, #20
+ 0x30C4, // ツ, #119
+ 0x30C6, // テ, #59
+ 0x30C7, // デ, #82
+ 0x30C8, // ト, #10
+ 0x30C9, // ド, #44
+ 0x30CA, // ナ, #102
+ 0x30CB, // ニ, #72
+ 0x30CD, // ネ, #117
+ 0x30CE, // ノ, #192
+ 0x30CF, // ハ, #164
+ 0x30D0, // バ, #62
+ 0x30D1, // パ, #90
+ 0x30D2, // ヒ, #398
+ 0x30D3, // ビ, #77
+ 0x30D4, // ピ, #135
+ 0x30D5, // フ, #47
+ 0x30D6, // ブ, #56
+ 0x30D7, // プ, #43
+ 0x30D8, // ヘ, #268
+ 0x30D9, // ベ, #157
+ 0x30DA, // ペ, #125
+ 0x30DB, // ホ, #155
+ 0x30DC, // ボ, #168
+ 0x30DD, // ポ, #114
+ 0x30DE, // マ, #57
+ 0x30DF, // ミ, #97
+ 0x30E0, // ム, #69
+ 0x30E1, // メ, #53
+ 0x30E2, // モ, #142
+ 0x30E3, // ャ, #93
+ 0x30E4, // ヤ, #258
+ 0x30E5, // ュ, #79
+ 0x30E6, // ユ, #405
+ 0x30E7, // ョ, #98
+ 0x30E9, // ラ, #26
+ 0x30EA, // リ, #30
+ 0x30EB, // ル, #24
+ 0x30EC, // レ, #41
+ 0x30ED, // ロ, #40
+ 0x30EF, // ワ, #144
+ 0x30F3, // ン, #3
+ 0x30F4, // ヴ, #483
+ 0x30FD, // ヽ, #501
+ 0x4E00, // 一, #84
+ 0x4E07, // 万, #337
+ 0x4E09, // 三, #323
+ 0x4E0A, // 上, #133
+ 0x4E0B, // 下, #180
+ 0x4E0D, // 不, #277
+ 0x4E16, // 世, #385
+ 0x4E2D, // 中, #87
+ 0x4E3B, // 主, #432
+ 0x4E88, // 予, #326
+ 0x4E8B, // 事, #95
+ 0x4E8C, // 二, #394
+ 0x4E95, // 井, #468
+ 0x4EA4, // 交, #410
+ 0x4EAC, // 京, #260
+ 0x4EBA, // 人, #61
+ 0x4ECA, // 今, #184
+ 0x4ECB, // 介, #358
+ 0x4ED5, // 仕, #391
+ 0x4ED6, // 他, #256
+ 0x4ED8, // 付, #243
+ 0x4EE3, // 代, #280
+ 0x4EE5, // 以, #216
+ 0x4EF6, // 件, #190
+ 0x4F1A, // 会, #105
+ 0x4F4D, // 位, #177
+ 0x4F4F, // 住, #376
+ 0x4F53, // 体, #223
+ 0x4F55, // 何, #294
+ 0x4F5C, // 作, #154
+ 0x4F7F, // 使, #233
+ 0x4F9B, // 供, #503
+ 0x4FA1, // 価, #217
+ 0x4FBF, // 便, #511
+ 0x4FDD, // 保, #279
+ 0x4FE1, // 信, #271
+ 0x500B, // 個, #415
+ 0x50CF, // 像, #178
+ 0x512A, // 優, #403
+ 0x5143, // 元, #384
+ 0x5148, // 先, #311
+ 0x5149, // 光, #488
+ 0x5165, // 入, #115
+ 0x5168, // 全, #173
+ 0x516C, // 公, #287
+ 0x5177, // 具, #447
+ 0x5185, // 内, #169
+ 0x5186, // 円, #131
+ 0x5199, // 写, #275
+ 0x51FA, // 出, #110
+ 0x5206, // 分, #130
+ 0x5207, // 切, #401
+ 0x521D, // 初, #319
+ 0x5225, // 別, #290
+ 0x5229, // 利, #226
+ 0x5236, // 制, #507
+ 0x524D, // 前, #124
+ 0x529B, // 力, #272
+ 0x52A0, // 加, #249
+ 0x52D5, // 動, #120
+ 0x52D9, // 務, #421
+ 0x52DF, // 募, #476
+ 0x5316, // 化, #308
+ 0x5317, // 北, #341
+ 0x533A, // 区, #348
+ 0x539F, // 原, #321
+ 0x53C2, // 参, #452
+ 0x53CB, // 友, #451
+ 0x53D6, // 取, #237
+ 0x53D7, // 受, #354
+ 0x53E3, // 口, #289
+ 0x53E4, // 古, #339
+ 0x53EF, // 可, #298
+ 0x53F0, // 台, #439
+ 0x53F7, // 号, #361
+ 0x5408, // 合, #118
+ 0x540C, // 同, #263
+ 0x540D, // 名, #65
+ 0x5411, // 向, #434
+ 0x544A, // 告, #386
+ 0x5468, // 周, #393
+ 0x5473, // 味, #299
+ 0x548C, // 和, #350
+ 0x54C1, // 品, #96
+ 0x54E1, // 員, #293
+ 0x5546, // 商, #198
+ 0x554F, // 問, #158
+ 0x55B6, // 営, #438
+ 0x5668, // 器, #366
+ 0x56DE, // 回, #143
+ 0x56F3, // 図, #444
+ 0x56FD, // 国, #153
+ 0x5712, // 園, #435
+ 0x571F, // 土, #239
+ 0x5728, // 在, #351
+ 0x5730, // 地, #163
+ 0x578B, // 型, #430
+ 0x5831, // 報, #112
+ 0x5834, // 場, #139
+ 0x58F2, // 売, #232
+ 0x5909, // 変, #306
+ 0x5916, // 外, #222
+ 0x591A, // 多, #336
+ 0x5927, // 大, #80
+ 0x5929, // 天, #278
+ 0x5973, // 女, #161
+ 0x597D, // 好, #349
+ 0x5A5A, // 婚, #479
+ 0x5B50, // 子, #113
+ 0x5B57, // 字, #492
+ 0x5B66, // 学, #132
+ 0x5B89, // 安, #295
+ 0x5B9A, // 定, #145
+ 0x5B9F, // 実, #220
+ 0x5BA4, // 室, #482
+ 0x5BAE, // 宮, #487
+ 0x5BB6, // 家, #211
+ 0x5BB9, // 容, #333
+ 0x5BFE, // 対, #252
+ 0x5C02, // 専, #474
+ 0x5C0F, // 小, #212
+ 0x5C11, // 少, #377
+ 0x5C4B, // 屋, #284
+ 0x5C71, // 山, #206
+ 0x5CA1, // 岡, #429
+ 0x5CF6, // 島, #297
+ 0x5DDD, // 川, #253
+ 0x5DE5, // 工, #374
+ 0x5E02, // 市, #159
+ 0x5E2F, // 帯, #416
+ 0x5E38, // 常, #437
+ 0x5E73, // 平, #390
+ 0x5E74, // 年, #54
+ 0x5E83, // 広, #367
+ 0x5E97, // 店, #149
+ 0x5EA6, // 度, #269
+ 0x5EAB, // 庫, #380
+ 0x5F0F, // 式, #265
+ 0x5F15, // 引, #345
+ 0x5F37, // 強, #446
+ 0x5F53, // 当, #240
+ 0x5F62, // 形, #502
+ 0x5F8C, // 後, #230
+ 0x5F97, // 得, #490
+ 0x5FC3, // 心, #307
+ 0x5FC5, // 必, #422
+ 0x5FDC, // 応, #356
+ 0x601D, // 思, #189
+ 0x6027, // 性, #201
+ 0x6075, // 恵, #400
+ 0x60C5, // 情, #140
+ 0x60F3, // 想, #477
+ 0x610F, // 意, #305
+ 0x611B, // 愛, #273
+ 0x611F, // 感, #257
+ 0x6210, // 成, #262
+ 0x6226, // 戦, #365
+ 0x6240, // 所, #236
+ 0x624B, // 手, #160
+ 0x6295, // 投, #129
+ 0x6301, // 持, #355
+ 0x6307, // 指, #425
+ 0x63A2, // 探, #369
+ 0x63B2, // 掲, #399
+ 0x643A, // 携, #459
+ 0x652F, // 支, #512
+ 0x653E, // 放, #469
+ 0x6559, // 教, #270
+ 0x6570, // 数, #181
+ 0x6587, // 文, #202
+ 0x6599, // 料, #106
+ 0x65B0, // 新, #99
+ 0x65B9, // 方, #126
+ 0x65C5, // 旅, #445
+ 0x65E5, // 日, #36
+ 0x660E, // 明, #300
+ 0x6620, // 映, #418
+ 0x6642, // 時, #107
+ 0x66F4, // 更, #359
+ 0x66F8, // 書, #174
+ 0x6700, // 最, #152
+ 0x6708, // 月, #49
+ 0x6709, // 有, #302
+ 0x671F, // 期, #332
+ 0x6728, // 木, #203
+ 0x672C, // 本, #92
+ 0x6750, // 材, #489
+ 0x6751, // 村, #466
+ 0x6765, // 来, #267
+ 0x6771, // 東, #191
+ 0x677F, // 板, #411
+ 0x679C, // 果, #441
+ 0x6821, // 校, #327
+ 0x682A, // 株, #412
+ 0x683C, // 格, #228
+ 0x691C, // 検, #179
+ 0x696D, // 業, #166
+ 0x697D, // 楽, #172
+ 0x69D8, // 様, #255
+ 0x6A5F, // 機, #235
+ 0x6B21, // 次, #318
+ 0x6B62, // 止, #475
+ 0x6B63, // 正, #312
+ 0x6C17, // 気, #116
+ 0x6C34, // 水, #165
+ 0x6C42, // 求, #465
+ 0x6C7A, // 決, #370
+ 0x6CBB, // 治, #505
+ 0x6CC1, // 況, #462
+ 0x6CD5, // 法, #227
+ 0x6CE8, // 注, #372
+ 0x6D3B, // 活, #303
+ 0x6D41, // 流, #480
+ 0x6D77, // 海, #274
+ 0x6E08, // 済, #417
+ 0x6F14, // 演, #504
+ 0x706B, // 火, #264
+ 0x70B9, // 点, #331
+ 0x7121, // 無, #58
+ 0x7248, // 版, #409
+ 0x7269, // 物, #170
+ 0x7279, // 特, #242
+ 0x72B6, // 状, #458
+ 0x73FE, // 現, #322
+ 0x7406, // 理, #162
+ 0x751F, // 生, #122
+ 0x7523, // 産, #320
+ 0x7528, // 用, #94
+ 0x7530, // 田, #195
+ 0x7537, // 男, #373
+ 0x753A, // 町, #314
+ 0x753B, // 画, #91
+ 0x754C, // 界, #436
+ 0x756A, // 番, #261
+ 0x75C5, // 病, #428
+ 0x767A, // 発, #194
+ 0x767B, // 登, #231
+ 0x767D, // 白, #419
+ 0x7684, // 的, #251
+ 0x76EE, // 目, #197
+ 0x76F4, // 直, #497
+ 0x76F8, // 相, #286
+ 0x770C, // 県, #199
+ 0x771F, // 真, #219
+ 0x7740, // 着, #283
+ 0x77E5, // 知, #185
+ 0x77F3, // 石, #500
+ 0x78BA, // 確, #383
+ 0x793A, // 示, #241
+ 0x793E, // 社, #167
+ 0x795E, // 神, #315
+ 0x798F, // 福, #423
+ 0x79C1, // 私, #347
+ 0x79D1, // 科, #420
+ 0x7A0E, // 税, #368
+ 0x7A2E, // 種, #455
+ 0x7A3F, // 稿, #148
+ 0x7A7A, // 空, #427
+ 0x7ACB, // 立, #309
+ 0x7B11, // 笑, #454
+ 0x7B2C, // 第, #317
+ 0x7B49, // 等, #457
+ 0x7B54, // 答, #426
+ 0x7BA1, // 管, #481
+ 0x7CFB, // 系, #408
+ 0x7D04, // 約, #276
+ 0x7D20, // 素, #407
+ 0x7D22, // 索, #214
+ 0x7D30, // 細, #381
+ 0x7D39, // 紹, #471
+ 0x7D42, // 終, #456
+ 0x7D44, // 組, #424
+ 0x7D4C, // 経, #360
+ 0x7D50, // 結, #291
+ 0x7D9A, // 続, #357
+ 0x7DCF, // 総, #467
+ 0x7DDA, // 線, #338
+ 0x7DE8, // 編, #453
+ 0x7F8E, // 美, #204
+ 0x8003, // 考, #387
+ 0x8005, // 者, #151
+ 0x805E, // 聞, #463
+ 0x8077, // 職, #363
+ 0x80B2, // 育, #433
+ 0x80FD, // 能, #250
+ 0x8179, // 腹, #396
+ 0x81EA, // 自, #156
+ 0x826F, // 良, #329
+ 0x8272, // 色, #402
+ 0x82B1, // 花, #440
+ 0x82B8, // 芸, #413
+ 0x82F1, // 英, #485
+ 0x8449, // 葉, #472
+ 0x884C, // 行, #128
+ 0x8853, // 術, #460
+ 0x8868, // 表, #209
+ 0x88FD, // 製, #431
+ 0x897F, // 西, #406
+ 0x8981, // 要, #313
+ 0x898B, // 見, #101
+ 0x898F, // 規, #375
+ 0x89A7, // 覧, #171
+ 0x89E3, // 解, #388
+ 0x8A00, // 言, #210
+ 0x8A08, // 計, #343
+ 0x8A18, // 記, #136
+ 0x8A2D, // 設, #292
+ 0x8A71, // 話, #213
+ 0x8A73, // 詳, #371
+ 0x8A8D, // 認, #404
+ 0x8A9E, // 語, #234
+ 0x8AAC, // 説, #494
+ 0x8AAD, // 読, #301
+ 0x8ABF, // 調, #443
+ 0x8AC7, // 談, #448
+ 0x8B77, // 護, #509
+ 0x8C37, // 谷, #506
+ 0x8CA9, // 販, #362
+ 0x8CB7, // 買, #346
+ 0x8CC7, // 資, #473
+ 0x8CEA, // 質, #281
+ 0x8CFC, // 購, #495
+ 0x8EAB, // 身, #470
+ 0x8ECA, // 車, #205
+ 0x8EE2, // 転, #335
+ 0x8F09, // 載, #342
+ 0x8FBC, // 込, #229
+ 0x8FD1, // 近, #304
+ 0x8FD4, // 返, #461
+ 0x8FFD, // 追, #379
+ 0x9001, // 送, #186
+ 0x901A, // 通, #182
+ 0x901F, // 速, #340
+ 0x9023, // 連, #244
+ 0x904B, // 運, #382
+ 0x904E, // 過, #498
+ 0x9053, // 道, #282
+ 0x9054, // 達, #450
+ 0x9055, // 違, #414
+ 0x9078, // 選, #288
+ 0x90E8, // 部, #208
+ 0x90FD, // 都, #344
+ 0x914D, // 配, #389
+ 0x91CD, // 重, #478
+ 0x91CE, // 野, #245
+ 0x91D1, // 金, #138
+ 0x9332, // 録, #238
+ 0x9577, // 長, #247
+ 0x9580, // 門, #508
+ 0x958B, // 開, #248
+ 0x9593, // 間, #141
+ 0x95A2, // 関, #188
+ 0x962A, // 阪, #496
+ 0x9650, // 限, #395
+ 0x9662, // 院, #449
+ 0x9664, // 除, #510
+ 0x969B, // 際, #493
+ 0x96C6, // 集, #196
+ 0x96D1, // 雑, #442
+ 0x96FB, // 電, #187
+ 0x9762, // 面, #328
+ 0x97F3, // 音, #325
+ 0x984C, // 題, #310
+ 0x985E, // 類, #491
+ 0x98A8, // 風, #353
+ 0x98DF, // 食, #218
+ 0x9928, // 館, #464
+ 0x99C5, // 駅, #316
+ 0x9A13, // 験, #397
+ 0x9AD8, // 高, #176
+ 0xFF57, // w, #108
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_ja_coverage=0.880569589120162;
+
+// The 512 most frequently occuring characters for the ko language in a sample of the Internet.
+// Ordered by codepoint, comment shows character and ranking by frequency
+const uint16_t frequent_ko[] = {
+ 0x314B, // ㅋ, #148
+ 0x314E, // ㅎ, #390
+ 0x3160, // ㅠ, #354
+ 0x318D, // ㆍ, #439
+ 0xAC00, // 가, #6
+ 0xAC01, // 각, #231
+ 0xAC04, // 간, #106
+ 0xAC08, // 갈, #362
+ 0xAC10, // 감, #122
+ 0xAC11, // 갑, #493
+ 0xAC15, // 강, #155
+ 0xAC19, // 같, #264
+ 0xAC1C, // 개, #87
+ 0xAC1D, // 객, #198
+ 0xAC24, // 갤, #457
+ 0xAC70, // 거, #91
+ 0xAC74, // 건, #161
+ 0xAC78, // 걸, #338
+ 0xAC80, // 검, #184
+ 0xAC83, // 것, #116
+ 0xAC8C, // 게, #36
+ 0xACA0, // 겠, #233
+ 0xACA8, // 겨, #341
+ 0xACA9, // 격, #245
+ 0xACAC, // 견, #413
+ 0xACB0, // 결, #202
+ 0xACBD, // 경, #62
+ 0xACC4, // 계, #142
+ 0xACE0, // 고, #12
+ 0xACE1, // 곡, #444
+ 0xACE8, // 골, #379
+ 0xACF3, // 곳, #388
+ 0xACF5, // 공, #59
+ 0xACFC, // 과, #69
+ 0xAD00, // 관, #95
+ 0xAD11, // 광, #235
+ 0xAD50, // 교, #128
+ 0xAD6C, // 구, #52
+ 0xAD6D, // 국, #85
+ 0xAD70, // 군, #293
+ 0xAD74, // 굴, #487
+ 0xAD81, // 궁, #441
+ 0xAD8C, // 권, #192
+ 0xADC0, // 귀, #386
+ 0xADDC, // 규, #367
+ 0xADF8, // 그, #30
+ 0xADF9, // 극, #424
+ 0xADFC, // 근, #241
+ 0xAE00, // 글, #61
+ 0xAE08, // 금, #138
+ 0xAE09, // 급, #269
+ 0xAE30, // 기, #3
+ 0xAE34, // 긴, #465
+ 0xAE38, // 길, #297
+ 0xAE40, // 김, #205
+ 0xAE4C, // 까, #171
+ 0xAED8, // 께, #273
+ 0xAF43, // 꽃, #475
+ 0xB05D, // 끝, #505
+ 0xB07C, // 끼, #490
+ 0xB098, // 나, #39
+ 0xB09C, // 난, #274
+ 0xB0A0, // 날, #292
+ 0xB0A8, // 남, #139
+ 0xB0B4, // 내, #56
+ 0xB108, // 너, #272
+ 0xB110, // 널, #476
+ 0xB118, // 넘, #492
+ 0xB124, // 네, #100
+ 0xB137, // 넷, #329
+ 0xB140, // 녀, #288
+ 0xB144, // 년, #151
+ 0xB178, // 노, #149
+ 0xB17C, // 논, #491
+ 0xB180, // 놀, #464
+ 0xB18D, // 농, #442
+ 0xB204, // 누, #319
+ 0xB208, // 눈, #383
+ 0xB274, // 뉴, #173
+ 0xB290, // 느, #368
+ 0xB294, // 는, #5
+ 0xB298, // 늘, #322
+ 0xB2A5, // 능, #190
+ 0xB2C8, // 니, #16
+ 0xB2D8, // 님, #153
+ 0xB2E4, // 다, #2
+ 0xB2E8, // 단, #134
+ 0xB2EB, // 닫, #195
+ 0xB2EC, // 달, #243
+ 0xB2F4, // 담, #254
+ 0xB2F5, // 답, #287
+ 0xB2F9, // 당, #159
+ 0xB300, // 대, #33
+ 0xB313, // 댓, #303
+ 0xB354, // 더, #140
+ 0xB358, // 던, #252
+ 0xB367, // 덧, #463
+ 0xB370, // 데, #104
+ 0xB378, // 델, #429
+ 0xB3C4, // 도, #25
+ 0xB3C5, // 독, #301
+ 0xB3CC, // 돌, #309
+ 0xB3D9, // 동, #58
+ 0xB418, // 되, #82
+ 0xB41C, // 된, #189
+ 0xB420, // 될, #408
+ 0xB429, // 됩, #332
+ 0xB450, // 두, #199
+ 0xB4A4, // 뒤, #496
+ 0xB4DC, // 드, #40
+ 0xB4E0, // 든, #283
+ 0xB4E4, // 들, #54
+ 0xB4EF, // 듯, #478
+ 0xB4F1, // 등, #90
+ 0xB514, // 디, #133
+ 0xB529, // 딩, #462
+ 0xB530, // 따, #333
+ 0xB54C, // 때, #240
+ 0xB610, // 또, #313
+ 0xB77C, // 라, #42
+ 0xB77D, // 락, #355
+ 0xB780, // 란, #290
+ 0xB78C, // 람, #246
+ 0xB78D, // 랍, #420
+ 0xB791, // 랑, #270
+ 0xB798, // 래, #174
+ 0xB799, // 랙, #381
+ 0xB79C, // 랜, #357
+ 0xB7A8, // 램, #359
+ 0xB7A9, // 랩, #402
+ 0xB7C9, // 량, #346
+ 0xB7EC, // 러, #130
+ 0xB7F0, // 런, #312
+ 0xB7FC, // 럼, #327
+ 0xB7FD, // 럽, #447
+ 0xB807, // 렇, #412
+ 0xB808, // 레, #114
+ 0xB80C, // 렌, #395
+ 0xB824, // 려, #158
+ 0xB825, // 력, #194
+ 0xB828, // 련, #326
+ 0xB839, // 령, #389
+ 0xB85C, // 로, #4
+ 0xB85D, // 록, #84
+ 0xB860, // 론, #366
+ 0xB8CC, // 료, #154
+ 0xB8E8, // 루, #236
+ 0xB958, // 류, #265
+ 0xB974, // 르, #212
+ 0xB978, // 른, #250
+ 0xB97C, // 를, #35
+ 0xB984, // 름, #276
+ 0xB9AC, // 리, #19
+ 0xB9AD, // 릭, #394
+ 0xB9B0, // 린, #259
+ 0xB9B4, // 릴, #485
+ 0xB9BC, // 림, #305
+ 0xB9BD, // 립, #217
+ 0xB9C1, // 링, #351
+ 0xB9C8, // 마, #67
+ 0xB9C9, // 막, #310
+ 0xB9CC, // 만, #65
+ 0xB9CE, // 많, #257
+ 0xB9D0, // 말, #188
+ 0xB9DB, // 맛, #397
+ 0xB9DD, // 망, #370
+ 0xB9DE, // 맞, #399
+ 0xB9E4, // 매, #125
+ 0xB9E8, // 맨, #422
+ 0xBA38, // 머, #311
+ 0xBA39, // 먹, #377
+ 0xBA3C, // 먼, #469
+ 0xBA54, // 메, #147
+ 0xBA70, // 며, #191
+ 0xBA74, // 면, #72
+ 0xBA85, // 명, #131
+ 0xBAA8, // 모, #73
+ 0xBAA9, // 목, #157
+ 0xBAB0, // 몰, #401
+ 0xBAB8, // 몸, #437
+ 0xBABB, // 못, #336
+ 0xBB34, // 무, #80
+ 0xBB38, // 문, #57
+ 0xBB3C, // 물, #94
+ 0xBBA4, // 뮤, #431
+ 0xBBF8, // 미, #76
+ 0xBBFC, // 민, #200
+ 0xBC00, // 밀, #308
+ 0xBC0F, // 및, #249
+ 0xBC14, // 바, #89
+ 0xBC15, // 박, #226
+ 0xBC18, // 반, #175
+ 0xBC1B, // 받, #248
+ 0xBC1C, // 발, #164
+ 0xBC29, // 방, #92
+ 0xBC30, // 배, #162
+ 0xBC31, // 백, #256
+ 0xBC84, // 버, #111
+ 0xBC88, // 번, #167
+ 0xBC8C, // 벌, #423
+ 0xBC94, // 범, #427
+ 0xBC95, // 법, #207
+ 0xBCA0, // 베, #281
+ 0xBCA4, // 벤, #378
+ 0xBCA8, // 벨, #387
+ 0xBCC0, // 변, #253
+ 0xBCC4, // 별, #262
+ 0xBCD1, // 병, #340
+ 0xBCF4, // 보, #20
+ 0xBCF5, // 복, #204
+ 0xBCF8, // 본, #182
+ 0xBCFC, // 볼, #385
+ 0xBD09, // 봉, #405
+ 0xBD80, // 부, #46
+ 0xBD81, // 북, #261
+ 0xBD84, // 분, #105
+ 0xBD88, // 불, #225
+ 0xBDF0, // 뷰, #350
+ 0xBE0C, // 브, #214
+ 0xBE14, // 블, #99
+ 0xBE44, // 비, #55
+ 0xBE4C, // 빌, #510
+ 0xBE60, // 빠, #398
+ 0xC0AC, // 사, #14
+ 0xC0AD, // 삭, #342
+ 0xC0B0, // 산, #121
+ 0xC0B4, // 살, #279
+ 0xC0BC, // 삼, #348
+ 0xC0C1, // 상, #41
+ 0xC0C8, // 새, #282
+ 0xC0C9, // 색, #181
+ 0xC0DD, // 생, #109
+ 0xC11C, // 서, #21
+ 0xC11D, // 석, #234
+ 0xC120, // 선, #107
+ 0xC124, // 설, #170
+ 0xC131, // 성, #50
+ 0xC138, // 세, #60
+ 0xC139, // 섹, #456
+ 0xC13C, // 센, #267
+ 0xC154, // 셔, #455
+ 0xC158, // 션, #237
+ 0xC15C, // 셜, #448
+ 0xC168, // 셨, #421
+ 0xC18C, // 소, #51
+ 0xC18D, // 속, #219
+ 0xC190, // 손, #323
+ 0xC1A1, // 송, #203
+ 0xC1C4, // 쇄, #501
+ 0xC1FC, // 쇼, #364
+ 0xC218, // 수, #27
+ 0xC219, // 숙, #467
+ 0xC21C, // 순, #258
+ 0xC220, // 술, #302
+ 0xC26C, // 쉬, #511
+ 0xC288, // 슈, #384
+ 0xC2A4, // 스, #11
+ 0xC2AC, // 슬, #438
+ 0xC2B4, // 슴, #504
+ 0xC2B5, // 습, #77
+ 0xC2B9, // 승, #299
+ 0xC2DC, // 시, #13
+ 0xC2DD, // 식, #137
+ 0xC2E0, // 신, #47
+ 0xC2E4, // 실, #132
+ 0xC2EC, // 심, #196
+ 0xC2ED, // 십, #482
+ 0xC2F6, // 싶, #352
+ 0xC2F8, // 싸, #419
+ 0xC4F0, // 쓰, #278
+ 0xC528, // 씨, #360
+ 0xC544, // 아, #23
+ 0xC545, // 악, #296
+ 0xC548, // 안, #71
+ 0xC54A, // 않, #209
+ 0xC54C, // 알, #222
+ 0xC554, // 암, #460
+ 0xC558, // 았, #349
+ 0xC559, // 앙, #473
+ 0xC55E, // 앞, #434
+ 0xC560, // 애, #271
+ 0xC561, // 액, #415
+ 0xC571, // 앱, #477
+ 0xC57C, // 야, #124
+ 0xC57D, // 약, #229
+ 0xC591, // 양, #177
+ 0xC5B4, // 어, #24
+ 0xC5B5, // 억, #407
+ 0xC5B8, // 언, #294
+ 0xC5BC, // 얼, #356
+ 0xC5C4, // 엄, #426
+ 0xC5C5, // 업, #118
+ 0xC5C6, // 없, #178
+ 0xC5C8, // 었, #165
+ 0xC5D0, // 에, #9
+ 0xC5D4, // 엔, #375
+ 0xC5D8, // 엘, #506
+ 0xC5EC, // 여, #66
+ 0xC5ED, // 역, #186
+ 0xC5EE, // 엮, #488
+ 0xC5F0, // 연, #96
+ 0xC5F4, // 열, #266
+ 0xC5FC, // 염, #449
+ 0xC600, // 였, #374
+ 0xC601, // 영, #83
+ 0xC608, // 예, #168
+ 0xC624, // 오, #75
+ 0xC628, // 온, #300
+ 0xC62C, // 올, #306
+ 0xC640, // 와, #119
+ 0xC644, // 완, #361
+ 0xC654, // 왔, #489
+ 0xC655, // 왕, #418
+ 0xC678, // 외, #218
+ 0xC694, // 요, #43
+ 0xC695, // 욕, #479
+ 0xC6A9, // 용, #48
+ 0xC6B0, // 우, #64
+ 0xC6B1, // 욱, #503
+ 0xC6B4, // 운, #108
+ 0xC6B8, // 울, #223
+ 0xC6C0, // 움, #317
+ 0xC6C3, // 웃, #404
+ 0xC6CC, // 워, #280
+ 0xC6D0, // 원, #45
+ 0xC6D4, // 월, #150
+ 0xC6E8, // 웨, #446
+ 0xC6F9, // 웹, #500
+ 0xC704, // 위, #78
+ 0xC720, // 유, #81
+ 0xC721, // 육, #321
+ 0xC724, // 윤, #416
+ 0xC73C, // 으, #49
+ 0xC740, // 은, #31
+ 0xC744, // 을, #17
+ 0xC74C, // 음, #112
+ 0xC751, // 응, #461
+ 0xC758, // 의, #8
+ 0xC774, // 이, #1
+ 0xC775, // 익, #403
+ 0xC778, // 인, #18
+ 0xC77C, // 일, #28
+ 0xC784, // 임, #160
+ 0xC785, // 입, #93
+ 0xC788, // 있, #44
+ 0xC790, // 자, #22
+ 0xC791, // 작, #88
+ 0xC798, // 잘, #347
+ 0xC7A1, // 잡, #372
+ 0xC7A5, // 장, #53
+ 0xC7AC, // 재, #120
+ 0xC7C1, // 쟁, #483
+ 0xC800, // 저, #98
+ 0xC801, // 적, #97
+ 0xC804, // 전, #34
+ 0xC808, // 절, #320
+ 0xC810, // 점, #201
+ 0xC811, // 접, #331
+ 0xC815, // 정, #26
+ 0xC81C, // 제, #29
+ 0xC838, // 져, #414
+ 0xC870, // 조, #86
+ 0xC871, // 족, #373
+ 0xC874, // 존, #432
+ 0xC880, // 좀, #470
+ 0xC885, // 종, #208
+ 0xC88B, // 좋, #239
+ 0xC8E0, // 죠, #451
+ 0xC8FC, // 주, #38
+ 0xC8FD, // 죽, #471
+ 0xC900, // 준, #286
+ 0xC904, // 줄, #392
+ 0xC911, // 중, #103
+ 0xC988, // 즈, #255
+ 0xC98C, // 즌, #507
+ 0xC990, // 즐, #371
+ 0xC99D, // 증, #260
+ 0xC9C0, // 지, #10
+ 0xC9C1, // 직, #216
+ 0xC9C4, // 진, #79
+ 0xC9C8, // 질, #238
+ 0xC9D1, // 집, #206
+ 0xC9DC, // 짜, #411
+ 0xC9F8, // 째, #494
+ 0xCABD, // 쪽, #435
+ 0xCC28, // 차, #146
+ 0xCC29, // 착, #443
+ 0xCC2C, // 찬, #481
+ 0xCC30, // 찰, #440
+ 0xCC38, // 참, #343
+ 0xCC3D, // 창, #304
+ 0xCC3E, // 찾, #335
+ 0xCC44, // 채, #284
+ 0xCC45, // 책, #298
+ 0xCC98, // 처, #242
+ 0xCC9C, // 천, #143
+ 0xCCA0, // 철, #380
+ 0xCCA8, // 첨, #452
+ 0xCCAB, // 첫, #484
+ 0xCCAD, // 청, #197
+ 0xCCB4, // 체, #126
+ 0xCCD0, // 쳐, #472
+ 0xCD08, // 초, #220
+ 0xCD1D, // 총, #406
+ 0xCD5C, // 최, #179
+ 0xCD94, // 추, #136
+ 0xCD95, // 축, #337
+ 0xCD9C, // 출, #166
+ 0xCDA9, // 충, #369
+ 0xCDE8, // 취, #210
+ 0xCE20, // 츠, #215
+ 0xCE21, // 측, #468
+ 0xCE35, // 층, #512
+ 0xCE58, // 치, #102
+ 0xCE5C, // 친, #325
+ 0xCE68, // 침, #263
+ 0xCE74, // 카, #115
+ 0xCE7C, // 칼, #466
+ 0xCE90, // 캐, #454
+ 0xCEE4, // 커, #285
+ 0xCEE8, // 컨, #328
+ 0xCEF4, // 컴, #417
+ 0xCF00, // 케, #339
+ 0xCF13, // 켓, #509
+ 0xCF1C, // 켜, #508
+ 0xCF54, // 코, #193
+ 0xCF58, // 콘, #391
+ 0xCFE0, // 쿠, #393
+ 0xD035, // 퀵, #453
+ 0xD06C, // 크, #101
+ 0xD070, // 큰, #495
+ 0xD074, // 클, #289
+ 0xD0A4, // 키, #230
+ 0xD0C0, // 타, #127
+ 0xD0C1, // 탁, #314
+ 0xD0C4, // 탄, #450
+ 0xD0C8, // 탈, #436
+ 0xD0DC, // 태, #221
+ 0xD0DD, // 택, #275
+ 0xD130, // 터, #70
+ 0xD14C, // 테, #213
+ 0xD150, // 텐, #324
+ 0xD154, // 텔, #430
+ 0xD15C, // 템, #382
+ 0xD1A0, // 토, #145
+ 0xD1B5, // 통, #156
+ 0xD22C, // 투, #227
+ 0xD2B8, // 트, #37
+ 0xD2B9, // 특, #247
+ 0xD2F0, // 티, #187
+ 0xD305, // 팅, #410
+ 0xD30C, // 파, #141
+ 0xD310, // 판, #163
+ 0xD314, // 팔, #499
+ 0xD328, // 패, #307
+ 0xD32C, // 팬, #459
+ 0xD338, // 팸, #433
+ 0xD37C, // 퍼, #344
+ 0xD398, // 페, #172
+ 0xD3B8, // 편, #251
+ 0xD3C9, // 평, #291
+ 0xD3EC, // 포, #68
+ 0xD3ED, // 폭, #445
+ 0xD3F0, // 폰, #318
+ 0xD45C, // 표, #232
+ 0xD480, // 풀, #497
+ 0xD488, // 품, #113
+ 0xD48D, // 풍, #425
+ 0xD504, // 프, #110
+ 0xD508, // 픈, #498
+ 0xD50C, // 플, #211
+ 0xD53C, // 피, #169
+ 0xD544, // 필, #295
+ 0xD551, // 핑, #376
+ 0xD558, // 하, #7
+ 0xD559, // 학, #129
+ 0xD55C, // 한, #15
+ 0xD560, // 할, #144
+ 0xD568, // 함, #152
+ 0xD569, // 합, #123
+ 0xD56D, // 항, #268
+ 0xD574, // 해, #32
+ 0xD588, // 했, #180
+ 0xD589, // 행, #135
+ 0xD5A5, // 향, #345
+ 0xD5C8, // 허, #396
+ 0xD5D8, // 험, #316
+ 0xD5E4, // 헤, #474
+ 0xD604, // 현, #185
+ 0xD611, // 협, #315
+ 0xD615, // 형, #244
+ 0xD61C, // 혜, #428
+ 0xD638, // 호, #117
+ 0xD63C, // 혼, #358
+ 0xD648, // 홈, #330
+ 0xD64D, // 홍, #363
+ 0xD654, // 화, #63
+ 0xD655, // 확, #183
+ 0xD658, // 환, #224
+ 0xD65C, // 활, #277
+ 0xD669, // 황, #353
+ 0xD68C, // 회, #74
+ 0xD68D, // 획, #458
+ 0xD69F, // 횟, #409
+ 0xD6A8, // 효, #400
+ 0xD6C4, // 후, #176
+ 0xD6C8, // 훈, #486
+ 0xD734, // 휴, #365
+ 0xD754, // 흔, #480
+ 0xD76C, // 희, #334
+ 0xD788, // 히, #228
+ 0xD798, // 힘, #502
+};
+// the percentage of the sample covered by the above characters
+static const float frequent_ko_coverage=0.948157021464184;
+
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index acfaea0..f3f3e15 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -89,7 +89,7 @@ public:
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- size_t frameCount,
+ size_t *pFrameCount,
track_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
@@ -106,6 +106,7 @@ public:
data.writeInt32(sampleRate);
data.writeInt32(format);
data.writeInt32(channelMask);
+ size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
data.writeInt32(frameCount);
track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
data.writeInt32(lFlags);
@@ -117,7 +118,7 @@ public:
}
data.writeInt32((int32_t) output);
data.writeInt32((int32_t) tid);
- int lSessionId = 0;
+ int lSessionId = AUDIO_SESSION_ALLOCATE;
if (sessionId != NULL) {
lSessionId = *sessionId;
}
@@ -127,6 +128,10 @@ public:
if (lStatus != NO_ERROR) {
ALOGE("createTrack error: %s", strerror(-lStatus));
} else {
+ frameCount = reply.readInt32();
+ if (pFrameCount != NULL) {
+ *pFrameCount = frameCount;
+ }
lFlags = reply.readInt32();
if (flags != NULL) {
*flags = lFlags;
@@ -138,8 +143,19 @@ public:
name = reply.readString8();
lStatus = reply.readInt32();
track = interface_cast<IAudioTrack>(reply.readStrongBinder());
+ if (lStatus == NO_ERROR) {
+ if (track == 0) {
+ ALOGE("createTrack should have returned an IAudioTrack");
+ lStatus = UNKNOWN_ERROR;
+ }
+ } else {
+ if (track != 0) {
+ ALOGE("createTrack returned an IAudioTrack but with status %d", lStatus);
+ track.clear();
+ }
+ }
}
- if (status) {
+ if (status != NULL) {
*status = lStatus;
}
return track;
@@ -150,7 +166,7 @@ public:
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
- size_t frameCount,
+ size_t *pFrameCount,
track_flags_t *flags,
pid_t tid,
int *sessionId,
@@ -163,11 +179,12 @@ public:
data.writeInt32(sampleRate);
data.writeInt32(format);
data.writeInt32(channelMask);
+ size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
data.writeInt32(frameCount);
track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
data.writeInt32(lFlags);
data.writeInt32((int32_t) tid);
- int lSessionId = 0;
+ int lSessionId = AUDIO_SESSION_ALLOCATE;
if (sessionId != NULL) {
lSessionId = *sessionId;
}
@@ -176,6 +193,10 @@ public:
if (lStatus != NO_ERROR) {
ALOGE("openRecord error: %s", strerror(-lStatus));
} else {
+ frameCount = reply.readInt32();
+ if (pFrameCount != NULL) {
+ *pFrameCount = frameCount;
+ }
lFlags = reply.readInt32();
if (flags != NULL) {
*flags = lFlags;
@@ -198,7 +219,7 @@ public:
}
}
}
- if (status) {
+ if (status != NULL) {
*status = lStatus;
}
return record;
@@ -415,15 +436,25 @@ public:
audio_io_handle_t output = (audio_io_handle_t) reply.readInt32();
ALOGV("openOutput() returned output, %d", output);
devices = (audio_devices_t)reply.readInt32();
- if (pDevices != NULL) *pDevices = devices;
+ if (pDevices != NULL) {
+ *pDevices = devices;
+ }
samplingRate = reply.readInt32();
- if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
+ if (pSamplingRate != NULL) {
+ *pSamplingRate = samplingRate;
+ }
format = (audio_format_t) reply.readInt32();
- if (pFormat != NULL) *pFormat = format;
+ if (pFormat != NULL) {
+ *pFormat = format;
+ }
channelMask = (audio_channel_mask_t)reply.readInt32();
- if (pChannelMask != NULL) *pChannelMask = channelMask;
+ if (pChannelMask != NULL) {
+ *pChannelMask = channelMask;
+ }
latency = reply.readInt32();
- if (pLatencyMs != NULL) *pLatencyMs = latency;
+ if (pLatencyMs != NULL) {
+ *pLatencyMs = latency;
+ }
return output;
}
@@ -487,13 +518,21 @@ public:
remote()->transact(OPEN_INPUT, data, &reply);
audio_io_handle_t input = (audio_io_handle_t) reply.readInt32();
devices = (audio_devices_t)reply.readInt32();
- if (pDevices != NULL) *pDevices = devices;
+ if (pDevices != NULL) {
+ *pDevices = devices;
+ }
samplingRate = reply.readInt32();
- if (pSamplingRate != NULL) *pSamplingRate = samplingRate;
+ if (pSamplingRate != NULL) {
+ *pSamplingRate = samplingRate;
+ }
format = (audio_format_t) reply.readInt32();
- if (pFormat != NULL) *pFormat = format;
+ if (pFormat != NULL) {
+ *pFormat = format;
+ }
channelMask = (audio_channel_mask_t)reply.readInt32();
- if (pChannelMask != NULL) *pChannelMask = channelMask;
+ if (pChannelMask != NULL) {
+ *pChannelMask = channelMask;
+ }
return input;
}
@@ -535,24 +574,27 @@ public:
status_t status = reply.readInt32();
if (status == NO_ERROR) {
uint32_t tmp = reply.readInt32();
- if (halFrames) {
+ if (halFrames != NULL) {
*halFrames = tmp;
}
tmp = reply.readInt32();
- if (dspFrames) {
+ if (dspFrames != NULL) {
*dspFrames = tmp;
}
}
return status;
}
- virtual size_t getInputFramesLost(audio_io_handle_t ioHandle) const
+ virtual uint32_t getInputFramesLost(audio_io_handle_t ioHandle) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32((int32_t) ioHandle);
- remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
- return reply.readInt32();
+ status_t status = remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
+ if (status != NO_ERROR) {
+ return 0;
+ }
+ return (uint32_t) reply.readInt32();
}
virtual int newAudioSessionId()
@@ -657,7 +699,7 @@ public:
if (pDesc == NULL) {
return effect;
- if (status) {
+ if (status != NULL) {
*status = BAD_VALUE;
}
}
@@ -675,7 +717,7 @@ public:
} else {
lStatus = reply.readInt32();
int tmp = reply.readInt32();
- if (id) {
+ if (id != NULL) {
*id = tmp;
}
tmp = reply.readInt32();
@@ -685,7 +727,7 @@ public:
effect = interface_cast<IEffect>(reply.readStrongBinder());
reply.read(pDesc, sizeof(effect_descriptor_t));
}
- if (status) {
+ if (status != NULL) {
*status = lStatus;
}
@@ -775,9 +817,11 @@ status_t BnAudioFlinger::onTransact(
} else {
track = createTrack(
(audio_stream_type_t) streamType, sampleRate, format,
- channelMask, frameCount, &flags, buffer, output, tid,
+ channelMask, &frameCount, &flags, buffer, output, tid,
&sessionId, name, clientUid, &status);
+ LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR));
}
+ reply->writeInt32(frameCount);
reply->writeInt32(flags);
reply->writeInt32(sessionId);
reply->writeString8(name);
@@ -797,8 +841,9 @@ status_t BnAudioFlinger::onTransact(
int sessionId = data.readInt32();
status_t status;
sp<IAudioRecord> record = openRecord(input,
- sampleRate, format, channelMask, frameCount, &flags, tid, &sessionId, &status);
+ sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, &status);
LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR));
+ reply->writeInt32(frameCount);
reply->writeInt32(flags);
reply->writeInt32(sessionId);
reply->writeInt32(status);
@@ -1026,7 +1071,7 @@ status_t BnAudioFlinger::onTransact(
case GET_INPUT_FRAMES_LOST: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
audio_io_handle_t ioHandle = (audio_io_handle_t) data.readInt32();
- reply->writeInt32(getInputFramesLost(ioHandle));
+ reply->writeInt32((int32_t) getInputFramesLost(ioHandle));
return NO_ERROR;
} break;
case NEW_AUDIO_SESSION_ID: {
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 4a7de65..9866d70 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -50,6 +50,9 @@ public:
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
+ if (cblk != 0 && cblk->pointer() == NULL) {
+ cblk.clear();
+ }
}
return cblk;
}
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 3cd9cfd..ffc21fc 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -60,6 +60,9 @@ public:
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
+ if (cblk != 0 && cblk->pointer() == NULL) {
+ cblk.clear();
+ }
}
return cblk;
}
@@ -122,6 +125,9 @@ public:
status = reply.readInt32();
if (status == NO_ERROR) {
*buffer = interface_cast<IMemory>(reply.readStrongBinder());
+ if (*buffer != 0 && (*buffer)->pointer() == NULL) {
+ (*buffer).clear();
+ }
}
}
return status;
diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp
index a303a8f..b94012a 100644
--- a/media/libmedia/IEffect.cpp
+++ b/media/libmedia/IEffect.cpp
@@ -117,6 +117,9 @@ public:
status_t status = remote()->transact(GET_CBLK, data, &reply);
if (status == NO_ERROR) {
cblk = interface_cast<IMemory>(reply.readStrongBinder());
+ if (cblk != 0 && cblk->pointer() == NULL) {
+ cblk.clear();
+ }
}
return cblk;
}
diff --git a/media/libmedia/IMediaDeathNotifier.cpp b/media/libmedia/IMediaDeathNotifier.cpp
index 9db5b1b..10b4934 100644
--- a/media/libmedia/IMediaDeathNotifier.cpp
+++ b/media/libmedia/IMediaDeathNotifier.cpp
@@ -75,7 +75,7 @@ IMediaDeathNotifier::removeObitRecipient(const wp<IMediaDeathNotifier>& recipien
}
void
-IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who) {
+IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
ALOGW("media server died");
// Need to do this with the lock held
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/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 8319cd7..1074da9 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -81,8 +81,14 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
{"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
};
+#if LOG_NDEBUG
+#define UNUSED __unused
+#else
+#define UNUSED
+#endif
+
/*static*/ void
-MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
+MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec UNUSED)
{
ALOGV("video codec:");
ALOGV("codec = %d", codec.mCodec);
@@ -93,7 +99,7 @@ MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec)
}
/*static*/ void
-MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
+MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec UNUSED)
{
ALOGV("audio codec:");
ALOGV("codec = %d", codec.mCodec);
@@ -103,7 +109,7 @@ MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec)
}
/*static*/ void
-MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
+MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUSED)
{
ALOGV("video encoder cap:");
ALOGV("codec = %d", cap.mCodec);
@@ -114,7 +120,7 @@ MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap)
}
/*static*/ void
-MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
+MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap UNUSED)
{
ALOGV("audio encoder cap:");
ALOGV("codec = %d", cap.mCodec);
@@ -124,21 +130,21 @@ MediaProfiles::logAudioEncoderCap(const MediaProfiles::AudioEncoderCap& cap)
}
/*static*/ void
-MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap)
+MediaProfiles::logVideoDecoderCap(const MediaProfiles::VideoDecoderCap& cap UNUSED)
{
ALOGV("video decoder cap:");
ALOGV("codec = %d", cap.mCodec);
}
/*static*/ void
-MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap)
+MediaProfiles::logAudioDecoderCap(const MediaProfiles::AudioDecoderCap& cap UNUSED)
{
ALOGV("audio codec cap:");
ALOGV("codec = %d", cap.mCodec);
}
/*static*/ void
-MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap)
+MediaProfiles::logVideoEditorCap(const MediaProfiles::VideoEditorCap& cap UNUSED)
{
ALOGV("videoeditor cap:");
ALOGV("mMaxInputFrameWidth = %d", cap.mMaxInputFrameWidth);
diff --git a/media/libmedia/MediaScannerClient.cpp b/media/libmedia/MediaScannerClient.cpp
index 93a4a4c..1661f04 100644
--- a/media/libmedia/MediaScannerClient.cpp
+++ b/media/libmedia/MediaScannerClient.cpp
@@ -14,217 +14,57 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaScannerClient"
+#include <utils/Log.h>
+
#include <media/mediascanner.h>
+#include "CharacterEncodingDetector.h"
#include "StringArray.h"
-#include "autodetect.h"
-#include "unicode/ucnv.h"
-#include "unicode/ustring.h"
-
namespace android {
MediaScannerClient::MediaScannerClient()
- : mNames(NULL),
- mValues(NULL),
- mLocaleEncoding(kEncodingNone)
+ : mEncodingDetector(NULL)
{
}
MediaScannerClient::~MediaScannerClient()
{
- delete mNames;
- delete mValues;
+ delete mEncodingDetector;
}
void MediaScannerClient::setLocale(const char* locale)
{
- if (!locale) return;
-
- if (!strncmp(locale, "ja", 2))
- mLocaleEncoding = kEncodingShiftJIS;
- else if (!strncmp(locale, "ko", 2))
- mLocaleEncoding = kEncodingEUCKR;
- else if (!strncmp(locale, "zh", 2)) {
- if (!strcmp(locale, "zh_CN")) {
- // simplified chinese for mainland China
- mLocaleEncoding = kEncodingGBK;
- } else {
- // assume traditional for non-mainland Chinese locales (Taiwan, Hong Kong, Singapore)
- mLocaleEncoding = kEncodingBig5;
- }
- }
+ mLocale = locale; // not currently used
}
void MediaScannerClient::beginFile()
{
- mNames = new StringArray;
- mValues = new StringArray;
+ delete mEncodingDetector;
+ mEncodingDetector = new CharacterEncodingDetector();
}
status_t MediaScannerClient::addStringTag(const char* name, const char* value)
{
- if (mLocaleEncoding != kEncodingNone) {
- // don't bother caching strings that are all ASCII.
- // call handleStringTag directly instead.
- // check to see if value (which should be utf8) has any non-ASCII characters
- bool nonAscii = false;
- const char* chp = value;
- char ch;
- while ((ch = *chp++)) {
- if (ch & 0x80) {
- nonAscii = true;
- break;
- }
- }
-
- if (nonAscii) {
- // save the strings for later so they can be used for native encoding detection
- mNames->push_back(name);
- mValues->push_back(value);
- return OK;
- }
- // else fall through
- }
-
- // autodetection is not necessary, so no need to cache the values
- // pass directly to the client instead
- return handleStringTag(name, value);
-}
-
-static uint32_t possibleEncodings(const char* s)
-{
- uint32_t result = kEncodingAll;
- // if s contains a native encoding, then it was mistakenly encoded in utf8 as if it were latin-1
- // so we need to reverse the latin-1 -> utf8 conversion to get the native chars back
- uint8_t ch1, ch2;
- uint8_t* chp = (uint8_t *)s;
-
- while ((ch1 = *chp++)) {
- if (ch1 & 0x80) {
- ch2 = *chp++;
- ch1 = ((ch1 << 6) & 0xC0) | (ch2 & 0x3F);
- // ch1 is now the first byte of the potential native char
-
- ch2 = *chp++;
- if (ch2 & 0x80)
- ch2 = ((ch2 << 6) & 0xC0) | (*chp++ & 0x3F);
- // ch2 is now the second byte of the potential native char
- int ch = (int)ch1 << 8 | (int)ch2;
- result &= findPossibleEncodings(ch);
- }
- // else ASCII character, which could be anything
- }
-
- return result;
-}
-
-void MediaScannerClient::convertValues(uint32_t encoding)
-{
- const char* enc = NULL;
- switch (encoding) {
- case kEncodingShiftJIS:
- enc = "shift-jis";
- break;
- case kEncodingGBK:
- enc = "gbk";
- break;
- case kEncodingBig5:
- enc = "Big5";
- break;
- case kEncodingEUCKR:
- enc = "EUC-KR";
- break;
- }
-
- if (enc) {
- UErrorCode status = U_ZERO_ERROR;
-
- UConverter *conv = ucnv_open(enc, &status);
- if (U_FAILURE(status)) {
- ALOGE("could not create UConverter for %s", enc);
- return;
- }
- UConverter *utf8Conv = ucnv_open("UTF-8", &status);
- if (U_FAILURE(status)) {
- ALOGE("could not create UConverter for UTF-8");
- ucnv_close(conv);
- return;
- }
-
- // for each value string, convert from native encoding to UTF-8
- for (int i = 0; i < mNames->size(); i++) {
- // first we need to untangle the utf8 and convert it back to the original bytes
- // since we are reducing the length of the string, we can do this in place
- uint8_t* src = (uint8_t *)mValues->getEntry(i);
- int len = strlen((char *)src);
- uint8_t* dest = src;
-
- uint8_t uch;
- while ((uch = *src++)) {
- if (uch & 0x80)
- *dest++ = ((uch << 6) & 0xC0) | (*src++ & 0x3F);
- else
- *dest++ = uch;
- }
- *dest = 0;
-
- // now convert from native encoding to UTF-8
- const char* source = mValues->getEntry(i);
- int targetLength = len * 3 + 1;
- char* buffer = new char[targetLength];
- // don't normally check for NULL, but in this case targetLength may be large
- if (!buffer)
- break;
- char* target = buffer;
-
- ucnv_convertEx(utf8Conv, conv, &target, target + targetLength,
- &source, (const char *)dest, NULL, NULL, NULL, NULL, TRUE, TRUE, &status);
- if (U_FAILURE(status)) {
- ALOGE("ucnv_convertEx failed: %d", status);
- mValues->setEntry(i, "???");
- } else {
- // zero terminate
- *target = 0;
- mValues->setEntry(i, buffer);
- }
-
- delete[] buffer;
- }
-
- ucnv_close(conv);
- ucnv_close(utf8Conv);
- }
+ mEncodingDetector->addTag(name, value);
+ return OK;
}
void MediaScannerClient::endFile()
{
- if (mLocaleEncoding != kEncodingNone) {
- int size = mNames->size();
- uint32_t encoding = kEncodingAll;
-
- // compute a bit mask containing all possible encodings
- for (int i = 0; i < mNames->size(); i++)
- encoding &= possibleEncodings(mValues->getEntry(i));
-
- // if the locale encoding matches, then assume we have a native encoding.
- if (encoding & mLocaleEncoding)
- convertValues(mLocaleEncoding);
-
- // finally, push all name/value pairs to the client
- for (int i = 0; i < mNames->size(); i++) {
- status_t status = handleStringTag(mNames->getEntry(i), mValues->getEntry(i));
- if (status) {
- break;
- }
+ mEncodingDetector->detectAndConvert();
+
+ int size = mEncodingDetector->size();
+ if (size) {
+ for (int i = 0; i < size; i++) {
+ const char *name;
+ const char *value;
+ mEncodingDetector->getTag(i, &name, &value);
+ handleStringTag(name, value);
}
}
- // else addStringTag() has done all the work so we have nothing to do
-
- delete mNames;
- delete mValues;
- mNames = NULL;
- mValues = NULL;
}
} // namespace android
diff --git a/media/libmedia/SoundPool.cpp b/media/libmedia/SoundPool.cpp
index 22e9fad..4885b4f 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"
@@ -199,7 +200,7 @@ SoundChannel* SoundPool::findNextChannel(int channelID)
return NULL;
}
-int SoundPool::load(const char* path, int priority)
+int SoundPool::load(const char* path, int priority __unused)
{
ALOGV("load: path=%s, priority=%d", path, priority);
Mutex::Autolock lock(&mLock);
@@ -209,7 +210,7 @@ int SoundPool::load(const char* path, int priority)
return sample->sampleID();
}
-int SoundPool::load(int fd, int64_t offset, int64_t length, int priority)
+int SoundPool::load(int fd, int64_t offset, int64_t length, int priority __unused)
{
ALOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d",
fd, offset, length, priority);
@@ -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);
@@ -600,16 +608,15 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
// wrong audio audio buffer size (mAudioBufferSize)
unsigned long toggle = mToggle ^ 1;
void *userData = (void *)((unsigned long)this | toggle);
- uint32_t channels = (numChannels == 2) ?
- AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO;
+ audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(numChannels);
// do not create a new audio track if current track is compatible with sample parameters
#ifdef USE_SHARED_MEM_BUFFER
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- channels, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
+ channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
#else
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- channels, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
+ channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
bufferFrames);
#endif
oldTrack = mAudioTrack;
@@ -730,7 +737,8 @@ void SoundChannel::process(int event, void *info, unsigned long toggle)
count = b->size;
}
memcpy(q, p, count);
-// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count);
+// ALOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size,
+// count);
} else if (mPos < mAudioBufferSize) {
count = mAudioBufferSize - mPos;
if (count > b->size) {
diff --git a/media/libmedia/autodetect.cpp b/media/libmedia/autodetect.cpp
deleted file mode 100644
index be5c3b2..0000000
--- a/media/libmedia/autodetect.cpp
+++ /dev/null
@@ -1,885 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "autodetect.h"
-
-struct CharRange {
- uint16_t first;
- uint16_t last;
-};
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP932.TXT
-static const CharRange kShiftJISRanges[] = {
- { 0x8140, 0x817E },
- { 0x8180, 0x81AC },
- { 0x81B8, 0x81BF },
- { 0x81C8, 0x81CE },
- { 0x81DA, 0x81E8 },
- { 0x81F0, 0x81F7 },
- { 0x81FC, 0x81FC },
- { 0x824F, 0x8258 },
- { 0x8260, 0x8279 },
- { 0x8281, 0x829A },
- { 0x829F, 0x82F1 },
- { 0x8340, 0x837E },
- { 0x8380, 0x8396 },
- { 0x839F, 0x83B6 },
- { 0x83BF, 0x83D6 },
- { 0x8440, 0x8460 },
- { 0x8470, 0x847E },
- { 0x8480, 0x8491 },
- { 0x849F, 0x84BE },
- { 0x8740, 0x875D },
- { 0x875F, 0x8775 },
- { 0x877E, 0x877E },
- { 0x8780, 0x879C },
- { 0x889F, 0x88FC },
- { 0x8940, 0x897E },
- { 0x8980, 0x89FC },
- { 0x8A40, 0x8A7E },
- { 0x8A80, 0x8AFC },
- { 0x8B40, 0x8B7E },
- { 0x8B80, 0x8BFC },
- { 0x8C40, 0x8C7E },
- { 0x8C80, 0x8CFC },
- { 0x8D40, 0x8D7E },
- { 0x8D80, 0x8DFC },
- { 0x8E40, 0x8E7E },
- { 0x8E80, 0x8EFC },
- { 0x8F40, 0x8F7E },
- { 0x8F80, 0x8FFC },
- { 0x9040, 0x907E },
- { 0x9080, 0x90FC },
- { 0x9140, 0x917E },
- { 0x9180, 0x91FC },
- { 0x9240, 0x927E },
- { 0x9280, 0x92FC },
- { 0x9340, 0x937E },
- { 0x9380, 0x93FC },
- { 0x9440, 0x947E },
- { 0x9480, 0x94FC },
- { 0x9540, 0x957E },
- { 0x9580, 0x95FC },
- { 0x9640, 0x967E },
- { 0x9680, 0x96FC },
- { 0x9740, 0x977E },
- { 0x9780, 0x97FC },
- { 0x9840, 0x9872 },
- { 0x989F, 0x98FC },
- { 0x9940, 0x997E },
- { 0x9980, 0x99FC },
- { 0x9A40, 0x9A7E },
- { 0x9A80, 0x9AFC },
- { 0x9B40, 0x9B7E },
- { 0x9B80, 0x9BFC },
- { 0x9C40, 0x9C7E },
- { 0x9C80, 0x9CFC },
- { 0x9D40, 0x9D7E },
- { 0x9D80, 0x9DFC },
- { 0x9E40, 0x9E7E },
- { 0x9E80, 0x9EFC },
- { 0x9F40, 0x9F7E },
- { 0x9F80, 0x9FFC },
- { 0xE040, 0xE07E },
- { 0xE080, 0xE0FC },
- { 0xE140, 0xE17E },
- { 0xE180, 0xE1FC },
- { 0xE240, 0xE27E },
- { 0xE280, 0xE2FC },
- { 0xE340, 0xE37E },
- { 0xE380, 0xE3FC },
- { 0xE440, 0xE47E },
- { 0xE480, 0xE4FC },
- { 0xE540, 0xE57E },
- { 0xE580, 0xE5FC },
- { 0xE640, 0xE67E },
- { 0xE680, 0xE6FC },
- { 0xE740, 0xE77E },
- { 0xE780, 0xE7FC },
- { 0xE840, 0xE87E },
- { 0xE880, 0xE8FC },
- { 0xE940, 0xE97E },
- { 0xE980, 0xE9FC },
- { 0xEA40, 0xEA7E },
- { 0xEA80, 0xEAA4 },
- { 0xED40, 0xED7E },
- { 0xED80, 0xEDFC },
- { 0xEE40, 0xEE7E },
- { 0xEE80, 0xEEEC },
- { 0xEEEF, 0xEEFC },
- { 0xFA40, 0xFA7E },
- { 0xFA80, 0xFAFC },
- { 0xFB40, 0xFB7E },
- { 0xFB80, 0xFBFC },
- { 0xFC40, 0xFC4B },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP936.TXT
-static const CharRange kGBKRanges[] = {
- { 0x8140, 0x817E },
- { 0x8180, 0x81FE },
- { 0x8240, 0x827E },
- { 0x8280, 0x82FE },
- { 0x8340, 0x837E },
- { 0x8380, 0x83FE },
- { 0x8440, 0x847E },
- { 0x8480, 0x84FE },
- { 0x8540, 0x857E },
- { 0x8580, 0x85FE },
- { 0x8640, 0x867E },
- { 0x8680, 0x86FE },
- { 0x8740, 0x877E },
- { 0x8780, 0x87FE },
- { 0x8840, 0x887E },
- { 0x8880, 0x88FE },
- { 0x8940, 0x897E },
- { 0x8980, 0x89FE },
- { 0x8A40, 0x8A7E },
- { 0x8A80, 0x8AFE },
- { 0x8B40, 0x8B7E },
- { 0x8B80, 0x8BFE },
- { 0x8C40, 0x8C7E },
- { 0x8C80, 0x8CFE },
- { 0x8D40, 0x8D7E },
- { 0x8D80, 0x8DFE },
- { 0x8E40, 0x8E7E },
- { 0x8E80, 0x8EFE },
- { 0x8F40, 0x8F7E },
- { 0x8F80, 0x8FFE },
- { 0x9040, 0x907E },
- { 0x9080, 0x90FE },
- { 0x9140, 0x917E },
- { 0x9180, 0x91FE },
- { 0x9240, 0x927E },
- { 0x9280, 0x92FE },
- { 0x9340, 0x937E },
- { 0x9380, 0x93FE },
- { 0x9440, 0x947E },
- { 0x9480, 0x94FE },
- { 0x9540, 0x957E },
- { 0x9580, 0x95FE },
- { 0x9640, 0x967E },
- { 0x9680, 0x96FE },
- { 0x9740, 0x977E },
- { 0x9780, 0x97FE },
- { 0x9840, 0x987E },
- { 0x9880, 0x98FE },
- { 0x9940, 0x997E },
- { 0x9980, 0x99FE },
- { 0x9A40, 0x9A7E },
- { 0x9A80, 0x9AFE },
- { 0x9B40, 0x9B7E },
- { 0x9B80, 0x9BFE },
- { 0x9C40, 0x9C7E },
- { 0x9C80, 0x9CFE },
- { 0x9D40, 0x9D7E },
- { 0x9D80, 0x9DFE },
- { 0x9E40, 0x9E7E },
- { 0x9E80, 0x9EFE },
- { 0x9F40, 0x9F7E },
- { 0x9F80, 0x9FFE },
- { 0xA040, 0xA07E },
- { 0xA080, 0xA0FE },
- { 0xA1A1, 0xA1FE },
- { 0xA2A1, 0xA2AA },
- { 0xA2B1, 0xA2E2 },
- { 0xA2E5, 0xA2EE },
- { 0xA2F1, 0xA2FC },
- { 0xA3A1, 0xA3FE },
- { 0xA4A1, 0xA4F3 },
- { 0xA5A1, 0xA5F6 },
- { 0xA6A1, 0xA6B8 },
- { 0xA6C1, 0xA6D8 },
- { 0xA6E0, 0xA6EB },
- { 0xA6EE, 0xA6F2 },
- { 0xA6F4, 0xA6F5 },
- { 0xA7A1, 0xA7C1 },
- { 0xA7D1, 0xA7F1 },
- { 0xA840, 0xA87E },
- { 0xA880, 0xA895 },
- { 0xA8A1, 0xA8BB },
- { 0xA8BD, 0xA8BE },
- { 0xA8C0, 0xA8C0 },
- { 0xA8C5, 0xA8E9 },
- { 0xA940, 0xA957 },
- { 0xA959, 0xA95A },
- { 0xA95C, 0xA95C },
- { 0xA960, 0xA97E },
- { 0xA980, 0xA988 },
- { 0xA996, 0xA996 },
- { 0xA9A4, 0xA9EF },
- { 0xAA40, 0xAA7E },
- { 0xAA80, 0xAAA0 },
- { 0xAB40, 0xAB7E },
- { 0xAB80, 0xABA0 },
- { 0xAC40, 0xAC7E },
- { 0xAC80, 0xACA0 },
- { 0xAD40, 0xAD7E },
- { 0xAD80, 0xADA0 },
- { 0xAE40, 0xAE7E },
- { 0xAE80, 0xAEA0 },
- { 0xAF40, 0xAF7E },
- { 0xAF80, 0xAFA0 },
- { 0xB040, 0xB07E },
- { 0xB080, 0xB0FE },
- { 0xB140, 0xB17E },
- { 0xB180, 0xB1FE },
- { 0xB240, 0xB27E },
- { 0xB280, 0xB2FE },
- { 0xB340, 0xB37E },
- { 0xB380, 0xB3FE },
- { 0xB440, 0xB47E },
- { 0xB480, 0xB4FE },
- { 0xB540, 0xB57E },
- { 0xB580, 0xB5FE },
- { 0xB640, 0xB67E },
- { 0xB680, 0xB6FE },
- { 0xB740, 0xB77E },
- { 0xB780, 0xB7FE },
- { 0xB840, 0xB87E },
- { 0xB880, 0xB8FE },
- { 0xB940, 0xB97E },
- { 0xB980, 0xB9FE },
- { 0xBA40, 0xBA7E },
- { 0xBA80, 0xBAFE },
- { 0xBB40, 0xBB7E },
- { 0xBB80, 0xBBFE },
- { 0xBC40, 0xBC7E },
- { 0xBC80, 0xBCFE },
- { 0xBD40, 0xBD7E },
- { 0xBD80, 0xBDFE },
- { 0xBE40, 0xBE7E },
- { 0xBE80, 0xBEFE },
- { 0xBF40, 0xBF7E },
- { 0xBF80, 0xBFFE },
- { 0xC040, 0xC07E },
- { 0xC080, 0xC0FE },
- { 0xC140, 0xC17E },
- { 0xC180, 0xC1FE },
- { 0xC240, 0xC27E },
- { 0xC280, 0xC2FE },
- { 0xC340, 0xC37E },
- { 0xC380, 0xC3FE },
- { 0xC440, 0xC47E },
- { 0xC480, 0xC4FE },
- { 0xC540, 0xC57E },
- { 0xC580, 0xC5FE },
- { 0xC640, 0xC67E },
- { 0xC680, 0xC6FE },
- { 0xC740, 0xC77E },
- { 0xC780, 0xC7FE },
- { 0xC840, 0xC87E },
- { 0xC880, 0xC8FE },
- { 0xC940, 0xC97E },
- { 0xC980, 0xC9FE },
- { 0xCA40, 0xCA7E },
- { 0xCA80, 0xCAFE },
- { 0xCB40, 0xCB7E },
- { 0xCB80, 0xCBFE },
- { 0xCC40, 0xCC7E },
- { 0xCC80, 0xCCFE },
- { 0xCD40, 0xCD7E },
- { 0xCD80, 0xCDFE },
- { 0xCE40, 0xCE7E },
- { 0xCE80, 0xCEFE },
- { 0xCF40, 0xCF7E },
- { 0xCF80, 0xCFFE },
- { 0xD040, 0xD07E },
- { 0xD080, 0xD0FE },
- { 0xD140, 0xD17E },
- { 0xD180, 0xD1FE },
- { 0xD240, 0xD27E },
- { 0xD280, 0xD2FE },
- { 0xD340, 0xD37E },
- { 0xD380, 0xD3FE },
- { 0xD440, 0xD47E },
- { 0xD480, 0xD4FE },
- { 0xD540, 0xD57E },
- { 0xD580, 0xD5FE },
- { 0xD640, 0xD67E },
- { 0xD680, 0xD6FE },
- { 0xD740, 0xD77E },
- { 0xD780, 0xD7F9 },
- { 0xD840, 0xD87E },
- { 0xD880, 0xD8FE },
- { 0xD940, 0xD97E },
- { 0xD980, 0xD9FE },
- { 0xDA40, 0xDA7E },
- { 0xDA80, 0xDAFE },
- { 0xDB40, 0xDB7E },
- { 0xDB80, 0xDBFE },
- { 0xDC40, 0xDC7E },
- { 0xDC80, 0xDCFE },
- { 0xDD40, 0xDD7E },
- { 0xDD80, 0xDDFE },
- { 0xDE40, 0xDE7E },
- { 0xDE80, 0xDEFE },
- { 0xDF40, 0xDF7E },
- { 0xDF80, 0xDFFE },
- { 0xE040, 0xE07E },
- { 0xE080, 0xE0FE },
- { 0xE140, 0xE17E },
- { 0xE180, 0xE1FE },
- { 0xE240, 0xE27E },
- { 0xE280, 0xE2FE },
- { 0xE340, 0xE37E },
- { 0xE380, 0xE3FE },
- { 0xE440, 0xE47E },
- { 0xE480, 0xE4FE },
- { 0xE540, 0xE57E },
- { 0xE580, 0xE5FE },
- { 0xE640, 0xE67E },
- { 0xE680, 0xE6FE },
- { 0xE740, 0xE77E },
- { 0xE780, 0xE7FE },
- { 0xE840, 0xE87E },
- { 0xE880, 0xE8FE },
- { 0xE940, 0xE97E },
- { 0xE980, 0xE9FE },
- { 0xEA40, 0xEA7E },
- { 0xEA80, 0xEAFE },
- { 0xEB40, 0xEB7E },
- { 0xEB80, 0xEBFE },
- { 0xEC40, 0xEC7E },
- { 0xEC80, 0xECFE },
- { 0xED40, 0xED7E },
- { 0xED80, 0xEDFE },
- { 0xEE40, 0xEE7E },
- { 0xEE80, 0xEEFE },
- { 0xEF40, 0xEF7E },
- { 0xEF80, 0xEFFE },
- { 0xF040, 0xF07E },
- { 0xF080, 0xF0FE },
- { 0xF140, 0xF17E },
- { 0xF180, 0xF1FE },
- { 0xF240, 0xF27E },
- { 0xF280, 0xF2FE },
- { 0xF340, 0xF37E },
- { 0xF380, 0xF3FE },
- { 0xF440, 0xF47E },
- { 0xF480, 0xF4FE },
- { 0xF540, 0xF57E },
- { 0xF580, 0xF5FE },
- { 0xF640, 0xF67E },
- { 0xF680, 0xF6FE },
- { 0xF740, 0xF77E },
- { 0xF780, 0xF7FE },
- { 0xF840, 0xF87E },
- { 0xF880, 0xF8A0 },
- { 0xF940, 0xF97E },
- { 0xF980, 0xF9A0 },
- { 0xFA40, 0xFA7E },
- { 0xFA80, 0xFAA0 },
- { 0xFB40, 0xFB7E },
- { 0xFB80, 0xFBA0 },
- { 0xFC40, 0xFC7E },
- { 0xFC80, 0xFCA0 },
- { 0xFD40, 0xFD7E },
- { 0xFD80, 0xFDA0 },
- { 0xFE40, 0xFE4F },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT
-static const CharRange kEUCKRRanges[] = {
- { 0x8141, 0x815A },
- { 0x8161, 0x817A },
- { 0x8181, 0x81FE },
- { 0x8241, 0x825A },
- { 0x8261, 0x827A },
- { 0x8281, 0x82FE },
- { 0x8341, 0x835A },
- { 0x8361, 0x837A },
- { 0x8381, 0x83FE },
- { 0x8441, 0x845A },
- { 0x8461, 0x847A },
- { 0x8481, 0x84FE },
- { 0x8541, 0x855A },
- { 0x8561, 0x857A },
- { 0x8581, 0x85FE },
- { 0x8641, 0x865A },
- { 0x8661, 0x867A },
- { 0x8681, 0x86FE },
- { 0x8741, 0x875A },
- { 0x8761, 0x877A },
- { 0x8781, 0x87FE },
- { 0x8841, 0x885A },
- { 0x8861, 0x887A },
- { 0x8881, 0x88FE },
- { 0x8941, 0x895A },
- { 0x8961, 0x897A },
- { 0x8981, 0x89FE },
- { 0x8A41, 0x8A5A },
- { 0x8A61, 0x8A7A },
- { 0x8A81, 0x8AFE },
- { 0x8B41, 0x8B5A },
- { 0x8B61, 0x8B7A },
- { 0x8B81, 0x8BFE },
- { 0x8C41, 0x8C5A },
- { 0x8C61, 0x8C7A },
- { 0x8C81, 0x8CFE },
- { 0x8D41, 0x8D5A },
- { 0x8D61, 0x8D7A },
- { 0x8D81, 0x8DFE },
- { 0x8E41, 0x8E5A },
- { 0x8E61, 0x8E7A },
- { 0x8E81, 0x8EFE },
- { 0x8F41, 0x8F5A },
- { 0x8F61, 0x8F7A },
- { 0x8F81, 0x8FFE },
- { 0x9041, 0x905A },
- { 0x9061, 0x907A },
- { 0x9081, 0x90FE },
- { 0x9141, 0x915A },
- { 0x9161, 0x917A },
- { 0x9181, 0x91FE },
- { 0x9241, 0x925A },
- { 0x9261, 0x927A },
- { 0x9281, 0x92FE },
- { 0x9341, 0x935A },
- { 0x9361, 0x937A },
- { 0x9381, 0x93FE },
- { 0x9441, 0x945A },
- { 0x9461, 0x947A },
- { 0x9481, 0x94FE },
- { 0x9541, 0x955A },
- { 0x9561, 0x957A },
- { 0x9581, 0x95FE },
- { 0x9641, 0x965A },
- { 0x9661, 0x967A },
- { 0x9681, 0x96FE },
- { 0x9741, 0x975A },
- { 0x9761, 0x977A },
- { 0x9781, 0x97FE },
- { 0x9841, 0x985A },
- { 0x9861, 0x987A },
- { 0x9881, 0x98FE },
- { 0x9941, 0x995A },
- { 0x9961, 0x997A },
- { 0x9981, 0x99FE },
- { 0x9A41, 0x9A5A },
- { 0x9A61, 0x9A7A },
- { 0x9A81, 0x9AFE },
- { 0x9B41, 0x9B5A },
- { 0x9B61, 0x9B7A },
- { 0x9B81, 0x9BFE },
- { 0x9C41, 0x9C5A },
- { 0x9C61, 0x9C7A },
- { 0x9C81, 0x9CFE },
- { 0x9D41, 0x9D5A },
- { 0x9D61, 0x9D7A },
- { 0x9D81, 0x9DFE },
- { 0x9E41, 0x9E5A },
- { 0x9E61, 0x9E7A },
- { 0x9E81, 0x9EFE },
- { 0x9F41, 0x9F5A },
- { 0x9F61, 0x9F7A },
- { 0x9F81, 0x9FFE },
- { 0xA041, 0xA05A },
- { 0xA061, 0xA07A },
- { 0xA081, 0xA0FE },
- { 0xA141, 0xA15A },
- { 0xA161, 0xA17A },
- { 0xA181, 0xA1FE },
- { 0xA241, 0xA25A },
- { 0xA261, 0xA27A },
- { 0xA281, 0xA2E7 },
- { 0xA341, 0xA35A },
- { 0xA361, 0xA37A },
- { 0xA381, 0xA3FE },
- { 0xA441, 0xA45A },
- { 0xA461, 0xA47A },
- { 0xA481, 0xA4FE },
- { 0xA541, 0xA55A },
- { 0xA561, 0xA57A },
- { 0xA581, 0xA5AA },
- { 0xA5B0, 0xA5B9 },
- { 0xA5C1, 0xA5D8 },
- { 0xA5E1, 0xA5F8 },
- { 0xA641, 0xA65A },
- { 0xA661, 0xA67A },
- { 0xA681, 0xA6E4 },
- { 0xA741, 0xA75A },
- { 0xA761, 0xA77A },
- { 0xA781, 0xA7EF },
- { 0xA841, 0xA85A },
- { 0xA861, 0xA87A },
- { 0xA881, 0xA8A4 },
- { 0xA8A6, 0xA8A6 },
- { 0xA8A8, 0xA8AF },
- { 0xA8B1, 0xA8FE },
- { 0xA941, 0xA95A },
- { 0xA961, 0xA97A },
- { 0xA981, 0xA9FE },
- { 0xAA41, 0xAA5A },
- { 0xAA61, 0xAA7A },
- { 0xAA81, 0xAAF3 },
- { 0xAB41, 0xAB5A },
- { 0xAB61, 0xAB7A },
- { 0xAB81, 0xABF6 },
- { 0xAC41, 0xAC5A },
- { 0xAC61, 0xAC7A },
- { 0xAC81, 0xACC1 },
- { 0xACD1, 0xACF1 },
- { 0xAD41, 0xAD5A },
- { 0xAD61, 0xAD7A },
- { 0xAD81, 0xADA0 },
- { 0xAE41, 0xAE5A },
- { 0xAE61, 0xAE7A },
- { 0xAE81, 0xAEA0 },
- { 0xAF41, 0xAF5A },
- { 0xAF61, 0xAF7A },
- { 0xAF81, 0xAFA0 },
- { 0xB041, 0xB05A },
- { 0xB061, 0xB07A },
- { 0xB081, 0xB0FE },
- { 0xB141, 0xB15A },
- { 0xB161, 0xB17A },
- { 0xB181, 0xB1FE },
- { 0xB241, 0xB25A },
- { 0xB261, 0xB27A },
- { 0xB281, 0xB2FE },
- { 0xB341, 0xB35A },
- { 0xB361, 0xB37A },
- { 0xB381, 0xB3FE },
- { 0xB441, 0xB45A },
- { 0xB461, 0xB47A },
- { 0xB481, 0xB4FE },
- { 0xB541, 0xB55A },
- { 0xB561, 0xB57A },
- { 0xB581, 0xB5FE },
- { 0xB641, 0xB65A },
- { 0xB661, 0xB67A },
- { 0xB681, 0xB6FE },
- { 0xB741, 0xB75A },
- { 0xB761, 0xB77A },
- { 0xB781, 0xB7FE },
- { 0xB841, 0xB85A },
- { 0xB861, 0xB87A },
- { 0xB881, 0xB8FE },
- { 0xB941, 0xB95A },
- { 0xB961, 0xB97A },
- { 0xB981, 0xB9FE },
- { 0xBA41, 0xBA5A },
- { 0xBA61, 0xBA7A },
- { 0xBA81, 0xBAFE },
- { 0xBB41, 0xBB5A },
- { 0xBB61, 0xBB7A },
- { 0xBB81, 0xBBFE },
- { 0xBC41, 0xBC5A },
- { 0xBC61, 0xBC7A },
- { 0xBC81, 0xBCFE },
- { 0xBD41, 0xBD5A },
- { 0xBD61, 0xBD7A },
- { 0xBD81, 0xBDFE },
- { 0xBE41, 0xBE5A },
- { 0xBE61, 0xBE7A },
- { 0xBE81, 0xBEFE },
- { 0xBF41, 0xBF5A },
- { 0xBF61, 0xBF7A },
- { 0xBF81, 0xBFFE },
- { 0xC041, 0xC05A },
- { 0xC061, 0xC07A },
- { 0xC081, 0xC0FE },
- { 0xC141, 0xC15A },
- { 0xC161, 0xC17A },
- { 0xC181, 0xC1FE },
- { 0xC241, 0xC25A },
- { 0xC261, 0xC27A },
- { 0xC281, 0xC2FE },
- { 0xC341, 0xC35A },
- { 0xC361, 0xC37A },
- { 0xC381, 0xC3FE },
- { 0xC441, 0xC45A },
- { 0xC461, 0xC47A },
- { 0xC481, 0xC4FE },
- { 0xC541, 0xC55A },
- { 0xC561, 0xC57A },
- { 0xC581, 0xC5FE },
- { 0xC641, 0xC652 },
- { 0xC6A1, 0xC6FE },
- { 0xC7A1, 0xC7FE },
- { 0xC8A1, 0xC8FE },
- { 0xCAA1, 0xCAFE },
- { 0xCBA1, 0xCBFE },
- { 0xCCA1, 0xCCFE },
- { 0xCDA1, 0xCDFE },
- { 0xCEA1, 0xCEFE },
- { 0xCFA1, 0xCFFE },
- { 0xD0A1, 0xD0FE },
- { 0xD1A1, 0xD1FE },
- { 0xD2A1, 0xD2FE },
- { 0xD3A1, 0xD3FE },
- { 0xD4A1, 0xD4FE },
- { 0xD5A1, 0xD5FE },
- { 0xD6A1, 0xD6FE },
- { 0xD7A1, 0xD7FE },
- { 0xD8A1, 0xD8FE },
- { 0xD9A1, 0xD9FE },
- { 0xDAA1, 0xDAFE },
- { 0xDBA1, 0xDBFE },
- { 0xDCA1, 0xDCFE },
- { 0xDDA1, 0xDDFE },
- { 0xDEA1, 0xDEFE },
- { 0xDFA1, 0xDFFE },
- { 0xE0A1, 0xE0FE },
- { 0xE1A1, 0xE1FE },
- { 0xE2A1, 0xE2FE },
- { 0xE3A1, 0xE3FE },
- { 0xE4A1, 0xE4FE },
- { 0xE5A1, 0xE5FE },
- { 0xE6A1, 0xE6FE },
- { 0xE7A1, 0xE7FE },
- { 0xE8A1, 0xE8FE },
- { 0xE9A1, 0xE9FE },
- { 0xEAA1, 0xEAFE },
- { 0xEBA1, 0xEBFE },
- { 0xECA1, 0xECFE },
- { 0xEDA1, 0xEDFE },
- { 0xEEA1, 0xEEFE },
- { 0xEFA1, 0xEFFE },
- { 0xF0A1, 0xF0FE },
- { 0xF1A1, 0xF1FE },
- { 0xF2A1, 0xF2FE },
- { 0xF3A1, 0xF3FE },
- { 0xF4A1, 0xF4FE },
- { 0xF5A1, 0xF5FE },
- { 0xF6A1, 0xF6FE },
- { 0xF7A1, 0xF7FE },
- { 0xF8A1, 0xF8FE },
- { 0xF9A1, 0xF9FE },
- { 0xFAA1, 0xFAFE },
- { 0xFBA1, 0xFBFE },
- { 0xFCA1, 0xFCFE },
- { 0xFDA1, 0xFDFE },
-};
-
-// generated from http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP950.TXT
-static const CharRange kBig5Ranges[] = {
- { 0xA140, 0xA17E },
- { 0xA1A1, 0xA1FE },
- { 0xA240, 0xA27E },
- { 0xA2A1, 0xA2FE },
- { 0xA340, 0xA37E },
- { 0xA3A1, 0xA3BF },
- { 0xA3E1, 0xA3E1 },
- { 0xA440, 0xA47E },
- { 0xA4A1, 0xA4FE },
- { 0xA540, 0xA57E },
- { 0xA5A1, 0xA5FE },
- { 0xA640, 0xA67E },
- { 0xA6A1, 0xA6FE },
- { 0xA740, 0xA77E },
- { 0xA7A1, 0xA7FE },
- { 0xA840, 0xA87E },
- { 0xA8A1, 0xA8FE },
- { 0xA940, 0xA97E },
- { 0xA9A1, 0xA9FE },
- { 0xAA40, 0xAA7E },
- { 0xAAA1, 0xAAFE },
- { 0xAB40, 0xAB7E },
- { 0xABA1, 0xABFE },
- { 0xAC40, 0xAC7E },
- { 0xACA1, 0xACFE },
- { 0xAD40, 0xAD7E },
- { 0xADA1, 0xADFE },
- { 0xAE40, 0xAE7E },
- { 0xAEA1, 0xAEFE },
- { 0xAF40, 0xAF7E },
- { 0xAFA1, 0xAFFE },
- { 0xB040, 0xB07E },
- { 0xB0A1, 0xB0FE },
- { 0xB140, 0xB17E },
- { 0xB1A1, 0xB1FE },
- { 0xB240, 0xB27E },
- { 0xB2A1, 0xB2FE },
- { 0xB340, 0xB37E },
- { 0xB3A1, 0xB3FE },
- { 0xB440, 0xB47E },
- { 0xB4A1, 0xB4FE },
- { 0xB540, 0xB57E },
- { 0xB5A1, 0xB5FE },
- { 0xB640, 0xB67E },
- { 0xB6A1, 0xB6FE },
- { 0xB740, 0xB77E },
- { 0xB7A1, 0xB7FE },
- { 0xB840, 0xB87E },
- { 0xB8A1, 0xB8FE },
- { 0xB940, 0xB97E },
- { 0xB9A1, 0xB9FE },
- { 0xBA40, 0xBA7E },
- { 0xBAA1, 0xBAFE },
- { 0xBB40, 0xBB7E },
- { 0xBBA1, 0xBBFE },
- { 0xBC40, 0xBC7E },
- { 0xBCA1, 0xBCFE },
- { 0xBD40, 0xBD7E },
- { 0xBDA1, 0xBDFE },
- { 0xBE40, 0xBE7E },
- { 0xBEA1, 0xBEFE },
- { 0xBF40, 0xBF7E },
- { 0xBFA1, 0xBFFE },
- { 0xC040, 0xC07E },
- { 0xC0A1, 0xC0FE },
- { 0xC140, 0xC17E },
- { 0xC1A1, 0xC1FE },
- { 0xC240, 0xC27E },
- { 0xC2A1, 0xC2FE },
- { 0xC340, 0xC37E },
- { 0xC3A1, 0xC3FE },
- { 0xC440, 0xC47E },
- { 0xC4A1, 0xC4FE },
- { 0xC540, 0xC57E },
- { 0xC5A1, 0xC5FE },
- { 0xC640, 0xC67E },
- { 0xC940, 0xC97E },
- { 0xC9A1, 0xC9FE },
- { 0xCA40, 0xCA7E },
- { 0xCAA1, 0xCAFE },
- { 0xCB40, 0xCB7E },
- { 0xCBA1, 0xCBFE },
- { 0xCC40, 0xCC7E },
- { 0xCCA1, 0xCCFE },
- { 0xCD40, 0xCD7E },
- { 0xCDA1, 0xCDFE },
- { 0xCE40, 0xCE7E },
- { 0xCEA1, 0xCEFE },
- { 0xCF40, 0xCF7E },
- { 0xCFA1, 0xCFFE },
- { 0xD040, 0xD07E },
- { 0xD0A1, 0xD0FE },
- { 0xD140, 0xD17E },
- { 0xD1A1, 0xD1FE },
- { 0xD240, 0xD27E },
- { 0xD2A1, 0xD2FE },
- { 0xD340, 0xD37E },
- { 0xD3A1, 0xD3FE },
- { 0xD440, 0xD47E },
- { 0xD4A1, 0xD4FE },
- { 0xD540, 0xD57E },
- { 0xD5A1, 0xD5FE },
- { 0xD640, 0xD67E },
- { 0xD6A1, 0xD6FE },
- { 0xD740, 0xD77E },
- { 0xD7A1, 0xD7FE },
- { 0xD840, 0xD87E },
- { 0xD8A1, 0xD8FE },
- { 0xD940, 0xD97E },
- { 0xD9A1, 0xD9FE },
- { 0xDA40, 0xDA7E },
- { 0xDAA1, 0xDAFE },
- { 0xDB40, 0xDB7E },
- { 0xDBA1, 0xDBFE },
- { 0xDC40, 0xDC7E },
- { 0xDCA1, 0xDCFE },
- { 0xDD40, 0xDD7E },
- { 0xDDA1, 0xDDFE },
- { 0xDE40, 0xDE7E },
- { 0xDEA1, 0xDEFE },
- { 0xDF40, 0xDF7E },
- { 0xDFA1, 0xDFFE },
- { 0xE040, 0xE07E },
- { 0xE0A1, 0xE0FE },
- { 0xE140, 0xE17E },
- { 0xE1A1, 0xE1FE },
- { 0xE240, 0xE27E },
- { 0xE2A1, 0xE2FE },
- { 0xE340, 0xE37E },
- { 0xE3A1, 0xE3FE },
- { 0xE440, 0xE47E },
- { 0xE4A1, 0xE4FE },
- { 0xE540, 0xE57E },
- { 0xE5A1, 0xE5FE },
- { 0xE640, 0xE67E },
- { 0xE6A1, 0xE6FE },
- { 0xE740, 0xE77E },
- { 0xE7A1, 0xE7FE },
- { 0xE840, 0xE87E },
- { 0xE8A1, 0xE8FE },
- { 0xE940, 0xE97E },
- { 0xE9A1, 0xE9FE },
- { 0xEA40, 0xEA7E },
- { 0xEAA1, 0xEAFE },
- { 0xEB40, 0xEB7E },
- { 0xEBA1, 0xEBFE },
- { 0xEC40, 0xEC7E },
- { 0xECA1, 0xECFE },
- { 0xED40, 0xED7E },
- { 0xEDA1, 0xEDFE },
- { 0xEE40, 0xEE7E },
- { 0xEEA1, 0xEEFE },
- { 0xEF40, 0xEF7E },
- { 0xEFA1, 0xEFFE },
- { 0xF040, 0xF07E },
- { 0xF0A1, 0xF0FE },
- { 0xF140, 0xF17E },
- { 0xF1A1, 0xF1FE },
- { 0xF240, 0xF27E },
- { 0xF2A1, 0xF2FE },
- { 0xF340, 0xF37E },
- { 0xF3A1, 0xF3FE },
- { 0xF440, 0xF47E },
- { 0xF4A1, 0xF4FE },
- { 0xF540, 0xF57E },
- { 0xF5A1, 0xF5FE },
- { 0xF640, 0xF67E },
- { 0xF6A1, 0xF6FE },
- { 0xF740, 0xF77E },
- { 0xF7A1, 0xF7FE },
- { 0xF840, 0xF87E },
- { 0xF8A1, 0xF8FE },
- { 0xF940, 0xF97E },
- { 0xF9A1, 0xF9FE },
-};
-
-static bool charMatchesEncoding(int ch, const CharRange* encodingRanges, int rangeCount) {
- // Use binary search to see if the character is contained in the encoding
- int low = 0;
- int high = rangeCount;
-
- while (low < high) {
- int i = (low + high) / 2;
- const CharRange* range = &encodingRanges[i];
- if (ch >= range->first && ch <= range->last)
- return true;
- if (ch > range->last)
- low = i + 1;
- else
- high = i;
- }
-
- return false;
-}
-
-extern uint32_t findPossibleEncodings(int ch)
-{
- // ASCII matches everything
- if (ch < 256) return kEncodingAll;
-
- int result = kEncodingNone;
-
- if (charMatchesEncoding(ch, kShiftJISRanges, ARRAY_SIZE(kShiftJISRanges)))
- result |= kEncodingShiftJIS;
- if (charMatchesEncoding(ch, kGBKRanges, ARRAY_SIZE(kGBKRanges)))
- result |= kEncodingGBK;
- if (charMatchesEncoding(ch, kBig5Ranges, ARRAY_SIZE(kBig5Ranges)))
- result |= kEncodingBig5;
- if (charMatchesEncoding(ch, kEUCKRRanges, ARRAY_SIZE(kEUCKRRanges)))
- result |= kEncodingEUCKR;
-
- return result;
-}
diff --git a/media/libmedia/autodetect.h b/media/libmedia/autodetect.h
deleted file mode 100644
index 9675db3..0000000
--- a/media/libmedia/autodetect.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AUTODETECT_H
-#define AUTODETECT_H
-
-#include <inttypes.h>
-
-// flags used for native encoding detection
-enum {
- kEncodingNone = 0,
- kEncodingShiftJIS = (1 << 0),
- kEncodingGBK = (1 << 1),
- kEncodingBig5 = (1 << 2),
- kEncodingEUCKR = (1 << 3),
-
- kEncodingAll = (kEncodingShiftJIS | kEncodingGBK | kEncodingBig5 | kEncodingEUCKR),
-};
-
-
-// returns a bitfield containing the possible native encodings for the given character
-extern uint32_t findPossibleEncodings(int ch);
-
-#endif // AUTODETECT_H
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 110b94c..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)
@@ -157,7 +160,7 @@ sp<IMemory> MediaMetadataRetriever::extractAlbumArt()
return mRetriever->extractAlbumArt();
}
-void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who) {
+void MediaMetadataRetriever::DeathNotifier::binderDied(const wp<IBinder>& who __unused) {
Mutex::Autolock lock(MediaMetadataRetriever::sServiceLock);
MediaMetadataRetriever::sService.clear();
ALOGW("MediaMetadataRetriever server died!");
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 0f6d897..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);
@@ -654,7 +655,7 @@ status_t MediaPlayer::setRetransmitEndpoint(const char* addrString,
return BAD_VALUE;
}
- memset(&mRetransmitEndpoint, 0, sizeof(&mRetransmitEndpoint));
+ memset(&mRetransmitEndpoint, 0, sizeof(mRetransmitEndpoint));
mRetransmitEndpoint.sin_family = AF_INET;
mRetransmitEndpoint.sin_addr = saddr;
mRetransmitEndpoint.sin_port = htons(port);
@@ -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/HDCP.cpp b/media/libmediaplayerservice/HDCP.cpp
index c2ac1a3..afe3936 100644
--- a/media/libmediaplayerservice/HDCP.cpp
+++ b/media/libmediaplayerservice/HDCP.cpp
@@ -107,11 +107,7 @@ uint32_t HDCP::getCaps() {
return NO_INIT;
}
- // TO-DO:
- // Only support HDCP_CAPS_ENCRYPT (byte-array to byte-array) for now.
- // use mHDCPModule->getCaps() when the HDCP libraries get updated.
- //return mHDCPModule->getCaps();
- return HDCPModule::HDCP_CAPS_ENCRYPT;
+ return mHDCPModule->getCaps();
}
status_t HDCP::encrypt(
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..fc355b0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -211,12 +211,12 @@ class MediaPlayerService : public BnMediaPlayerService
virtual void flush() {}
virtual void pause() {}
virtual void close() {}
- void setAudioStreamType(audio_stream_type_t streamType) {}
+ void setAudioStreamType(audio_stream_type_t streamType __unused) {}
// stream type is not used for AudioCache
virtual audio_stream_type_t getAudioStreamType() const { return AUDIO_STREAM_DEFAULT; }
- void setVolume(float left, float right) {}
- virtual status_t setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
+ void setVolume(float left __unused, float right __unused) {}
+ virtual status_t setPlaybackRatePermille(int32_t ratePermille __unused) { return INVALID_OPERATION; }
uint32_t sampleRate() const { return mSampleRate; }
audio_format_t format() const { return mFormat; }
size_t size() const { return mSize; }
@@ -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 f9d9020..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,31 +763,85 @@ 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 = setupMPEG2TSRecording();
+ break;
+
+ default:
+ ALOGE("Unsupported output file format: %d", mOutputFormat);
+ status = UNKNOWN_ERROR;
+ 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 = startMPEG2TSRecording();
+ {
+ 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)) {
@@ -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
@@ -973,7 +1016,7 @@ status_t StagefrightRecorder::startRTPRecording() {
return err;
}
- err = setupVideoEncoder(mediaSource, mVideoBitRate, &source);
+ err = setupVideoEncoder(mediaSource, &source);
if (err != OK) {
return err;
}
@@ -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);
@@ -1017,7 +1060,7 @@ status_t StagefrightRecorder::startMPEG2TSRecording() {
}
sp<MediaSource> encoder;
- err = setupVideoEncoder(mediaSource, mVideoBitRate, &encoder);
+ err = setupVideoEncoder(mediaSource, &encoder);
if (err != OK) {
return err;
@@ -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;
@@ -1383,25 +1391,22 @@ status_t StagefrightRecorder::setupCameraSource(
status_t StagefrightRecorder::setupVideoEncoder(
sp<MediaSource> cameraSource,
- int32_t videoBitRate,
sp<MediaSource> *source) {
source->clear();
- sp<MetaData> enc_meta = new MetaData;
- enc_meta->setInt32(kKeyBitRate, videoBitRate);
- 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:
@@ -1409,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;
@@ -1495,16 +1510,12 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
return OK;
}
-status_t StagefrightRecorder::setupMPEG4Recording(
- int outputFd,
- int32_t videoWidth, int32_t videoHeight,
- int32_t videoBitRate,
- int32_t *totalBitRate,
- sp<MediaWriter> *mediaWriter) {
- mediaWriter->clear();
- *totalBitRate = 0;
+status_t StagefrightRecorder::setupMPEG4Recording() {
+ mWriter.clear();
+ mTotalBitRate = 0;
+
status_t err = OK;
- sp<MediaWriter> writer = new MPEG4Writer(outputFd);
+ sp<MediaWriter> writer = new MPEG4Writer(mOutputFd);
if (mVideoSource < VIDEO_SOURCE_LIST_END) {
@@ -1515,13 +1526,13 @@ status_t StagefrightRecorder::setupMPEG4Recording(
}
sp<MediaSource> encoder;
- err = setupVideoEncoder(mediaSource, videoBitRate, &encoder);
+ err = setupVideoEncoder(mediaSource, &encoder);
if (err != OK) {
return err;
}
writer->addSource(encoder);
- *totalBitRate += videoBitRate;
+ mTotalBitRate += mVideoBitRate;
}
// Audio source is added at the end if it exists.
@@ -1530,7 +1541,7 @@ status_t StagefrightRecorder::setupMPEG4Recording(
if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
err = setupAudioEncoder(writer);
if (err != OK) return err;
- *totalBitRate += mAudioBitRate;
+ mTotalBitRate += mAudioBitRate;
}
if (mInterleaveDurationUs > 0) {
@@ -1548,22 +1559,28 @@ status_t StagefrightRecorder::setupMPEG4Recording(
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);
}
writer->setListener(mListener);
- *mediaWriter = writer;
+ mWriter = writer;
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);
@@ -1576,27 +1593,6 @@ void StagefrightRecorder::setupMPEG4MetaData(int64_t startTimeUs, int32_t totalB
}
}
-status_t StagefrightRecorder::startMPEG4Recording() {
- int32_t totalBitRate;
- status_t err = setupMPEG4Recording(
- mOutputFd, mVideoWidth, mVideoHeight,
- mVideoBitRate, &totalBitRate, &mWriter);
- 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) {
@@ -1636,6 +1632,8 @@ status_t StagefrightRecorder::stop() {
mWriter.clear();
}
+ mGraphicBufferProducer.clear();
+
if (mOutputFd >= 0) {
::close(mOutputFd);
mOutputFd = -1;
@@ -1655,7 +1653,6 @@ status_t StagefrightRecorder::stop() {
addBatteryData(params);
}
-
return err;
}
@@ -1707,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 31f09e0..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,22 +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(
- int outputFd,
- int32_t videoWidth, int32_t videoHeight,
- int32_t videoBitRate,
- int32_t *totalBitRate,
- sp<MediaWriter> *mediaWriter);
- 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);
@@ -147,14 +143,8 @@ 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,
- int32_t videoBitRate,
- sp<MediaSource> *source);
+ status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source);
// Encoding parameter handling utilities
status_t setParameter(const String8 &key, const String8 &value);
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> &notify,
+ 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> &notify,
+ 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> &notify,
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> &notify,
+ 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> &notify,
+ 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> &notify,
+ 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> &notify,
+ 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/AudioBufferProviderSource.cpp b/media/libnbaio/AudioBufferProviderSource.cpp
index 74a6fdb..4a69104 100644
--- a/media/libnbaio/AudioBufferProviderSource.cpp
+++ b/media/libnbaio/AudioBufferProviderSource.cpp
@@ -24,11 +24,11 @@
namespace android {
AudioBufferProviderSource::AudioBufferProviderSource(AudioBufferProvider *provider,
- NBAIO_Format format) :
+ const NBAIO_Format& format) :
NBAIO_Source(format), mProvider(provider), mConsumed(0)
{
ALOG_ASSERT(provider != NULL);
- ALOG_ASSERT(format != Format_Invalid);
+ ALOG_ASSERT(Format_isValid(format));
}
AudioBufferProviderSource::~AudioBufferProviderSource()
diff --git a/media/libnbaio/AudioStreamInSource.cpp b/media/libnbaio/AudioStreamInSource.cpp
index 05273f6..ae8fac8 100644
--- a/media/libnbaio/AudioStreamInSource.cpp
+++ b/media/libnbaio/AudioStreamInSource.cpp
@@ -40,7 +40,7 @@ AudioStreamInSource::~AudioStreamInSource()
ssize_t AudioStreamInSource::negotiate(const NBAIO_Format offers[], size_t numOffers,
NBAIO_Format counterOffers[], size_t& numCounterOffers)
{
- if (mFormat == Format_Invalid) {
+ if (!Format_isValid(mFormat)) {
mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common);
audio_format_t streamFormat = mStream->common.get_format(&mStream->common);
if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) {
@@ -67,7 +67,7 @@ size_t AudioStreamInSource::framesOverrun()
ssize_t AudioStreamInSource::read(void *buffer, size_t count)
{
- if (CC_UNLIKELY(mFormat == Format_Invalid)) {
+ if (CC_UNLIKELY(!Format_isValid(mFormat))) {
return NEGOTIATE;
}
ssize_t bytesRead = mStream->read(mStream, buffer, count << mBitShift);
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index e4341d7..aa9810e 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -37,7 +37,7 @@ AudioStreamOutSink::~AudioStreamOutSink()
ssize_t AudioStreamOutSink::negotiate(const NBAIO_Format offers[], size_t numOffers,
NBAIO_Format counterOffers[], size_t& numCounterOffers)
{
- if (mFormat == Format_Invalid) {
+ if (!Format_isValid(mFormat)) {
mStreamBufferSizeBytes = mStream->common.get_buffer_size(&mStream->common);
audio_format_t streamFormat = mStream->common.get_format(&mStream->common);
if (streamFormat == AUDIO_FORMAT_PCM_16_BIT) {
@@ -56,7 +56,7 @@ ssize_t AudioStreamOutSink::write(const void *buffer, size_t count)
if (!mNegotiated) {
return NEGOTIATE;
}
- ALOG_ASSERT(mFormat != Format_Invalid);
+ ALOG_ASSERT(Format_isValid(mFormat));
ssize_t ret = mStream->write(mStream, buffer, count << mBitShift);
if (ret > 0) {
ret >>= mBitShift;
diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp
index 3c61b60..b23967b 100644
--- a/media/libnbaio/MonoPipe.cpp
+++ b/media/libnbaio/MonoPipe.cpp
@@ -30,7 +30,7 @@
namespace android {
-MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) :
+MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) :
NBAIO_Sink(format),
mUpdateSeq(0),
mReqFrames(reqFrames),
diff --git a/media/libnbaio/NBAIO.cpp b/media/libnbaio/NBAIO.cpp
index e0d2c21..51514de 100644
--- a/media/libnbaio/NBAIO.cpp
+++ b/media/libnbaio/NBAIO.cpp
@@ -22,17 +22,22 @@
namespace android {
-size_t Format_frameSize(NBAIO_Format format)
+size_t Format_frameSize(const NBAIO_Format& format)
{
+ // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT
return Format_channelCount(format) * sizeof(short);
}
-size_t Format_frameBitShift(NBAIO_Format format)
+int Format_frameBitShift(const NBAIO_Format& format)
{
+ // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT
// sizeof(short) == 2, so frame size == 1 << channels
return Format_channelCount(format);
+ // FIXME must return -1 for non-power of 2
}
+const NBAIO_Format Format_Invalid = { 0 };
+
enum {
Format_SR_8000,
Format_SR_11025,
@@ -51,12 +56,12 @@ enum {
Format_C_Mask = 0x18
};
-unsigned Format_sampleRate(NBAIO_Format format)
+unsigned Format_sampleRate(const NBAIO_Format& format)
{
- if (format == Format_Invalid) {
+ if (!Format_isValid(format)) {
return 0;
}
- switch (format & Format_SR_Mask) {
+ switch (format.mPacked & Format_SR_Mask) {
case Format_SR_8000:
return 8000;
case Format_SR_11025:
@@ -78,12 +83,12 @@ unsigned Format_sampleRate(NBAIO_Format format)
}
}
-unsigned Format_channelCount(NBAIO_Format format)
+unsigned Format_channelCount(const NBAIO_Format& format)
{
- if (format == Format_Invalid) {
+ if (!Format_isValid(format)) {
return 0;
}
- switch (format & Format_C_Mask) {
+ switch (format.mPacked & Format_C_Mask) {
case Format_C_1:
return 1;
case Format_C_2:
@@ -95,7 +100,7 @@ unsigned Format_channelCount(NBAIO_Format format)
NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
{
- NBAIO_Format format;
+ unsigned format;
switch (sampleRate) {
case 8000:
format = Format_SR_8000;
@@ -134,7 +139,9 @@ NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
default:
return Format_Invalid;
}
- return format;
+ NBAIO_Format ret;
+ ret.mPacked = format;
+ return ret;
}
// This is a default implementation; it is expected that subclasses will optimize this.
@@ -216,9 +223,9 @@ ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
{
ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
offers, numOffers, counterOffers, numCounterOffers);
- if (mFormat != Format_Invalid) {
+ if (Format_isValid(mFormat)) {
for (size_t i = 0; i < numOffers; ++i) {
- if (offers[i] == mFormat) {
+ if (Format_isEqual(offers[i], mFormat)) {
mNegotiated = true;
return i;
}
@@ -233,4 +240,14 @@ ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
return (ssize_t) NEGOTIATE;
}
+bool Format_isValid(const NBAIO_Format& format)
+{
+ return format.mPacked != Format_Invalid.mPacked;
+}
+
+bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
+{
+ return format1.mPacked == format2.mPacked;
+}
+
} // namespace android
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 045bf64..ba8d0b4 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -441,7 +441,7 @@ void NBLog::Reader::dump(int fd, size_t indent)
bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
{
- return iMemory.get() == mIMemory.get();
+ return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
}
} // namespace android
diff --git a/media/libnbaio/Pipe.cpp b/media/libnbaio/Pipe.cpp
index 1c21f9c..115f311 100644
--- a/media/libnbaio/Pipe.cpp
+++ b/media/libnbaio/Pipe.cpp
@@ -25,7 +25,7 @@
namespace android {
-Pipe::Pipe(size_t maxFrames, NBAIO_Format format) :
+Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format) :
NBAIO_Sink(format),
mMaxFrames(roundup(maxFrames)),
mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
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 c68dfc1..f2354b4 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -365,6 +365,7 @@ ACodec::ACodec()
mIsEncoder(false),
mUseMetadataOnEncoderOutput(false),
mShutdownInProgress(false),
+ mIsConfiguredForAdaptivePlayback(false),
mEncoderDelay(0),
mEncoderPadding(0),
mChannelMaskPresent(false),
@@ -372,7 +373,9 @@ ACodec::ACodec()
mDequeueCounter(0),
mStoreMetaDataInOutputBuffers(false),
mMetaDataBuffersToSubmit(0),
- mRepeatFrameDelayUs(-1ll) {
+ mRepeatFrameDelayUs(-1ll),
+ mMaxPtsGapUs(-1l),
+ mCreateInputBuffersSuspended(false) {
mUninitializedState = new UninitializedState(this);
mLoadedState = new LoadedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
@@ -1114,6 +1117,16 @@ status_t ACodec::configureCodec(
&mRepeatFrameDelayUs)) {
mRepeatFrameDelayUs = -1ll;
}
+
+ 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
@@ -1121,6 +1134,7 @@ status_t ACodec::configureCodec(
int32_t haveNativeWindow = msg->findObject("native-window", &obj) &&
obj != NULL;
mStoreMetaDataInOutputBuffers = false;
+ mIsConfiguredForAdaptivePlayback = false;
if (!encoder && video && haveNativeWindow) {
err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE);
if (err != OK) {
@@ -1165,12 +1179,14 @@ status_t ACodec::configureCodec(
ALOGW_IF(err != OK,
"[%s] prepareForAdaptivePlayback failed w/ err %d",
mComponentName.c_str(), err);
+ mIsConfiguredForAdaptivePlayback = (err == OK);
}
// allow failure
err = OK;
} else {
ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str());
mStoreMetaDataInOutputBuffers = true;
+ mIsConfiguredForAdaptivePlayback = true;
}
int32_t push;
@@ -3318,11 +3334,11 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
mCodec->mInputEOSResult = err;
}
break;
-
- default:
- CHECK_EQ((int)mode, (int)FREE_BUFFERS);
- break;
}
+
+ default:
+ CHECK_EQ((int)mode, (int)FREE_BUFFERS);
+ break;
}
}
@@ -3413,7 +3429,7 @@ bool ACodec::BaseState::onOMXFillBufferDone(
sp<AMessage> reply =
new AMessage(kWhatOutputBufferDrained, mCodec->id());
- if (!mCodec->mSentFormat) {
+ if (!mCodec->mSentFormat && rangeLength > 0) {
mCodec->sendFormatChange(reply);
}
@@ -3773,6 +3789,7 @@ void ACodec::LoadedState::stateEntered() {
mCodec->mDequeueCounter = 0;
mCodec->mMetaDataBuffersToSubmit = 0;
mCodec->mRepeatFrameDelayUs = -1ll;
+ mCodec->mIsConfiguredForAdaptivePlayback = false;
if (mCodec->mShutdownInProgress) {
bool keepComponentAllocated = mCodec->mKeepComponentAllocated;
@@ -3921,6 +3938,37 @@ void ACodec::LoadedState::onCreateInputSurface(
}
}
+ if (err == OK && mCodec->mMaxPtsGapUs > 0l) {
+ err = mCodec->mOMX->setInternalOption(
+ mCodec->mNode,
+ kPortIndexInput,
+ IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP,
+ &mCodec->mMaxPtsGapUs,
+ sizeof(mCodec->mMaxPtsGapUs));
+
+ 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);
+ }
+ }
+
if (err == OK) {
notify->setObject("input-surface",
new BufferProducerWrapper(bufferProducer));
@@ -3978,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);
@@ -4044,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);
@@ -4313,6 +4363,22 @@ status_t ACodec::setParameters(const sp<AMessage> &params) {
}
}
+ 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/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index d7223d9..cadadc8 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -278,7 +278,7 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) {
// Drop retrieved and previously lost audio data.
if (mNumFramesReceived == 0 && timeUs < mStartTimeUs) {
- mRecord->getInputFramesLost();
+ (void) mRecord->getInputFramesLost();
ALOGV("Drop audio data at %lld/%lld us", timeUs, mStartTimeUs);
return OK;
}
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/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 5772316..86844b8 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -85,7 +85,8 @@ CameraSourceTimeLapse::CameraSourceTimeLapse(
mVideoWidth = videoSize.width;
mVideoHeight = videoSize.height;
- if (!trySettingVideoSize(videoSize.width, videoSize.height)) {
+ if (OK == mInitCheck && !trySettingVideoSize(videoSize.width, videoSize.height)) {
+ releaseCamera();
mInitCheck = NO_INIT;
}
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/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 4f1c5b3..dfb5c04 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -2441,6 +2441,58 @@ status_t MPEG4Extractor::verifyTrack(Track *track) {
return OK;
}
+typedef enum {
+ //AOT_NONE = -1,
+ //AOT_NULL_OBJECT = 0,
+ //AOT_AAC_MAIN = 1, /**< Main profile */
+ AOT_AAC_LC = 2, /**< Low Complexity object */
+ //AOT_AAC_SSR = 3,
+ //AOT_AAC_LTP = 4,
+ AOT_SBR = 5,
+ //AOT_AAC_SCAL = 6,
+ //AOT_TWIN_VQ = 7,
+ //AOT_CELP = 8,
+ //AOT_HVXC = 9,
+ //AOT_RSVD_10 = 10, /**< (reserved) */
+ //AOT_RSVD_11 = 11, /**< (reserved) */
+ //AOT_TTSI = 12, /**< TTSI Object */
+ //AOT_MAIN_SYNTH = 13, /**< Main Synthetic object */
+ //AOT_WAV_TAB_SYNTH = 14, /**< Wavetable Synthesis object */
+ //AOT_GEN_MIDI = 15, /**< General MIDI object */
+ //AOT_ALG_SYNTH_AUD_FX = 16, /**< Algorithmic Synthesis and Audio FX object */
+ AOT_ER_AAC_LC = 17, /**< Error Resilient(ER) AAC Low Complexity */
+ //AOT_RSVD_18 = 18, /**< (reserved) */
+ //AOT_ER_AAC_LTP = 19, /**< Error Resilient(ER) AAC LTP object */
+ AOT_ER_AAC_SCAL = 20, /**< Error Resilient(ER) AAC Scalable object */
+ //AOT_ER_TWIN_VQ = 21, /**< Error Resilient(ER) TwinVQ object */
+ AOT_ER_BSAC = 22, /**< Error Resilient(ER) BSAC object */
+ AOT_ER_AAC_LD = 23, /**< Error Resilient(ER) AAC LowDelay object */
+ //AOT_ER_CELP = 24, /**< Error Resilient(ER) CELP object */
+ //AOT_ER_HVXC = 25, /**< Error Resilient(ER) HVXC object */
+ //AOT_ER_HILN = 26, /**< Error Resilient(ER) HILN object */
+ //AOT_ER_PARA = 27, /**< Error Resilient(ER) Parametric object */
+ //AOT_RSVD_28 = 28, /**< might become SSC */
+ AOT_PS = 29, /**< PS, Parametric Stereo (includes SBR) */
+ //AOT_MPEGS = 30, /**< MPEG Surround */
+
+ AOT_ESCAPE = 31, /**< Signal AOT uses more than 5 bits */
+
+ //AOT_MP3ONMP4_L1 = 32, /**< MPEG-Layer1 in mp4 */
+ //AOT_MP3ONMP4_L2 = 33, /**< MPEG-Layer2 in mp4 */
+ //AOT_MP3ONMP4_L3 = 34, /**< MPEG-Layer3 in mp4 */
+ //AOT_RSVD_35 = 35, /**< might become DST */
+ //AOT_RSVD_36 = 36, /**< might become ALS */
+ //AOT_AAC_SLS = 37, /**< AAC + SLS */
+ //AOT_SLS = 38, /**< SLS */
+ //AOT_ER_AAC_ELD = 39, /**< AAC Enhanced Low Delay */
+
+ //AOT_USAC = 42, /**< USAC */
+ //AOT_SAOC = 43, /**< SAOC */
+ //AOT_LD_MPEGS = 44, /**< Low Delay MPEG Surround */
+
+ //AOT_RSVD50 = 50, /**< Interim AOT for Rsvd50 */
+} AUDIO_OBJECT_TYPE;
+
status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
const void *esds_data, size_t esds_size) {
ESDS esds(esds_data, esds_size);
@@ -2523,7 +2575,7 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
sampleRate = kSamplingRate[freqIndex];
}
- if (objectType == 5 || objectType == 29) { // SBR specific config per 14496-3 table 1.13
+ if (objectType == AOT_SBR || objectType == AOT_PS) {//SBR specific config per 14496-3 table 1.13
uint32_t extFreqIndex = br.getBits(4);
int32_t extSampleRate;
if (extFreqIndex == 15) {
@@ -2541,6 +2593,111 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
// mLastTrack->meta->setInt32(kKeyExtSampleRate, extSampleRate);
}
+ switch (numChannels) {
+ // values defined in 14496-3_2009 amendment-4 Table 1.19 - Channel Configuration
+ case 0:
+ case 1:// FC
+ case 2:// FL FR
+ case 3:// FC, FL FR
+ case 4:// FC, FL FR, RC
+ case 5:// FC, FL FR, SL SR
+ case 6:// FC, FL FR, SL SR, LFE
+ //numChannels already contains the right value
+ break;
+ case 11:// FC, FL FR, SL SR, RC, LFE
+ numChannels = 7;
+ break;
+ case 7: // FC, FCL FCR, FL FR, SL SR, LFE
+ case 12:// FC, FL FR, SL SR, RL RR, LFE
+ case 14:// FC, FL FR, SL SR, LFE, FHL FHR
+ numChannels = 8;
+ break;
+ default:
+ return ERROR_UNSUPPORTED;
+ }
+
+ {
+ if (objectType == AOT_SBR || objectType == AOT_PS) {
+ const int32_t extensionSamplingFrequency = br.getBits(4);
+ objectType = br.getBits(5);
+
+ if (objectType == AOT_ESCAPE) {
+ objectType = 32 + br.getBits(6);
+ }
+ }
+ if (objectType == AOT_AAC_LC || objectType == AOT_ER_AAC_LC ||
+ objectType == AOT_ER_AAC_LD || objectType == AOT_ER_AAC_SCAL ||
+ objectType == AOT_ER_BSAC) {
+ const int32_t frameLengthFlag = br.getBits(1);
+
+ const int32_t dependsOnCoreCoder = br.getBits(1);
+
+ if (dependsOnCoreCoder ) {
+ const int32_t coreCoderDelay = br.getBits(14);
+ }
+
+ const int32_t extensionFlag = br.getBits(1);
+
+ if (numChannels == 0 ) {
+ int32_t channelsEffectiveNum = 0;
+ int32_t channelsNum = 0;
+ const int32_t ElementInstanceTag = br.getBits(4);
+ const int32_t Profile = br.getBits(2);
+ const int32_t SamplingFrequencyIndex = br.getBits(4);
+ const int32_t NumFrontChannelElements = br.getBits(4);
+ const int32_t NumSideChannelElements = br.getBits(4);
+ const int32_t NumBackChannelElements = br.getBits(4);
+ const int32_t NumLfeChannelElements = br.getBits(2);
+ const int32_t NumAssocDataElements = br.getBits(3);
+ const int32_t NumValidCcElements = br.getBits(4);
+
+ const int32_t MonoMixdownPresent = br.getBits(1);
+ if (MonoMixdownPresent != 0) {
+ const int32_t MonoMixdownElementNumber = br.getBits(4);
+ }
+
+ const int32_t StereoMixdownPresent = br.getBits(1);
+ if (StereoMixdownPresent != 0) {
+ const int32_t StereoMixdownElementNumber = br.getBits(4);
+ }
+
+ const int32_t MatrixMixdownIndexPresent = br.getBits(1);
+ if (MatrixMixdownIndexPresent != 0) {
+ const int32_t MatrixMixdownIndex = br.getBits(2);
+ const int32_t PseudoSurroundEnable = br.getBits(1);
+ }
+
+ int i;
+ for (i=0; i < NumFrontChannelElements; i++) {
+ const int32_t FrontElementIsCpe = br.getBits(1);
+ const int32_t FrontElementTagSelect = br.getBits(4);
+ channelsNum += FrontElementIsCpe ? 2 : 1;
+ }
+
+ for (i=0; i < NumSideChannelElements; i++) {
+ const int32_t SideElementIsCpe = br.getBits(1);
+ const int32_t SideElementTagSelect = br.getBits(4);
+ channelsNum += SideElementIsCpe ? 2 : 1;
+ }
+
+ for (i=0; i < NumBackChannelElements; i++) {
+ const int32_t BackElementIsCpe = br.getBits(1);
+ const int32_t BackElementTagSelect = br.getBits(4);
+ channelsNum += BackElementIsCpe ? 2 : 1;
+ }
+ channelsEffectiveNum = channelsNum;
+
+ for (i=0; i < NumLfeChannelElements; i++) {
+ const int32_t LfeElementTagSelect = br.getBits(4);
+ channelsNum += 1;
+ }
+ ALOGV("mpeg4 audio channelsNum = %d", channelsNum);
+ ALOGV("mpeg4 audio channelsEffectiveNum = %d", channelsEffectiveNum);
+ numChannels = channelsNum;
+ }
+ }
+ }
+
if (numChannels == 0) {
return ERROR_UNSUPPORTED;
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a0f17b5..0fa3b2d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -972,13 +972,16 @@ void MPEG4Writer::writeFtypBox(MetaData *param) {
if (param && param->findInt32(kKeyFileType, &fileType) &&
fileType != OUTPUT_FORMAT_MPEG_4) {
writeFourcc("3gp4");
+ writeInt32(0);
+ writeFourcc("isom");
+ writeFourcc("3gp4");
} else {
+ writeFourcc("mp42");
+ writeInt32(0);
writeFourcc("isom");
+ writeFourcc("mp42");
}
- writeInt32(0);
- writeFourcc("isom");
- writeFourcc("3gp4");
endBox();
}
@@ -1760,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;
@@ -1771,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> &notify);
+ 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> &notify) {
+ 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/SkipCutBuffer.cpp b/media/libstagefright/SkipCutBuffer.cpp
index 773854f..e2e6d79 100644
--- a/media/libstagefright/SkipCutBuffer.cpp
+++ b/media/libstagefright/SkipCutBuffer.cpp
@@ -25,7 +25,7 @@
namespace android {
SkipCutBuffer::SkipCutBuffer(int32_t skip, int32_t cut) {
- mFrontPadding = skip;
+ mFrontPadding = mSkip = skip;
mBackPadding = cut;
mWriteHead = 0;
mReadHead = 0;
@@ -94,6 +94,7 @@ void SkipCutBuffer::submit(const sp<ABuffer>& buffer) {
void SkipCutBuffer::clear() {
mWriteHead = mReadHead = 0;
+ mFrontPadding = mSkip;
}
void SkipCutBuffer::write(const char *src, size_t num) {
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/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 1b20cbb..2f5eff4 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -30,7 +30,7 @@
#define DRC_DEFAULT_MOBILE_REF_LEVEL 64 /* 64*-0.25dB = -16 dB below full scale for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_CUT 127 /* maximum compression of dynamic range for mobile conf */
#define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
-#define MAX_CHANNEL_COUNT 6 /* maximum number of audio channels that can be decoded */
+#define MAX_CHANNEL_COUNT 8 /* maximum number of audio channels that can be decoded */
// names of properties that can be used to override the default DRC settings
#define PROP_DRC_OVERRIDE_REF_LEVEL "aac_drc_reference_level"
#define PROP_DRC_OVERRIDE_CUT "aac_drc_cut"
@@ -58,6 +58,8 @@ SoftAAC2::SoftAAC2(
mIsADTS(false),
mInputBufferCount(0),
mSignalledError(false),
+ mSawInputEos(false),
+ mSignalledOutputEos(false),
mAnchorTimeUs(0),
mNumSamplesOutput(0),
mOutputPortSettingsChange(NONE) {
@@ -294,8 +296,11 @@ void SoftAAC2::maybeConfigureDownmix() const {
if (!(property_get("media.aac_51_output_enabled", value, NULL) &&
(!strcmp(value, "1") || !strcasecmp(value, "true")))) {
ALOGI("Downmixing multichannel AAC to stereo");
- aacDecoder_SetParam(mAACDecoder, AAC_PCM_OUTPUT_CHANNELS, 2);
+ aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, 2);
mStreamInfo->numChannels = 2;
+ // By default, the decoder creates a 5.1 channel downmix signal
+ // for seven and eight channel input streams. To enable 6.1 and 7.1 channel output
+ // use aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1)
}
}
}
@@ -350,115 +355,83 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
return;
}
- while (!inQueue.empty() && !outQueue.empty()) {
- BufferInfo *inInfo = *inQueue.begin();
- OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+ while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
+ BufferInfo *inInfo = NULL;
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
+ if (!inQueue.empty()) {
+ inInfo = *inQueue.begin();
+ inHeader = inInfo->mHeader;
+ }
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+ outHeader->nFlags = 0;
- if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- inQueue.erase(inQueue.begin());
- inInfo->mOwnedByUs = false;
- notifyEmptyBufferDone(inHeader);
-
- if (mDecoderHasData) {
- // flush out the decoder's delayed data by calling DecodeFrame
- // one more time, with the AACDEC_FLUSH flag set
- INT_PCM *outBuffer =
- reinterpret_cast<INT_PCM *>(
- outHeader->pBuffer + outHeader->nOffset);
-
- AAC_DECODER_ERROR decoderErr =
- aacDecoder_DecodeFrame(mAACDecoder,
- outBuffer,
- outHeader->nAllocLen,
- AACDEC_FLUSH);
- mDecoderHasData = false;
-
- if (decoderErr != AAC_DEC_OK) {
- mSignalledError = true;
-
- notify(OMX_EventError, OMX_ErrorUndefined, decoderErr,
- NULL);
-
- return;
- }
-
- outHeader->nFilledLen =
- mStreamInfo->frameSize
- * sizeof(int16_t)
- * mStreamInfo->numChannels;
- } else {
- // we never submitted any data to the decoder, so there's nothing to flush out
- outHeader->nFilledLen = 0;
+ if (inHeader) {
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ mSawInputEos = true;
}
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
-
- outQueue.erase(outQueue.begin());
- outInfo->mOwnedByUs = false;
- notifyFillBufferDone(outHeader);
- return;
- }
-
- if (inHeader->nOffset == 0) {
- mAnchorTimeUs = inHeader->nTimeStamp;
- mNumSamplesOutput = 0;
- }
+ if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumSamplesOutput = 0;
+ }
- size_t adtsHeaderSize = 0;
- if (mIsADTS) {
- // skip 30 bits, aac_frame_length follows.
- // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+ if (mIsADTS) {
+ size_t adtsHeaderSize = 0;
+ // skip 30 bits, aac_frame_length follows.
+ // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
- const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+ const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
- bool signalError = false;
- if (inHeader->nFilledLen < 7) {
- ALOGE("Audio data too short to contain even the ADTS header. "
- "Got %ld bytes.", inHeader->nFilledLen);
- hexdump(adtsHeader, inHeader->nFilledLen);
- signalError = true;
- } else {
- bool protectionAbsent = (adtsHeader[1] & 1);
-
- unsigned aac_frame_length =
- ((adtsHeader[3] & 3) << 11)
- | (adtsHeader[4] << 3)
- | (adtsHeader[5] >> 5);
-
- if (inHeader->nFilledLen < aac_frame_length) {
- ALOGE("Not enough audio data for the complete frame. "
- "Got %ld bytes, frame size according to the ADTS "
- "header is %u bytes.",
- inHeader->nFilledLen, aac_frame_length);
+ bool signalError = false;
+ if (inHeader->nFilledLen < 7) {
+ ALOGE("Audio data too short to contain even the ADTS header. "
+ "Got %ld bytes.", inHeader->nFilledLen);
hexdump(adtsHeader, inHeader->nFilledLen);
signalError = true;
} else {
- adtsHeaderSize = (protectionAbsent ? 7 : 9);
-
- inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
- inBufferLength[0] = aac_frame_length - adtsHeaderSize;
-
- inHeader->nOffset += adtsHeaderSize;
- inHeader->nFilledLen -= adtsHeaderSize;
+ bool protectionAbsent = (adtsHeader[1] & 1);
+
+ unsigned aac_frame_length =
+ ((adtsHeader[3] & 3) << 11)
+ | (adtsHeader[4] << 3)
+ | (adtsHeader[5] >> 5);
+
+ if (inHeader->nFilledLen < aac_frame_length) {
+ ALOGE("Not enough audio data for the complete frame. "
+ "Got %ld bytes, frame size according to the ADTS "
+ "header is %u bytes.",
+ inHeader->nFilledLen, aac_frame_length);
+ hexdump(adtsHeader, inHeader->nFilledLen);
+ signalError = true;
+ } else {
+ adtsHeaderSize = (protectionAbsent ? 7 : 9);
+
+ inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
+ inBufferLength[0] = aac_frame_length - adtsHeaderSize;
+
+ inHeader->nOffset += adtsHeaderSize;
+ inHeader->nFilledLen -= adtsHeaderSize;
+ }
}
- }
- if (signalError) {
- mSignalledError = true;
+ if (signalError) {
+ mSignalledError = true;
- notify(OMX_EventError,
- OMX_ErrorStreamCorrupt,
- ERROR_MALFORMED,
- NULL);
+ notify(OMX_EventError,
+ OMX_ErrorStreamCorrupt,
+ ERROR_MALFORMED,
+ NULL);
- return;
+ return;
+ }
+ } else {
+ inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
+ inBufferLength[0] = inHeader->nFilledLen;
}
} else {
- inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
- inBufferLength[0] = inHeader->nFilledLen;
+ inBufferLength[0] = 0;
}
// Fill and decode
@@ -471,50 +444,66 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
int prevNumChannels = mStreamInfo->numChannels;
AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS;
- while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+ while ((bytesValid[0] > 0 || mSawInputEos) && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+ mDecoderHasData |= (bytesValid[0] > 0);
aacDecoder_Fill(mAACDecoder,
inBuffer,
inBufferLength,
bytesValid);
- mDecoderHasData = true;
decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
outBuffer,
outHeader->nAllocLen,
0 /* flags */);
-
if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
- ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
+ if (mSawInputEos && bytesValid[0] <= 0) {
+ if (mDecoderHasData) {
+ // flush out the decoder's delayed data by calling DecodeFrame
+ // one more time, with the AACDEC_FLUSH flag set
+ decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
+ outBuffer,
+ outHeader->nAllocLen,
+ AACDEC_FLUSH);
+ mDecoderHasData = false;
+ }
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ mSignalledOutputEos = true;
+ break;
+ } else {
+ ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
+ }
}
}
size_t numOutBytes =
mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
- if (decoderErr == AAC_DEC_OK) {
- UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
- inHeader->nFilledLen -= inBufferUsedLength;
- inHeader->nOffset += inBufferUsedLength;
- } else {
- ALOGW("AAC decoder returned error %d, substituting silence",
- decoderErr);
+ if (inHeader) {
+ if (decoderErr == AAC_DEC_OK) {
+ UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+ inHeader->nFilledLen -= inBufferUsedLength;
+ inHeader->nOffset += inBufferUsedLength;
+ } else {
+ ALOGW("AAC decoder returned error %d, substituting silence",
+ decoderErr);
- memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
+ memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
- // Discard input buffer.
- inHeader->nFilledLen = 0;
+ // Discard input buffer.
+ inHeader->nFilledLen = 0;
- aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+ aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
- // fall through
- }
+ // fall through
+ }
- if (inHeader->nFilledLen == 0) {
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
}
/*
@@ -555,7 +544,6 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
// we've previously decoded valid data, in the latter case
// (decode failed) we'll output a silent frame.
outHeader->nFilledLen = numOutBytes;
- outHeader->nFlags = 0;
outHeader->nTimeStamp =
mAnchorTimeUs
@@ -582,6 +570,12 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) {
// depend on fragments from the last one decoded.
// drain all existing data
drainDecoder();
+ // force decoder loop to drop the first decoded buffer by resetting these state variables,
+ // but only if initialization has already happened.
+ if (mInputBufferCount != 0) {
+ mInputBufferCount = 1;
+ mStreamInfo->sampleRate = 0;
+ }
}
}
@@ -606,6 +600,8 @@ void SoftAAC2::onReset() {
mStreamInfo->sampleRate = 0;
mSignalledError = false;
+ mSawInputEos = false;
+ mSignalledOutputEos = false;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index 2d960ab..a7ea1e2 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -55,6 +55,8 @@ private:
bool mDecoderHasData;
size_t mInputBufferCount;
bool mSignalledError;
+ bool mSawInputEos;
+ bool mSignalledOutputEos;
int64_t mAnchorTimeUs;
int64_t mNumSamplesOutput;
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 7c382fb..61df65e 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -49,6 +49,8 @@ SoftMP3::SoftMP3(
mNumChannels(2),
mSamplingRate(44100),
mSignalledError(false),
+ mSawInputEos(false),
+ mSignalledOutputEos(false),
mOutputPortSettingsChange(NONE) {
initPorts();
initDecoder();
@@ -194,48 +196,36 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
- while (!inQueue.empty() && !outQueue.empty()) {
- BufferInfo *inInfo = *inQueue.begin();
- OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+ while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
+ BufferInfo *inInfo = NULL;
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
+ if (!inQueue.empty()) {
+ inInfo = *inQueue.begin();
+ inHeader = inInfo->mHeader;
+ }
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+ outHeader->nFlags = 0;
- if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- inQueue.erase(inQueue.begin());
- inInfo->mOwnedByUs = false;
- notifyEmptyBufferDone(inHeader);
-
- if (!mIsFirst) {
- // pad the end of the stream with 529 samples, since that many samples
- // were trimmed off the beginning when decoding started
- outHeader->nFilledLen =
- kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+ if (inHeader) {
+ if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumFramesOutput = 0;
+ }
- memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
- } else {
- // Since we never discarded frames from the start, we won't have
- // to add any padding at the end either.
- outHeader->nFilledLen = 0;
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ mSawInputEos = true;
}
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ mConfig->pInputBuffer =
+ inHeader->pBuffer + inHeader->nOffset;
- outQueue.erase(outQueue.begin());
- outInfo->mOwnedByUs = false;
- notifyFillBufferDone(outHeader);
- return;
- }
-
- if (inHeader->nOffset == 0) {
- mAnchorTimeUs = inHeader->nTimeStamp;
- mNumFramesOutput = 0;
+ mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+ } else {
+ mConfig->pInputBuffer = NULL;
+ mConfig->inputBufferCurrentLength = 0;
}
-
- mConfig->pInputBuffer =
- inHeader->pBuffer + inHeader->nOffset;
-
- mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
mConfig->inputBufferMaxLength = 0;
mConfig->inputBufferUsedLength = 0;
@@ -262,13 +252,28 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
}
- // This is recoverable, just ignore the current frame and
- // play silence instead.
- memset(outHeader->pBuffer,
- 0,
- mConfig->outputFrameSize * sizeof(int16_t));
-
- mConfig->inputBufferUsedLength = inHeader->nFilledLen;
+ if (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR && mSawInputEos) {
+ if (!mIsFirst) {
+ // pad the end of the stream with 529 samples, since that many samples
+ // were trimmed off the beginning when decoding started
+ outHeader->nOffset = 0;
+ outHeader->nFilledLen = kPVMP3DecoderDelay * mNumChannels * sizeof(int16_t);
+
+ memset(outHeader->pBuffer, 0, outHeader->nFilledLen);
+ }
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ mSignalledOutputEos = true;
+ } else {
+ // This is recoverable, just ignore the current frame and
+ // play silence instead.
+ memset(outHeader->pBuffer,
+ 0,
+ mConfig->outputFrameSize * sizeof(int16_t));
+
+ if (inHeader) {
+ mConfig->inputBufferUsedLength = inHeader->nFilledLen;
+ }
+ }
} else if (mConfig->samplingRate != mSamplingRate
|| mConfig->num_channels != mNumChannels) {
mSamplingRate = mConfig->samplingRate;
@@ -289,7 +294,7 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
outHeader->nFilledLen =
mConfig->outputFrameSize * sizeof(int16_t) - outHeader->nOffset;
- } else {
+ } else if (!mSignalledOutputEos) {
outHeader->nOffset = 0;
outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
}
@@ -298,23 +303,24 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
mAnchorTimeUs
+ (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;
- outHeader->nFlags = 0;
-
- CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
+ if (inHeader) {
+ CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
- inHeader->nOffset += mConfig->inputBufferUsedLength;
- inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
+ inHeader->nOffset += mConfig->inputBufferUsedLength;
+ inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
- mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
- if (inHeader->nFilledLen == 0) {
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ if (inHeader->nFilledLen == 0) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
}
+ mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
+
outInfo->mOwnedByUs = false;
outQueue.erase(outQueue.begin());
outInfo = NULL;
@@ -329,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;
}
}
@@ -362,6 +371,8 @@ void SoftMP3::onReset() {
pvmp3_InitDecoder(mConfig, mDecoderBuf);
mIsFirst = true;
mSignalledError = false;
+ mSawInputEos = false;
+ mSignalledOutputEos = false;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index 4af91ea..f9e7b53 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -61,6 +61,8 @@ private:
bool mIsFirst;
bool mSignalledError;
+ bool mSawInputEos;
+ bool mSignalledOutputEos;
enum {
NONE,
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 51bb958..515e4d3 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -54,6 +54,8 @@ SoftVorbis::SoftVorbis(
mAnchorTimeUs(0),
mNumFramesOutput(0),
mNumFramesLeftOnPage(-1),
+ mSawInputEos(false),
+ mSignalledOutputEos(false),
mOutputPortSettingsChange(NONE) {
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
@@ -290,48 +292,47 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
return;
}
- while (!inQueue.empty() && !outQueue.empty()) {
- BufferInfo *inInfo = *inQueue.begin();
- OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+ while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
+ BufferInfo *inInfo = NULL;
+ OMX_BUFFERHEADERTYPE *inHeader = NULL;
+ if (!inQueue.empty()) {
+ inInfo = *inQueue.begin();
+ inHeader = inInfo->mHeader;
+ }
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
- if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
- inQueue.erase(inQueue.begin());
- inInfo->mOwnedByUs = false;
- notifyEmptyBufferDone(inHeader);
+ int32_t numPageSamples = 0;
- outHeader->nFilledLen = 0;
- outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ if (inHeader) {
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ mSawInputEos = true;
+ }
- outQueue.erase(outQueue.begin());
- outInfo->mOwnedByUs = false;
- notifyFillBufferDone(outHeader);
- return;
- }
+ if (inHeader->nFilledLen || !mSawInputEos) {
+ CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
+ memcpy(&numPageSamples,
+ inHeader->pBuffer
+ + inHeader->nOffset + inHeader->nFilledLen - 4,
+ sizeof(numPageSamples));
- int32_t numPageSamples;
- CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
- memcpy(&numPageSamples,
- inHeader->pBuffer
- + inHeader->nOffset + inHeader->nFilledLen - 4,
- sizeof(numPageSamples));
+ if (inHeader->nOffset == 0) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mNumFramesOutput = 0;
+ }
- if (numPageSamples >= 0) {
- mNumFramesLeftOnPage = numPageSamples;
+ inHeader->nFilledLen -= sizeof(numPageSamples);;
+ }
}
- if (inHeader->nOffset == 0) {
- mAnchorTimeUs = inHeader->nTimeStamp;
- mNumFramesOutput = 0;
+ if (numPageSamples >= 0) {
+ mNumFramesLeftOnPage = numPageSamples;
}
- inHeader->nFilledLen -= sizeof(numPageSamples);;
-
ogg_buffer buf;
- buf.data = inHeader->pBuffer + inHeader->nOffset;
- buf.size = inHeader->nFilledLen;
+ buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL;
+ buf.size = inHeader ? inHeader->nFilledLen : 0;
buf.refcount = 1;
buf.ptr.owner = NULL;
@@ -351,6 +352,7 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
int numFrames = 0;
+ outHeader->nFlags = 0;
int err = vorbis_dsp_synthesis(mState, &pack, 1);
if (err != 0) {
ALOGW("vorbis_dsp_synthesis returned %d", err);
@@ -370,13 +372,16 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
ALOGV("discarding %d frames at end of page",
numFrames - mNumFramesLeftOnPage);
numFrames = mNumFramesLeftOnPage;
+ if (mSawInputEos) {
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ mSignalledOutputEos = true;
+ }
}
mNumFramesLeftOnPage -= numFrames;
}
outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels;
outHeader->nOffset = 0;
- outHeader->nFlags = 0;
outHeader->nTimeStamp =
mAnchorTimeUs
@@ -384,11 +389,13 @@ void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
mNumFramesOutput += numFrames;
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
+ if (inHeader) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ }
outInfo->mOwnedByUs = false;
outQueue.erase(outQueue.begin());
@@ -425,6 +432,8 @@ void SoftVorbis::onReset() {
mVi = NULL;
}
+ mSawInputEos = false;
+ mSignalledOutputEos = false;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index cb628a0..1d00816 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -59,6 +59,8 @@ private:
int64_t mAnchorTimeUs;
int64_t mNumFramesOutput;
int32_t mNumFramesLeftOnPage;
+ bool mSawInputEos;
+ bool mSignalledOutputEos;
enum {
NONE,
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> &notify, uint32_t flags, bool uidValid, uid_t uid)
+ const sp<AMessage> &notify, 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> &notify,
- 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/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 973b779..f095987 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -47,6 +47,7 @@ namespace android {
// static
const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll;
+const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
PlaylistFetcher::PlaylistFetcher(
const sp<AMessage> &notify,
@@ -61,6 +62,7 @@ PlaylistFetcher::PlaylistFetcher(
mSeqNumber(-1),
mNumRetries(0),
mStartup(true),
+ mPrepared(false),
mNextPTSTimeUs(-1ll),
mMonitorQueueGeneration(0),
mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY),
@@ -103,10 +105,16 @@ int64_t PlaylistFetcher::getSegmentStartTimeUs(int32_t seqNumber) const {
return segmentStartUs;
}
-bool PlaylistFetcher::timeToRefreshPlaylist(int64_t nowUs) const {
- if (mPlaylist == NULL) {
+int64_t PlaylistFetcher::delayUsToRefreshPlaylist() const {
+ int64_t nowUs = ALooper::GetNowUs();
+
+ if (mPlaylist == NULL || mLastPlaylistFetchTimeUs < 0ll) {
CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY);
- return true;
+ return 0ll;
+ }
+
+ if (mPlaylist->isComplete()) {
+ return (~0llu >> 1);
}
int32_t targetDurationSecs;
@@ -157,7 +165,8 @@ bool PlaylistFetcher::timeToRefreshPlaylist(int64_t nowUs) const {
break;
}
- return mLastPlaylistFetchTimeUs + minPlaylistAgeUs <= nowUs;
+ int64_t delayUs = mLastPlaylistFetchTimeUs + minPlaylistAgeUs - nowUs;
+ return delayUs > 0ll ? delayUs : 0ll;
}
status_t PlaylistFetcher::decryptBuffer(
@@ -274,7 +283,15 @@ status_t PlaylistFetcher::decryptBuffer(
return OK;
}
-void PlaylistFetcher::postMonitorQueue(int64_t delayUs) {
+void PlaylistFetcher::postMonitorQueue(int64_t delayUs, int64_t minDelayUs) {
+ int64_t maxDelayUs = delayUsToRefreshPlaylist();
+ if (maxDelayUs < minDelayUs) {
+ maxDelayUs = minDelayUs;
+ }
+ if (delayUs > maxDelayUs) {
+ ALOGV("Need to refresh playlist in %lld", maxDelayUs);
+ delayUs = maxDelayUs;
+ }
sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id());
msg->setInt32("generation", mMonitorQueueGeneration);
msg->post(delayUs);
@@ -415,6 +432,7 @@ status_t PlaylistFetcher::onStart(const sp<AMessage> &msg) {
if (mStartTimeUs >= 0ll) {
mSeqNumber = -1;
mStartup = true;
+ mPrepared = false;
}
postMonitorQueue();
@@ -456,40 +474,62 @@ void PlaylistFetcher::queueDiscontinuity(
void PlaylistFetcher::onMonitorQueue() {
bool downloadMore = false;
+ refreshPlaylist();
+
+ int32_t targetDurationSecs;
+ int64_t targetDurationUs = kMinBufferedDurationUs;
+ if (mPlaylist != NULL) {
+ CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
+ targetDurationUs = targetDurationSecs * 1000000ll;
+ }
- status_t finalResult;
+ // buffer at least 3 times the target duration, or up to 10 seconds
+ int64_t durationToBufferUs = targetDurationUs * 3;
+ if (durationToBufferUs > kMinBufferedDurationUs) {
+ durationToBufferUs = kMinBufferedDurationUs;
+ }
+
+ int64_t bufferedDurationUs = 0ll;
+ status_t finalResult = NOT_ENOUGH_DATA;
if (mStreamTypeMask == LiveSession::STREAMTYPE_SUBTITLES) {
sp<AnotherPacketSource> packetSource =
mPacketSources.valueFor(LiveSession::STREAMTYPE_SUBTITLES);
- int64_t bufferedDurationUs =
+ bufferedDurationUs =
packetSource->getBufferedDurationUs(&finalResult);
-
- downloadMore = (bufferedDurationUs < kMinBufferedDurationUs);
finalResult = OK;
} else {
bool first = true;
- int64_t minBufferedDurationUs = 0ll;
for (size_t i = 0; i < mPacketSources.size(); ++i) {
if ((mStreamTypeMask & mPacketSources.keyAt(i)) == 0) {
continue;
}
- int64_t bufferedDurationUs =
+ int64_t bufferedStreamDurationUs =
mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult);
-
- if (first || bufferedDurationUs < minBufferedDurationUs) {
- minBufferedDurationUs = bufferedDurationUs;
+ if (first || bufferedStreamDurationUs < bufferedDurationUs) {
+ bufferedDurationUs = bufferedStreamDurationUs;
first = false;
}
}
+ }
+ downloadMore = (bufferedDurationUs < durationToBufferUs);
- downloadMore =
- !first && (minBufferedDurationUs < kMinBufferedDurationUs);
+ // signal start if buffered up at least the target size
+ if (!mPrepared && bufferedDurationUs > targetDurationUs && downloadMore) {
+ mPrepared = true;
+
+ ALOGV("prepared, buffered=%lld > %lld",
+ bufferedDurationUs, targetDurationUs);
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatTemporarilyDoneFetching);
+ msg->post();
}
if (finalResult == OK && downloadMore) {
+ ALOGV("monitoring, buffered=%lld < %lld",
+ bufferedDurationUs, durationToBufferUs);
onDownloadNext();
} else {
// Nothing to do yet, try again in a second.
@@ -498,15 +538,17 @@ void PlaylistFetcher::onMonitorQueue() {
msg->setInt32("what", kWhatTemporarilyDoneFetching);
msg->post();
- postMonitorQueue(1000000ll);
+ int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2;
+ ALOGV("pausing for %lld, buffered=%lld > %lld",
+ delayUs, bufferedDurationUs, durationToBufferUs);
+ // :TRICKY: need to enforce minimum delay because the delay to
+ // refresh the playlist will become 0
+ postMonitorQueue(delayUs, mPrepared ? targetDurationUs * 2 : 0);
}
}
-void PlaylistFetcher::onDownloadNext() {
- int64_t nowUs = ALooper::GetNowUs();
-
- if (mLastPlaylistFetchTimeUs < 0ll
- || (!mPlaylist->isComplete() && timeToRefreshPlaylist(nowUs))) {
+status_t PlaylistFetcher::refreshPlaylist() {
+ if (delayUsToRefreshPlaylist() <= 0) {
bool unchanged;
sp<M3UParser> playlist = mSession->fetchPlaylist(
mURI.c_str(), mPlaylistHash, &unchanged);
@@ -522,7 +564,7 @@ void PlaylistFetcher::onDownloadNext() {
} else {
ALOGE("failed to load playlist at url '%s'", mURI.c_str());
notifyError(ERROR_IO);
- return;
+ return ERROR_IO;
}
} else {
mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY;
@@ -535,6 +577,13 @@ void PlaylistFetcher::onDownloadNext() {
mLastPlaylistFetchTimeUs = ALooper::GetNowUs();
}
+ return OK;
+}
+
+void PlaylistFetcher::onDownloadNext() {
+ if (refreshPlaylist() != OK) {
+ return;
+ }
int32_t firstSeqNumberInPlaylist;
if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
@@ -553,12 +602,18 @@ void PlaylistFetcher::onDownloadNext() {
if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
mSeqNumber = getSeqNumberForTime(mStartTimeUs);
+ ALOGV("Initial sequence number for time %lld is %ld from (%ld .. %ld)",
+ mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist,
+ lastSeqNumberInPlaylist);
} else {
// If this is a live session, start 3 segments from the end.
mSeqNumber = lastSeqNumberInPlaylist - 3;
if (mSeqNumber < firstSeqNumberInPlaylist) {
mSeqNumber = firstSeqNumberInPlaylist;
}
+ ALOGV("Initial sequence number for live event %ld from (%ld .. %ld)",
+ mSeqNumber, firstSeqNumberInPlaylist,
+ lastSeqNumberInPlaylist);
}
mStartTimeUs = -1ll;
@@ -570,16 +625,34 @@ void PlaylistFetcher::onDownloadNext() {
++mNumRetries;
if (mSeqNumber > lastSeqNumberInPlaylist) {
- mLastPlaylistFetchTimeUs = -1;
- postMonitorQueue(3000000ll);
+ // refresh in increasing fraction (1/2, 1/3, ...) of the
+ // playlist's target duration or 3 seconds, whichever is less
+ int32_t targetDurationSecs;
+ CHECK(mPlaylist->meta()->findInt32(
+ "target-duration", &targetDurationSecs));
+ int64_t delayUs = mPlaylist->size() * targetDurationSecs *
+ 1000000ll / (1 + mNumRetries);
+ if (delayUs > kMaxMonitorDelayUs) {
+ delayUs = kMaxMonitorDelayUs;
+ }
+ ALOGV("sequence number high: %ld from (%ld .. %ld), monitor in %lld (retry=%d)",
+ mSeqNumber, firstSeqNumberInPlaylist,
+ lastSeqNumberInPlaylist, delayUs, mNumRetries);
+ postMonitorQueue(delayUs);
return;
}
// we've missed the boat, let's start from the lowest sequence
// number available and signal a discontinuity.
- ALOGI("We've missed the boat, restarting playback.");
- mSeqNumber = lastSeqNumberInPlaylist;
+ ALOGI("We've missed the boat, restarting playback."
+ " mStartup=%d, was looking for %d in %d-%d",
+ mStartup, mSeqNumber, firstSeqNumberInPlaylist,
+ lastSeqNumberInPlaylist);
+ mSeqNumber = lastSeqNumberInPlaylist - 3;
+ if (mSeqNumber < firstSeqNumberInPlaylist) {
+ mSeqNumber = firstSeqNumberInPlaylist;
+ }
explicitDiscontinuity = true;
// fall through
@@ -788,12 +861,13 @@ status_t PlaylistFetcher::extractAndQueueAccessUnits(
&& source->dequeueAccessUnit(&accessUnit) == OK) {
// Note that we do NOT dequeue any discontinuities.
+ // for simplicity, store a reference to the format in each unit
+ sp<MetaData> format = source->getFormat();
+ if (format != NULL) {
+ accessUnit->meta()->setObject("format", format);
+ }
packetSource->queueAccessUnit(accessUnit);
}
-
- if (packetSource->getFormat() == NULL) {
- packetSource->setFormat(source->getFormat());
- }
}
return OK;
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 1648e02..78dea20 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -79,6 +79,7 @@ private:
};
static const int64_t kMinBufferedDurationUs;
+ static const int64_t kMaxMonitorDelayUs;
sp<AMessage> mNotify;
sp<LiveSession> mSession;
@@ -97,6 +98,7 @@ private:
int32_t mSeqNumber;
int32_t mNumRetries;
bool mStartup;
+ bool mPrepared;
int64_t mNextPTSTimeUs;
int32_t mMonitorQueueGeneration;
@@ -120,10 +122,11 @@ private:
status_t decryptBuffer(
size_t playlistIndex, const sp<ABuffer> &buffer);
- void postMonitorQueue(int64_t delayUs = 0);
+ void postMonitorQueue(int64_t delayUs = 0, int64_t minDelayUs = 0);
void cancelMonitorQueue();
- bool timeToRefreshPlaylist(int64_t nowUs) const;
+ int64_t delayUsToRefreshPlaylist() const;
+ status_t refreshPlaylist();
// Returns the media time in us of the segment specified by seqNumber.
// This is computed by summing the durations of all segments before it.
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 1ec4a40..f0f203c 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -468,49 +468,6 @@ void ID3::Iterator::getID(String8 *id) const {
}
}
-static void convertISO8859ToString8(
- const uint8_t *data, size_t size,
- String8 *s) {
- size_t utf8len = 0;
- for (size_t i = 0; i < size; ++i) {
- if (data[i] == '\0') {
- size = i;
- break;
- } else if (data[i] < 0x80) {
- ++utf8len;
- } else {
- utf8len += 2;
- }
- }
-
- if (utf8len == size) {
- // Only ASCII characters present.
-
- s->setTo((const char *)data, size);
- return;
- }
-
- char *tmp = new char[utf8len];
- char *ptr = tmp;
- for (size_t i = 0; i < size; ++i) {
- if (data[i] == '\0') {
- break;
- } else if (data[i] < 0x80) {
- *ptr++ = data[i];
- } else if (data[i] < 0xc0) {
- *ptr++ = 0xc2;
- *ptr++ = data[i];
- } else {
- *ptr++ = 0xc3;
- *ptr++ = data[i] - 64;
- }
- }
-
- s->setTo(tmp, utf8len);
-
- delete[] tmp;
- tmp = NULL;
-}
// the 2nd argument is used to get the data following the \0 in a comment field
void ID3::Iterator::getString(String8 *id, String8 *comment) const {
@@ -543,7 +500,9 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
return;
}
- convertISO8859ToString8(frameData, mFrameSize, id);
+ // this is supposed to be ISO-8859-1, but pass it up as-is to the caller, who will figure
+ // out the real encoding
+ id->setTo((const char*)frameData, mFrameSize);
return;
}
@@ -561,13 +520,13 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
}
if (encoding == 0x00) {
- // ISO 8859-1
- convertISO8859ToString8(frameData + 1, n, id);
+ // supposedly ISO 8859-1
+ id->setTo((const char*)frameData + 1, n);
} else if (encoding == 0x03) {
- // UTF-8
+ // supposedly UTF-8
id->setTo((const char *)(frameData + 1), n);
} else if (encoding == 0x02) {
- // UTF-16 BE, no byte order mark.
+ // supposedly UTF-16 BE, no byte order mark.
// API wants number of characters, not number of bytes...
int len = n / 2;
const char16_t *framedata = (const char16_t *) (frameData + 1);
@@ -583,7 +542,7 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
if (framedatacopy != NULL) {
delete[] framedatacopy;
}
- } else {
+ } else if (encoding == 0x01) {
// UCS-2
// API wants number of characters, not number of bytes...
int len = n / 2;
@@ -602,7 +561,27 @@ void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
framedata++;
len--;
}
- id->setTo(framedata, len);
+
+ // check if the resulting data consists entirely of 8-bit values
+ bool eightBit = true;
+ for (int i = 0; i < len; i++) {
+ if (framedata[i] > 0xff) {
+ eightBit = false;
+ break;
+ }
+ }
+ if (eightBit) {
+ // collapse to 8 bit, then let the media scanner client figure out the real encoding
+ char *frame8 = new char[len];
+ for (int i = 0; i < len; i++) {
+ frame8[i] = framedata[i];
+ }
+ id->setTo(frame8, len);
+ delete [] frame8;
+ } else {
+ id->setTo(framedata, len);
+ }
+
if (framedatacopy != NULL) {
delete[] framedatacopy;
}
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> &notify, uint32_t flags = 0, bool uidValid = false, uid_t uid = 0);
+ SDPLoader(
+ const sp<AMessage> &notify,
+ 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/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 3153c8b..52fb2a5 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -70,7 +70,27 @@ status_t AnotherPacketSource::stop() {
}
sp<MetaData> AnotherPacketSource::getFormat() {
- return mFormat;
+ Mutex::Autolock autoLock(mLock);
+ if (mFormat != NULL) {
+ return mFormat;
+ }
+
+ List<sp<ABuffer> >::iterator it = mBuffers.begin();
+ while (it != mBuffers.end()) {
+ sp<ABuffer> buffer = *it;
+ int32_t discontinuity;
+ if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
+ break;
+ }
+
+ sp<RefBase> object;
+ if (buffer->meta()->findObject("format", &object)) {
+ return static_cast<MetaData*>(object.get());
+ }
+
+ ++it;
+ }
+ return NULL;
}
status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
@@ -94,6 +114,11 @@ status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
return INFO_DISCONTINUITY;
}
+ sp<RefBase> object;
+ if ((*buffer)->meta()->findObject("format", &object)) {
+ mFormat = static_cast<MetaData*>(object.get());
+ }
+
return OK;
}
@@ -120,17 +145,22 @@ status_t AnotherPacketSource::read(
}
return INFO_DISCONTINUITY;
- } else {
- int64_t timeUs;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+ }
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+ sp<RefBase> object;
+ if (buffer->meta()->findObject("format", &object)) {
+ mFormat = static_cast<MetaData*>(object.get());
+ }
- mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+ int64_t timeUs;
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- *out = mediaBuffer;
- return OK;
- }
+ MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
+
+ mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+ *out = mediaBuffer;
+ return OK;
}
return mEOSResult;
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index b8970ad..1e6de55 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -42,7 +42,12 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance,
mEndOfStream(false),
mEndOfStreamSent(false),
mRepeatAfterUs(-1ll),
+ mMaxTimestampGapUs(-1ll),
+ mPrevOriginalTimeUs(-1ll),
+ mPrevModifiedTimeUs(-1ll),
+ mSkipFramesBeforeNs(-1ll),
mRepeatLastFrameGeneration(0),
+ mRepeatLastFrameTimestamp(-1ll),
mLatestSubmittedBufferId(-1),
mLatestSubmittedBufferFrameNum(0),
mLatestSubmittedBufferUseCount(0),
@@ -299,6 +304,32 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {
return;
}
+void GraphicBufferSource::codecBufferFilled(OMX_BUFFERHEADERTYPE* header) {
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mMaxTimestampGapUs > 0ll
+ && !(header->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
+ ssize_t index = mOriginalTimeUs.indexOfKey(header->nTimeStamp);
+ if (index >= 0) {
+ ALOGV("OUT timestamp: %lld -> %lld",
+ header->nTimeStamp, mOriginalTimeUs[index]);
+ header->nTimeStamp = mOriginalTimeUs[index];
+ mOriginalTimeUs.removeItemsAt(index);
+ } else {
+ // giving up the effort as encoder doesn't appear to preserve pts
+ ALOGW("giving up limiting timestamp gap (pts = %lld)",
+ header->nTimeStamp);
+ mMaxTimestampGapUs = -1ll;
+ }
+ if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) {
+ // something terribly wrong must have happened, giving up...
+ ALOGE("mOriginalTimeUs has too many entries (%d)",
+ mOriginalTimeUs.size());
+ mMaxTimestampGapUs = -1ll;
+ }
+ }
+}
+
void GraphicBufferSource::suspend(bool suspend) {
Mutex::Autolock autoLock(mMutex);
@@ -384,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,
@@ -431,6 +473,7 @@ bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() {
BufferQueue::BufferItem item;
item.mBuf = mLatestSubmittedBufferId;
item.mFrameNumber = mLatestSubmittedBufferFrameNum;
+ item.mTimestamp = mRepeatLastFrameTimestamp;
status_t err = submitBuffer_l(item, cbi);
@@ -440,6 +483,20 @@ bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() {
++mLatestSubmittedBufferUseCount;
+ /* repeat last frame up to kRepeatLastFrameCount times.
+ * in case of static scene, a single repeat might not get rid of encoder
+ * ghosting completely, refresh a couple more times to get better quality
+ */
+ if (--mRepeatLastFrameCount > 0) {
+ mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
+
+ if (mReflector != NULL) {
+ sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id());
+ msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+ msg->post(mRepeatAfterUs);
+ }
+ }
+
return true;
}
@@ -460,8 +517,11 @@ void GraphicBufferSource::setLatestSubmittedBuffer_l(
mLatestSubmittedBufferId = item.mBuf;
mLatestSubmittedBufferFrameNum = item.mFrameNumber;
+ mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
+
mLatestSubmittedBufferUseCount = 1;
mRepeatBufferDeferred = false;
+ mRepeatLastFrameCount = kRepeatLastFrameCount;
if (mReflector != NULL) {
sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id());
@@ -497,6 +557,39 @@ status_t GraphicBufferSource::signalEndOfInputStream() {
return OK;
}
+int64_t GraphicBufferSource::getTimestamp(const BufferQueue::BufferItem &item) {
+ int64_t timeUs = item.mTimestamp / 1000;
+
+ if (mMaxTimestampGapUs > 0ll) {
+ /* Cap timestamp gap between adjacent frames to specified max
+ *
+ * In the scenario of cast mirroring, encoding could be suspended for
+ * prolonged periods. Limiting the pts gap to workaround the problem
+ * where encoder's rate control logic produces huge frames after a
+ * long period of suspension.
+ */
+
+ int64_t originalTimeUs = timeUs;
+ if (mPrevOriginalTimeUs >= 0ll) {
+ if (originalTimeUs < mPrevOriginalTimeUs) {
+ // Drop the frame if it's going backward in time. Bad timestamp
+ // could disrupt encoder's rate control completely.
+ ALOGV("Dropping frame that's going backward in time");
+ return -1;
+ }
+ int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
+ timeUs = (timestampGapUs < mMaxTimestampGapUs ?
+ timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+ }
+ mPrevOriginalTimeUs = originalTimeUs;
+ mPrevModifiedTimeUs = timeUs;
+ mOriginalTimeUs.add(timeUs, originalTimeUs);
+ ALOGV("IN timestamp: %lld -> %lld", originalTimeUs, timeUs);
+ }
+
+ return timeUs;
+}
+
status_t GraphicBufferSource::submitBuffer_l(
const BufferQueue::BufferItem &item, int cbi) {
ALOGV("submitBuffer_l cbi=%d", cbi);
@@ -513,9 +606,15 @@ status_t GraphicBufferSource::submitBuffer_l(
memcpy(data, &type, 4);
memcpy(data + 4, &handle, sizeof(buffer_handle_t));
+ int64_t timeUs = getTimestamp(item);
+ if (timeUs < 0ll) {
+ ALOGE("Dropping frame with bad timestamp");
+ return UNKNOWN_ERROR;
+ }
+
status_t err = mNodeInstance->emptyDirectBuffer(header, 0,
4 + sizeof(buffer_handle_t), OMX_BUFFERFLAG_ENDOFFRAME,
- item.mTimestamp / 1000);
+ timeUs);
if (err != OK) {
ALOGW("WARNING: emptyDirectBuffer failed: 0x%x", err);
codecBuffer.mGraphicBuffer = NULL;
@@ -609,6 +708,12 @@ void GraphicBufferSource::onFrameAvailable() {
BufferQueue::BufferItem item;
status_t err = mBufferQueue->acquireBuffer(&item, 0);
if (err == OK) {
+ // If this is the first time we're seeing this buffer, add it to our
+ // slot table.
+ if (item.mGraphicBuffer != NULL) {
+ ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
+ mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+ }
mBufferQueue->releaseBuffer(item.mBuf, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence);
}
@@ -658,6 +763,25 @@ status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs(
return OK;
}
+status_t GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) {
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting || maxGapUs <= 0ll) {
+ return INVALID_OPERATION;
+ }
+
+ mMaxTimestampGapUs = 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 9e5eee6..153f2a0 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -87,6 +87,10 @@ public:
// fill it with a new frame of data; otherwise, just mark it as available.
void codecBufferEmptied(OMX_BUFFERHEADERTYPE* header);
+ // Called when omx_message::FILL_BUFFER_DONE is received. (Currently the
+ // buffer source will fix timestamp in the header if needed.)
+ void codecBufferFilled(OMX_BUFFERHEADERTYPE* header);
+
// This is called after the last input frame has been submitted. We
// need to submit an empty buffer with the EOS flag set. If we don't
// have a codec buffer ready, we just set the mEndOfStream flag.
@@ -105,6 +109,19 @@ public:
// state and once this behaviour is specified it cannot be reset.
status_t setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs);
+ // When set, the timestamp fed to the encoder will be modified such that
+ // the gap between two adjacent frames is capped at maxGapUs. Timestamp
+ // will be restored to the original when the encoded frame is returned to
+ // the client.
+ // This is to solve a problem in certain real-time streaming case, where
+ // encoder's rate control logic produces huge frames after a long period
+ // 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
@@ -165,6 +182,7 @@ private:
void setLatestSubmittedBuffer_l(const BufferQueue::BufferItem &item);
bool repeatLatestSubmittedBuffer_l();
+ int64_t getTimestamp(const BufferQueue::BufferItem &item);
// Lock, covers all member variables.
mutable Mutex mMutex;
@@ -206,13 +224,23 @@ private:
enum {
kWhatRepeatLastFrame,
};
+ enum {
+ kRepeatLastFrameCount = 10,
+ };
- int64_t mRepeatAfterUs;
+ 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;
int mLatestSubmittedBufferId;
uint64_t mLatestSubmittedBufferFrameNum;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 5f104fc..dba522f 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -849,6 +849,8 @@ status_t OMXNodeInstance::setInternalOption(
switch (type) {
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();
@@ -864,7 +866,8 @@ status_t OMXNodeInstance::setInternalOption(
bool suspend = *(bool *)data;
bufferSource->suspend(suspend);
- } else {
+ } else if (type ==
+ IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY){
if (size != sizeof(int64_t)) {
return INVALID_OPERATION;
}
@@ -872,6 +875,23 @@ status_t OMXNodeInstance::setInternalOption(
int64_t delayUs = *(int64_t *)data;
return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
+ } else if (type ==
+ IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP){
+ if (size != sizeof(int64_t)) {
+ return INVALID_OPERATION;
+ }
+
+ 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;
@@ -883,6 +903,8 @@ status_t OMXNodeInstance::setInternalOption(
}
void OMXNodeInstance::onMessage(const omx_message &msg) {
+ const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
+
if (msg.type == omx_message::FILL_BUFFER_DONE) {
OMX_BUFFERHEADERTYPE *buffer =
static_cast<OMX_BUFFERHEADERTYPE *>(
@@ -892,10 +914,18 @@ void OMXNodeInstance::onMessage(const omx_message &msg) {
static_cast<BufferMeta *>(buffer->pAppPrivate);
buffer_meta->CopyFromOMX(buffer);
- } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
- const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
if (bufferSource != NULL) {
+ // fix up the buffer info (especially timestamp) if needed
+ bufferSource->codecBufferFilled(buffer);
+
+ omx_message newMsg = msg;
+ newMsg.u.extended_buffer_data.timestamp = buffer->nTimeStamp;
+ mObserver->onMessage(newMsg);
+ return;
+ }
+ } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
+ if (bufferSource != NULL) {
// This is one of the buffers used exclusively by
// GraphicBufferSource.
// Don't dispatch a message back to ACodec, since it doesn't
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> &notify, uint32_t flags, bool uidValid, uid_t uid)
+SDPLoader::SDPLoader(
+ const sp<AMessage> &notify,
+ 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/timedtext/test/Android.mk b/media/libstagefright/timedtext/test/Android.mk
index a5e7ba2..9a9fde2 100644
--- a/media/libstagefright/timedtext/test/Android.mk
+++ b/media/libstagefright/timedtext/test/Android.mk
@@ -2,7 +2,6 @@ LOCAL_PATH:= $(call my-dir)
# ================================================================
# Unit tests for libstagefright_timedtext
-# See also /development/testrunner/test_defs.xml
# ================================================================
# ================================================================
@@ -18,10 +17,13 @@ LOCAL_SRC_FILES := TimedTextSRTSource_test.cpp
LOCAL_C_INCLUDES := \
$(TOP)/external/expat/lib \
- $(TOP)/frameworks/base/media/libstagefright/timedtext
+ $(TOP)/frameworks/av/media/libstagefright/timedtext
LOCAL_SHARED_LIBRARIES := \
+ libbinder \
libexpat \
- libstagefright
+ libstagefright \
+ libstagefright_foundation \
+ libutils
include $(BUILD_NATIVE_TEST)
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/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index edcc087..50d317a 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -216,7 +216,7 @@ sp<ABuffer> TSPacketizer::Track::prependADTSHeader(
uint8_t *ptr = dup->data();
*ptr++ = 0xff;
- *ptr++ = 0xf1; // b11110001, ID=0, layer=0, protection_absent=1
+ *ptr++ = 0xf9; // b11111001, ID=1(MPEG-2), layer=0, protection_absent=1
*ptr++ =
profile << 6
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 1ac647a..f848054 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES := \
libaudioflinger \
+ libcamera_metadata\
libcameraservice \
libmedialogservice \
libcutils \
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];