diff options
Diffstat (limited to 'media')
67 files changed, 1704 insertions, 717 deletions
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 961b0a2..a7bf380 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -471,7 +471,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId); - if (input == 0) { + if (input == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, " "channel mask %#x, session %d", mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId); diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 140fb66..2f16444 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -35,9 +35,9 @@ Mutex AudioSystem::gLock; sp<IAudioFlinger> AudioSystem::gAudioFlinger; sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; -// Cached values -DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0); +// Cached values for output handles +DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(NULL); // Cached values for recording queries, all protected by gLock uint32_t AudioSystem::gPrevInSamplingRate; @@ -196,12 +196,12 @@ String8 AudioSystem::getParameters(audio_io_handle_t ioHandle, const String8& ke status_t AudioSystem::setParameters(const String8& keyValuePairs) { - return setParameters((audio_io_handle_t) 0, keyValuePairs); + return setParameters(AUDIO_IO_HANDLE_NONE, keyValuePairs); } String8 AudioSystem::getParameters(const String8& keys) { - return getParameters((audio_io_handle_t) 0, keys); + return getParameters(AUDIO_IO_HANDLE_NONE, keys); } // convert volume steps to natural log scale @@ -284,7 +284,7 @@ status_t AudioSystem::getOutputFrameCount(size_t* frameCount, audio_stream_type_ } output = getOutput(streamType); - if (output == 0) { + if (output == AUDIO_IO_HANDLE_NONE) { return PERMISSION_DENIED; } @@ -329,15 +329,14 @@ status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t st } output = getOutput(streamType); - if (output == 0) { + if (output == AUDIO_IO_HANDLE_NONE) { return PERMISSION_DENIED; } - return getLatency(output, streamType, latency); + return getLatency(output, latency); } status_t AudioSystem::getLatency(audio_io_handle_t output, - audio_stream_type_t streamType __unused, uint32_t* latency) { OutputDescriptor *outputDesc; @@ -354,7 +353,7 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, gLock.unlock(); } - ALOGV("getLatency() streamType %d, output %d, latency %d", streamType, output, *latency); + ALOGV("getLatency() output %d, latency %d", output, *latency); return NO_ERROR; } @@ -401,19 +400,11 @@ status_t AudioSystem::setVoiceVolume(float value) } status_t AudioSystem::getRenderPosition(audio_io_handle_t output, uint32_t *halFrames, - uint32_t *dspFrames, audio_stream_type_t stream) + uint32_t *dspFrames) { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - if (stream == AUDIO_STREAM_DEFAULT) { - stream = AUDIO_STREAM_MUSIC; - } - - if (output == 0) { - output = getOutput(stream); - } - return af->getRenderPosition(halFrames, dspFrames, output); } @@ -422,7 +413,7 @@ uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); uint32_t result = 0; if (af == 0) return result; - if (ioHandle == 0) return result; + if (ioHandle == AUDIO_IO_HANDLE_NONE) return result; result = af->getInputFramesLost(ioHandle); return result; @@ -431,7 +422,7 @@ uint32_t AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) int AudioSystem::newAudioSessionId() { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); - if (af == 0) return 0; + if (af == 0) return AUDIO_SESSION_ALLOCATE; return af->newAudioSessionId(); } @@ -473,7 +464,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, audio_io_handle const OutputDescriptor *desc; audio_stream_type_t stream; - if (ioHandle == 0) return; + if (ioHandle == AUDIO_IO_HANDLE_NONE) return; Mutex::Autolock _l(AudioSystem::gLock); @@ -739,7 +730,7 @@ uint32_t AudioSystem::getStrategyForStream(audio_stream_type_t stream) audio_devices_t AudioSystem::getDevicesForStream(audio_stream_type_t stream) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); - if (aps == 0) return (audio_devices_t)0; + if (aps == 0) return AUDIO_DEVICE_NONE; return aps->getDevicesForStream(stream); } @@ -747,7 +738,7 @@ audio_io_handle_t AudioSystem::getOutputForEffect(const effect_descriptor_t *des { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); // FIXME change return type to status_t, and return PERMISSION_DENIED here - if (aps == 0) return 0; + if (aps == 0) return AUDIO_IO_HANDLE_NONE; return aps->getOutputForEffect(desc); } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 60ed626..fbfd3da 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -333,8 +333,8 @@ status_t AudioTrack::set( mOffloadInfo = NULL; } - mVolume[LEFT] = 1.0f; - mVolume[RIGHT] = 1.0f; + mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f; + mVolume[AUDIO_INTERLEAVE_RIGHT] = 1.0f; mSendLevel = 0.0f; // mFrameCount is initialized in createTrack_l mReqFrameCount = frameCount; @@ -371,16 +371,6 @@ 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. - if (mOutput != 0) { - AudioSystem::releaseOutput(mOutput); - mOutput = 0; - } -#endif return status; } @@ -556,7 +546,7 @@ void AudioTrack::pause() mAudioTrack->pause(); if (isOffloaded_l()) { - if (mOutput != 0) { + if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t halFrames; // OffloadThread sends HAL pause in its threadLoop.. time saved // here can be slightly off @@ -573,8 +563,8 @@ status_t AudioTrack::setVolume(float left, float right) } AutoMutex lock(mLock); - mVolume[LEFT] = left; - mVolume[RIGHT] = right; + mVolume[AUDIO_INTERLEAVE_LEFT] = left; + mVolume[AUDIO_INTERLEAVE_RIGHT] = right; mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000)); @@ -643,7 +633,7 @@ uint32_t AudioTrack::getSampleRate() const // query the HAL and update if needed. // FIXME use Proxy return channel to update the rate from server and avoid polling here if (isOffloaded_l()) { - if (mOutput != 0) { + if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t sampleRate = 0; status_t status = AudioSystem::getSamplingRate(mOutput, mStreamType, &sampleRate); if (status == NO_ERROR) { @@ -789,7 +779,7 @@ status_t AudioTrack::getPosition(uint32_t *position) const return NO_ERROR; } - if (mOutput != 0) { + if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t halFrames; AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames); } @@ -865,7 +855,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) audio_io_handle_t output = AudioSystem::getOutput(mStreamType, mSampleRate, mFormat, mChannelMask, mFlags, mOffloadInfo); - if (output == 0) { + if (output == AUDIO_IO_HANDLE_NONE) { 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); @@ -878,7 +868,7 @@ status_t AudioTrack::createTrack_l(size_t epoch) // 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, mStreamType, &afLatency); + status = AudioSystem::getLatency(output, &afLatency); if (status != NO_ERROR) { ALOGE("getLatency(%d) failed status %d", output, status); goto release; @@ -1024,7 +1014,6 @@ status_t AudioTrack::createTrack_l(size_t epoch) output, tid, &mSessionId, - mName, mClientUid, &status); @@ -1135,8 +1124,8 @@ status_t AudioTrack::createTrack_l(size_t epoch) mStaticProxy = new StaticAudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF); mProxy = mStaticProxy; } - mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | - uint16_t(mVolume[LEFT] * 0x1000)); + mProxy->setVolumeLR((uint32_t(uint16_t(mVolume[AUDIO_INTERLEAVE_RIGHT] * 0x1000)) << 16) | + uint16_t(mVolume[AUDIO_INTERLEAVE_LEFT] * 0x1000)); mProxy->setSendLevel(mSendLevel); mProxy->setSampleRate(mSampleRate); mProxy->setEpoch(epoch); @@ -1281,8 +1270,7 @@ void AudioTrack::releaseBuffer(Buffer* audioBuffer) if (mState == STATE_ACTIVE) { audio_track_cblk_t* cblk = mCblk; if (android_atomic_and(~CBLK_DISABLED, &cblk->mFlags) & CBLK_DISABLED) { - ALOGW("releaseBuffer() track %p name=%s disabled due to previous underrun, restarting", - this, mName.string()); + ALOGW("releaseBuffer() track %p disabled due to previous underrun, restarting", this); // FIXME ignoring status mAudioTrack->start(); } @@ -1777,16 +1765,6 @@ 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. - if (mOutput != 0) { - AudioSystem::releaseOutput(mOutput); - mOutput = 0; - } -#endif ALOGW("restoreTrack_l() failed status %d", result); mState = STATE_STOPPED; } @@ -1820,7 +1798,7 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) String8 AudioTrack::getParameters(const String8& keys) { audio_io_handle_t output = getOutput(); - if (output != 0) { + if (output != AUDIO_IO_HANDLE_NONE) { return AudioSystem::getParameters(output, keys); } else { return String8::empty(); diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp index fdd1a12..58c9fc1 100644 --- a/media/libmedia/AudioTrackShared.cpp +++ b/media/libmedia/AudioTrackShared.cpp @@ -200,7 +200,7 @@ status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *reques ts = &remaining; break; default: - LOG_FATAL("obtainBuffer() timeout=%d", timeout); + LOG_ALWAYS_FATAL("obtainBuffer() timeout=%d", timeout); ts = NULL; break; } @@ -429,7 +429,7 @@ status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *request ts = &remaining; break; default: - LOG_FATAL("waitStreamEndDone() timeout=%d", timeout); + LOG_ALWAYS_FATAL("waitStreamEndDone() timeout=%d", timeout); ts = NULL; break; } @@ -470,7 +470,7 @@ StaticAudioTrackClientProxy::StaticAudioTrackClientProxy(audio_track_cblk_t* cbl void StaticAudioTrackClientProxy::flush() { - LOG_FATAL("static flush"); + LOG_ALWAYS_FATAL("static flush"); } void StaticAudioTrackClientProxy::setLoop(size_t loopStart, size_t loopEnd, int loopCount) diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp index eb091ac..4992798 100644 --- a/media/libmedia/CharacterEncodingDetector.cpp +++ b/media/libmedia/CharacterEncodingDetector.cpp @@ -90,6 +90,7 @@ void CharacterEncodingDetector::detectAndConvert() { char buf[1024]; buf[0] = 0; int idx; + bool allprintable = true; for (int i = 0; i < size; i++) { const char *name = mNames.getEntry(i); const char *value = mValues.getEntry(i); @@ -103,18 +104,60 @@ void CharacterEncodingDetector::detectAndConvert() { strlcat(buf, value, sizeof(buf)); // separate tags by space so ICU's ngram detector can do its job strlcat(buf, " ", sizeof(buf)); + allprintable = false; } } - 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); + const char *combinedenc = "UTF-8"; + if (allprintable) { + // since 'buf' is empty, ICU would return a UTF-8 matcher with low confidence, so + // no need to even call it + ALOGV("all tags are printable, assuming ascii (%d)", strlen(buf)); + } else { + ucsdet_setText(csd, buf, strlen(buf), &status); + int32_t matches; + const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status); + bool goodmatch = true; + const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf), + ucma, matches, &goodmatch); + + if (!goodmatch && strlen(buf) < 20) { + ALOGV("not a good match, trying with more data"); + // This string might be too short for ICU to do anything useful with. + // (real world example: "Björk" in ISO-8859-1 might be detected as GB18030, because + // the ISO detector reports a confidence of 0, while the GB18030 detector reports + // a confidence of 10 with no invalid characters) + // Append artist, album and title if they were previously omitted because they + // were printable ascii. + bool added = false; + 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, "album") || + !strcmp(name, "title"))) { + strlcat(buf, value, sizeof(buf)); + strlcat(buf, " ", sizeof(buf)); + added = true; + } + } + if (added) { + ucsdet_setText(csd, buf, strlen(buf), &status); + ucma = ucsdet_detectAll(csd, &matches, &status); + bestCombinedMatch = getPreferred(buf, strlen(buf), + ucma, matches, &goodmatch); + if (!goodmatch) { + ALOGV("still not a good match after adding printable tags"); + } + } else { + ALOGV("no printable tags to add"); + } + } - if (bestCombinedMatch != NULL) { - combinedenc = ucsdet_getName(bestCombinedMatch, &status); + if (bestCombinedMatch != NULL) { + combinedenc = ucsdet_getName(bestCombinedMatch, &status); + } } for (int i = 0; i < size; i++) { @@ -128,24 +171,29 @@ void CharacterEncodingDetector::detectAndConvert() { int32_t inputLength = strlen(s); const char *enc; - if (!strcmp(name, "artist") || + if (!allprintable && (!strcmp(name, "artist") || !strcmp(name, "albumartist") || !strcmp(name, "composer") || !strcmp(name, "genre") || !strcmp(name, "album") || - !strcmp(name, "title")) { + !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; + if (isPrintableAscii(s, inputLength)) { + enc = "UTF-8"; + ALOGV("@@@@ %s is ascii", mNames.getEntry(i)); + } 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)); } - 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) { @@ -207,10 +255,15 @@ void CharacterEncodingDetector::detectAndConvert() { * algorithm and larger frequent character lists than ICU * - devalue encoding where the conversion contains unlikely characters (symbols, reserved, etc) * - pick the highest match + * - signal to the caller whether this match is considered good: confidence > 15, and confidence + * delta with the next runner up > 15 */ const UCharsetMatch *CharacterEncodingDetector::getPreferred( - const char *input, size_t len, const UCharsetMatch** ucma, size_t nummatches) { + const char *input, size_t len, + const UCharsetMatch** ucma, size_t nummatches, + bool *goodmatch) { + *goodmatch = false; Vector<const UCharsetMatch*> matches; UErrorCode status = U_ZERO_ERROR; @@ -227,6 +280,10 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( return NULL; } if (num == 1) { + int confidence = ucsdet_getConfidence(matches[0], &status); + if (confidence > 15) { + *goodmatch = true; + } return matches[0]; } @@ -326,15 +383,35 @@ const UCharsetMatch *CharacterEncodingDetector::getPreferred( // find match with highest confidence after adjusting for unlikely characters int highest = newconfidence[0]; size_t highestidx = 0; + int runnerup = -10000; + int runnerupidx = -10000; num = newconfidence.size(); for (size_t i = 1; i < num; i++) { if (newconfidence[i] > highest) { + runnerup = highest; + runnerupidx = highestidx; highest = newconfidence[i]; highestidx = i; + } else if (newconfidence[i] > runnerup){ + runnerup = newconfidence[i]; + runnerupidx = i; } } status = U_ZERO_ERROR; - ALOGV("selecting '%s' w/ %d confidence", ucsdet_getName(matches[highestidx], &status), highest); + ALOGV("selecting: '%s' w/ %d confidence", + ucsdet_getName(matches[highestidx], &status), highest); + if (runnerupidx < 0) { + ALOGV("no runner up"); + if (highest > 15) { + *goodmatch = true; + } + } else { + ALOGV("runner up: '%s' w/ %d confidence", + ucsdet_getName(matches[runnerupidx], &status), runnerup); + if ((highest - runnerup) > 15) { + *goodmatch = true; + } + } return matches[highestidx]; } diff --git a/media/libmedia/CharacterEncodingDetector.h b/media/libmedia/CharacterEncodingDetector.h index 3655a91..7b5ed86 100644 --- a/media/libmedia/CharacterEncodingDetector.h +++ b/media/libmedia/CharacterEncodingDetector.h @@ -41,7 +41,9 @@ class CharacterEncodingDetector { private: const UCharsetMatch *getPreferred( - const char *input, size_t len, const UCharsetMatch** ucma, size_t matches); + const char *input, size_t len, + const UCharsetMatch** ucma, size_t matches, + bool *goodmatch); bool isFrequent(const uint16_t *values, uint32_t c); diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index a9a9f1a..eb813bd 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -95,7 +95,6 @@ public: audio_io_handle_t output, pid_t tid, int *sessionId, - String8& name, int clientUid, status_t *status) { @@ -110,6 +109,7 @@ public: data.writeInt32(frameCount); track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT; data.writeInt32(lFlags); + // haveSharedBuffer if (sharedBuffer != 0) { data.writeInt32(true); data.writeStrongBinder(sharedBuffer->asBinder()); @@ -140,7 +140,6 @@ public: if (sessionId != NULL) { *sessionId = lSessionId; } - name = reply.readString8(); lStatus = reply.readInt32(); track = interface_cast<IAudioTrack>(reply.readStrongBinder()); if (lStatus == NO_ERROR) { @@ -412,7 +411,7 @@ public: const audio_offload_info_t *offloadInfo) { Parcel data, reply; - audio_devices_t devices = pDevices != NULL ? *pDevices : (audio_devices_t)0; + audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE; uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0; audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT; audio_channel_mask_t channelMask = pChannelMask != NULL ? @@ -426,6 +425,7 @@ public: data.writeInt32(channelMask); data.writeInt32(latency); data.writeInt32((int32_t) flags); + // hasOffloadInfo if (offloadInfo == NULL) { data.writeInt32(0); } else { @@ -503,7 +503,7 @@ public: audio_channel_mask_t *pChannelMask) { Parcel data, reply; - audio_devices_t devices = pDevices != NULL ? *pDevices : (audio_devices_t)0; + audio_devices_t devices = pDevices != NULL ? *pDevices : AUDIO_DEVICE_NONE; uint32_t samplingRate = pSamplingRate != NULL ? *pSamplingRate : 0; audio_format_t format = pFormat != NULL ? *pFormat : AUDIO_FORMAT_DEFAULT; audio_channel_mask_t channelMask = pChannelMask != NULL ? @@ -601,7 +601,7 @@ public: Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply); - int id = 0; + int id = AUDIO_SESSION_ALLOCATE; if (status == NO_ERROR) { id = reply.readInt32(); } @@ -808,7 +808,6 @@ status_t BnAudioFlinger::onTransact( pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); int clientUid = data.readInt32(); - String8 name; status_t status; sp<IAudioTrack> track; if ((haveSharedBuffer && (buffer == 0)) || @@ -819,13 +818,12 @@ status_t BnAudioFlinger::onTransact( track = createTrack( (audio_stream_type_t) streamType, sampleRate, format, channelMask, &frameCount, &flags, buffer, output, tid, - &sessionId, name, clientUid, &status); + &sessionId, clientUid, &status); LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR)); } reply->writeInt32(frameCount); reply->writeInt32(flags); reply->writeInt32(sessionId); - reply->writeString8(name); reply->writeInt32(status); reply->writeStrongBinder(track->asBinder()); return NO_ERROR; diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 1a027a6..9bb4a49 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -137,6 +137,7 @@ public: data.writeInt32(static_cast <uint32_t>(format)); data.writeInt32(channelMask); data.writeInt32(static_cast <uint32_t>(flags)); + // hasOffloadInfo if (offloadInfo == NULL) { data.writeInt32(0); } else { diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp index f7a9a75..f1a6a9f 100644 --- a/media/libmedia/IDrm.cpp +++ b/media/libmedia/IDrm.cpp @@ -51,6 +51,7 @@ enum { ENCRYPT, DECRYPT, SIGN, + SIGN_RSA, VERIFY, SET_LISTENER }; @@ -196,11 +197,15 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } - virtual status_t getProvisionRequest(Vector<uint8_t> &request, + virtual status_t getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector<uint8_t> &request, String8 &defaultUrl) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + data.writeString8(certType); + data.writeString8(certAuthority); remote()->transact(GET_PROVISION_REQUEST, data, &reply); readVector(reply, request); @@ -209,13 +214,18 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } - virtual status_t provideProvisionResponse(Vector<uint8_t> const &response) { + virtual status_t provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); writeVector(data, response); remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply); + readVector(reply, certificate); + readVector(reply, wrappedKey); + return reply.readInt32(); } @@ -386,6 +396,25 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } + virtual status_t signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature) { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + writeVector(data, sessionId); + data.writeString8(algorithm); + writeVector(data, message); + writeVector(data, wrappedKey); + + remote()->transact(SIGN_RSA, data, &reply); + readVector(reply, signature); + + return reply.readInt32(); + } + virtual status_t setListener(const sp<IDrmClient>& listener) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); @@ -563,9 +592,13 @@ status_t BnDrm::onTransact( case GET_PROVISION_REQUEST: { CHECK_INTERFACE(IDrm, data, reply); + String8 certType = data.readString8(); + String8 certAuthority = data.readString8(); + Vector<uint8_t> request; String8 defaultUrl; - status_t result = getProvisionRequest(request, defaultUrl); + status_t result = getProvisionRequest(certType, certAuthority, + request, defaultUrl); writeVector(reply, request); reply->writeString8(defaultUrl); reply->writeInt32(result); @@ -576,8 +609,13 @@ status_t BnDrm::onTransact( { CHECK_INTERFACE(IDrm, data, reply); Vector<uint8_t> response; + Vector<uint8_t> certificate; + Vector<uint8_t> wrappedKey; readVector(data, response); - reply->writeInt32(provideProvisionResponse(response)); + status_t result = provideProvisionResponse(response, certificate, wrappedKey); + writeVector(reply, certificate); + writeVector(reply, wrappedKey); + reply->writeInt32(result); return OK; } @@ -725,6 +763,20 @@ status_t BnDrm::onTransact( return OK; } + case SIGN_RSA: + { + CHECK_INTERFACE(IDrm, data, reply); + Vector<uint8_t> sessionId, message, wrappedKey, signature; + readVector(data, sessionId); + String8 algorithm = data.readString8(); + readVector(data, message); + readVector(data, wrappedKey); + uint32_t result = signRSA(sessionId, algorithm, message, wrappedKey, signature); + writeVector(reply, signature); + reply->writeInt32(result); + return OK; + } + case SET_LISTENER: { CHECK_INTERFACE(IDrm, data, reply); sp<IDrmClient> listener = diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index adef3be..61b6d36 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -1057,7 +1057,7 @@ bool ToneGenerator::initAudioTrack() { 0, // notificationFrames 0, // sharedBuffer mThreadCanCallJava, - 0, // sessionId + AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_CALLBACK); if (mpAudioTrack->initCheck() != NO_ERROR) { diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index d94c7c5..0be01a9 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -531,6 +531,14 @@ status_t MediaPlayer::setAudioStreamType(audio_stream_type_t type) return OK; } +status_t MediaPlayer::getAudioStreamType(audio_stream_type_t *type) +{ + ALOGV("getAudioStreamType"); + Mutex::Autolock _l(mLock); + *type = mStreamType; + return OK; +} + status_t MediaPlayer::setLooping(int loop) { ALOGV("MediaPlayer::setLooping"); diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 4189a5e..caf2dfc 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -53,6 +53,8 @@ LOCAL_C_INCLUDES := \ LOCAL_MODULE:= libmediaplayerservice +LOCAL_32_BIT_ONLY := true + include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index eebcb79..d50037f 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -28,9 +28,21 @@ #include <media/stagefright/foundation/AString.h> #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/MediaErrors.h> +#include <binder/IServiceManager.h> +#include <binder/IPCThreadState.h> namespace android { +static bool checkPermission(const char* permissionString) { +#ifndef HAVE_ANDROID_OS + return true; +#endif + if (getpid() == IPCThreadState::self()->getCallingPid()) return true; + bool ok = checkCallingPermission(String16(permissionString)); + if (!ok) ALOGE("Request requires %s", permissionString); + return ok; +} + KeyedVector<Vector<uint8_t>, String8> Drm::mUUIDToLibraryPathMap; KeyedVector<String8, wp<SharedLibrary> > Drm::mLibraryPathToOpenLibraryMap; Mutex Drm::mMapLock; @@ -373,7 +385,8 @@ status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId, return mPlugin->queryKeyStatus(sessionId, infoMap); } -status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) { +status_t Drm::getProvisionRequest(String8 const &certType, String8 const &certAuthority, + Vector<uint8_t> &request, String8 &defaultUrl) { Mutex::Autolock autoLock(mLock); if (mInitCheck != OK) { @@ -384,10 +397,13 @@ status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) return -EINVAL; } - return mPlugin->getProvisionRequest(request, defaultUrl); + return mPlugin->getProvisionRequest(certType, certAuthority, + request, defaultUrl); } -status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) { +status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey) { Mutex::Autolock autoLock(mLock); if (mInitCheck != OK) { @@ -398,7 +414,7 @@ status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response) { return -EINVAL; } - return mPlugin->provideProvisionResponse(response); + return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); } @@ -589,6 +605,28 @@ status_t Drm::verify(Vector<uint8_t> const &sessionId, return mPlugin->verify(sessionId, keyId, message, signature, match); } +status_t Drm::signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature) { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + if (!checkPermission("android.permission.ACCESS_DRM_CERTIFICATES")) { + return -EPERM; + } + + return mPlugin->signRSA(sessionId, algorithm, message, wrappedKey, signature); +} + void Drm::binderDied(const wp<IBinder> &the_late_who) { delete mPlugin; diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 119fd50..3d4b0fc 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -66,10 +66,14 @@ struct Drm : public BnDrm, virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId, KeyedVector<String8, String8> &infoMap) const; - virtual status_t getProvisionRequest(Vector<uint8_t> &request, + virtual status_t getProvisionRequest(String8 const &certType, + String8 const &certAuthority, + Vector<uint8_t> &request, String8 &defaulUrl); - virtual status_t provideProvisionResponse(Vector<uint8_t> const &response); + virtual status_t provideProvisionResponse(Vector<uint8_t> const &response, + Vector<uint8_t> &certificate, + Vector<uint8_t> &wrappedKey); virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops); @@ -111,6 +115,12 @@ struct Drm : public BnDrm, Vector<uint8_t> const &signature, bool &match); + virtual status_t signRSA(Vector<uint8_t> const &sessionId, + String8 const &algorithm, + Vector<uint8_t> const &message, + Vector<uint8_t> const &wrappedKey, + Vector<uint8_t> &signature); + virtual status_t setListener(const sp<IDrmClient>& listener); virtual void sendEvent(DrmPlugin::EventType eventType, int extra, diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp index 90aed39..74e5013 100644 --- a/media/libmediaplayerservice/MediaPlayerFactory.cpp +++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp @@ -67,6 +67,12 @@ player_type MediaPlayerFactory::getDefaultPlayerType() { return NU_PLAYER; } + // TODO: remove this EXPERIMENTAL developer settings property + if (property_get("persist.sys.media.use-nuplayer", value, NULL) + && !strcasecmp("true", value)) { + return NU_PLAYER; + } + return STAGEFRIGHT_PLAYER; } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 200c561..778eb9a 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1679,7 +1679,7 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() { ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) { - LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); + LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback."); //ALOGV("write(%p, %u)", buffer, size); if (mTrack != 0) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index a750ad0..d8d939a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -31,13 +31,10 @@ #include "ATSParser.h" -#include "SoftwareRenderer.h" - #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> -#include <media/stagefright/ACodec.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MetaData.h> @@ -146,7 +143,6 @@ NuPlayer::NuPlayer() : mUIDValid(false), mSourceFlags(0), mVideoIsAVC(false), - mNeedsSwRenderer(false), mAudioEOS(false), mVideoEOS(false), mScanSourcesPending(false), @@ -442,7 +438,6 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { ALOGV("kWhatStart"); mVideoIsAVC = false; - mNeedsSwRenderer = false; mAudioEOS = false; mVideoEOS = false; mSkipRenderingAudioUntilMediaTimeUs = -1; @@ -533,24 +528,21 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { { bool audio = msg->what() == kWhatAudioNotify; - sp<AMessage> codecRequest; - CHECK(msg->findMessage("codec-request", &codecRequest)); - int32_t what; - CHECK(codecRequest->findInt32("what", &what)); + CHECK(msg->findInt32("what", &what)); - if (what == ACodec::kWhatFillThisBuffer) { + if (what == Decoder::kWhatFillThisBuffer) { status_t err = feedDecoderInputData( - audio, codecRequest); + audio, msg); if (err == -EWOULDBLOCK) { if (mSource->feedMoreTSData() == OK) { msg->post(10000ll); } } - } else if (what == ACodec::kWhatEOS) { + } else if (what == Decoder::kWhatEOS) { int32_t err; - CHECK(codecRequest->findInt32("err", &err)); + CHECK(msg->findInt32("err", &err)); if (err == ERROR_END_OF_STREAM) { ALOGV("got %s decoder EOS", audio ? "audio" : "video"); @@ -561,7 +553,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { } mRenderer->queueEOS(audio, err); - } else if (what == ACodec::kWhatFlushCompleted) { + } else if (what == Decoder::kWhatFlushCompleted) { bool needShutdown; if (audio) { @@ -590,14 +582,17 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { } finishFlushIfPossible(); - } else if (what == ACodec::kWhatOutputFormatChanged) { + } else if (what == Decoder::kWhatOutputFormatChanged) { + sp<AMessage> format; + CHECK(msg->findMessage("format", &format)); + if (audio) { int32_t numChannels; - CHECK(codecRequest->findInt32( + CHECK(format->findInt32( "channel-count", &numChannels)); int32_t sampleRate; - CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); + CHECK(format->findInt32("sample-rate", &sampleRate)); ALOGV("Audio output format changed to %d Hz, %d channels", sampleRate, numChannels); @@ -621,7 +616,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { } int32_t channelMask; - if (!codecRequest->findInt32("channel-mask", &channelMask)) { + if (!format->findInt32("channel-mask", &channelMask)) { channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; } @@ -642,11 +637,11 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { // video int32_t width, height; - CHECK(codecRequest->findInt32("width", &width)); - CHECK(codecRequest->findInt32("height", &height)); + CHECK(format->findInt32("width", &width)); + CHECK(format->findInt32("height", &height)); int32_t cropLeft, cropTop, cropRight, cropBottom; - CHECK(codecRequest->findRect( + CHECK(format->findRect( "crop", &cropLeft, &cropTop, &cropRight, &cropBottom)); @@ -679,22 +674,8 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { notifyListener( MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight); - - if (mNeedsSwRenderer && mNativeWindow != NULL) { - int32_t colorFormat; - CHECK(codecRequest->findInt32("color-format", &colorFormat)); - - sp<MetaData> meta = new MetaData; - meta->setInt32(kKeyWidth, width); - meta->setInt32(kKeyHeight, height); - meta->setRect(kKeyCropRect, cropLeft, cropTop, cropRight, cropBottom); - meta->setInt32(kKeyColorFormat, colorFormat); - - mRenderer->setSoftRenderer( - new SoftwareRenderer(mNativeWindow->getNativeWindow(), meta)); - } } - } else if (what == ACodec::kWhatShutdownCompleted) { + } else if (what == Decoder::kWhatShutdownCompleted) { ALOGV("%s shutdown completed", audio ? "audio" : "video"); if (audio) { mAudioDecoder.clear(); @@ -709,22 +690,15 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { } finishFlushIfPossible(); - } else if (what == ACodec::kWhatError) { + } else if (what == Decoder::kWhatError) { ALOGE("Received error from %s decoder, aborting playback.", audio ? "audio" : "video"); mRenderer->queueEOS(audio, UNKNOWN_ERROR); - } else if (what == ACodec::kWhatDrainThisBuffer) { - renderBuffer(audio, codecRequest); - } else if (what == ACodec::kWhatComponentAllocated) { - if (!audio) { - AString name; - CHECK(codecRequest->findString("componentName", &name)); - mNeedsSwRenderer = name.startsWith("OMX.google."); - } - } else if (what != ACodec::kWhatComponentConfigured - && what != ACodec::kWhatBuffersAllocated) { - ALOGV("Unhandled codec notification %d '%c%c%c%c'.", + } else if (what == Decoder::kWhatDrainThisBuffer) { + renderBuffer(audio, msg); + } else { + ALOGV("Unhandled decoder notification %d '%c%c%c%c'.", what, what >> 24, (what >> 16) & 0xff, @@ -925,8 +899,7 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { *decoder = audio ? new Decoder(notify) : new Decoder(notify, mNativeWindow); - looper()->registerHandler(*decoder); - + (*decoder)->init(); (*decoder)->configure(format); return OK; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 9dfe4a0..f1d3d55 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -24,7 +24,6 @@ namespace android { -struct ACodec; struct MetaData; struct NuPlayerDriver; @@ -118,7 +117,6 @@ private: sp<MediaPlayerBase::AudioSink> mAudioSink; sp<Decoder> mVideoDecoder; bool mVideoIsAVC; - bool mNeedsSwRenderer; sp<Decoder> mAudioDecoder; sp<Renderer> mRenderer; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 2423fd5..469c9ca 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -17,14 +17,17 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NuPlayerDecoder" #include <utils/Log.h> +#include <inttypes.h> #include "NuPlayerDecoder.h" +#include <media/ICrypto.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> -#include <media/stagefright/ACodec.h> +#include <media/stagefright/MediaCodec.h> #include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> namespace android { @@ -32,122 +35,425 @@ NuPlayer::Decoder::Decoder( const sp<AMessage> ¬ify, const sp<NativeWindowWrapper> &nativeWindow) : mNotify(notify), - mNativeWindow(nativeWindow) { + mNativeWindow(nativeWindow), + mBufferGeneration(0), + mComponentName("decoder") { + // Every decoder has its own looper because MediaCodec operations + // are blocking, but NuPlayer needs asynchronous operations. + mDecoderLooper = new ALooper; + mDecoderLooper->setName("NuPlayerDecoder"); + mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO); + + mCodecLooper = new ALooper; + mCodecLooper->setName("NuPlayerDecoder-MC"); + mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); } NuPlayer::Decoder::~Decoder() { } -void NuPlayer::Decoder::configure(const sp<AMessage> &format) { +void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { CHECK(mCodec == NULL); + ++mBufferGeneration; + AString mime; CHECK(format->findString("mime", &mime)); - sp<AMessage> notifyMsg = - new AMessage(kWhatCodecNotify, id()); + sp<Surface> surface = NULL; + if (mNativeWindow != NULL) { + surface = mNativeWindow->getSurfaceTextureClient(); + } - mCSDIndex = 0; - for (size_t i = 0;; ++i) { - sp<ABuffer> csd; - if (!format->findBuffer(StringPrintf("csd-%d", i).c_str(), &csd)) { - break; - } + mComponentName = mime; + mComponentName.append(" decoder"); + ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get()); - mCSD.push(csd); + mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); + if (mCodec == NULL) { + ALOGE("Failed to create %s decoder", mime.c_str()); + handleError(UNKNOWN_ERROR); + return; } + mCodec->getName(&mComponentName); + if (mNativeWindow != NULL) { - format->setObject("native-window", mNativeWindow); + // disconnect from surface as MediaCodec will reconnect + CHECK_EQ((int)NO_ERROR, + native_window_api_disconnect( + surface.get(), + NATIVE_WINDOW_API_MEDIA)); + } + status_t err = mCodec->configure( + format, surface, NULL /* crypto */, 0 /* flags */); + if (err != OK) { + ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); + handleError(err); + return; + } + // the following should work in configured state + CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat)); + CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat)); + + err = mCodec->start(); + if (err != OK) { + ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err); + handleError(err); + return; } - // Current video decoders do not return from OMX_FillThisBuffer - // quickly, violating the OpenMAX specs, until that is remedied - // we need to invest in an extra looper to free the main event - // queue. - bool needDedicatedLooper = !strncasecmp(mime.c_str(), "video/", 6); + // the following should work after start + CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers)); + CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers)); + ALOGV("[%s] got %zu input and %zu output buffers", + mComponentName.c_str(), + mInputBuffers.size(), + mOutputBuffers.size()); - mFormat = format; - mCodec = new ACodec; + requestCodecNotification(); +} - if (needDedicatedLooper && mCodecLooper == NULL) { - mCodecLooper = new ALooper; - mCodecLooper->setName("NuPlayerDecoder"); - mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); +void NuPlayer::Decoder::requestCodecNotification() { + if (mCodec != NULL) { + sp<AMessage> reply = new AMessage(kWhatCodecNotify, id()); + reply->setInt32("generation", mBufferGeneration); + mCodec->requestActivityNotification(reply); } +} - (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec); +bool NuPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) { + int32_t generation; + CHECK(msg->findInt32("generation", &generation)); + return generation != mBufferGeneration; +} - mCodec->setNotificationMessage(notifyMsg); - mCodec->initiateSetup(format); +void NuPlayer::Decoder::init() { + mDecoderLooper->registerHandler(this); } -void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) { - switch (msg->what()) { - case kWhatCodecNotify: - { - int32_t what; - CHECK(msg->findInt32("what", &what)); - - if (what == ACodec::kWhatFillThisBuffer) { - onFillThisBuffer(msg); - } else { - sp<AMessage> notify = mNotify->dup(); - notify->setMessage("codec-request", msg); - notify->post(); - } - break; +void NuPlayer::Decoder::configure(const sp<AMessage> &format) { + sp<AMessage> msg = new AMessage(kWhatConfigure, id()); + msg->setMessage("format", format); + msg->post(); +} + +void NuPlayer::Decoder::handleError(int32_t err) +{ + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatError); + notify->setInt32("err", err); + notify->post(); +} + +bool NuPlayer::Decoder::handleAnInputBuffer() { + size_t bufferIx = -1; + status_t res = mCodec->dequeueInputBuffer(&bufferIx); + ALOGV("[%s] dequeued input: %d", + mComponentName.c_str(), res == OK ? (int)bufferIx : res); + if (res != OK) { + if (res != -EAGAIN) { + handleError(res); } + return false; + } - default: - TRESPASS(); - break; + CHECK_LT(bufferIx, mInputBuffers.size()); + + sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, id()); + reply->setSize("buffer-ix", bufferIx); + reply->setInt32("generation", mBufferGeneration); + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatFillThisBuffer); + notify->setBuffer("buffer", mInputBuffers[bufferIx]); + notify->setMessage("reply", reply); + notify->post(); + return true; +} + +void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) { + size_t bufferIx; + CHECK(msg->findSize("buffer-ix", &bufferIx)); + CHECK_LT(bufferIx, mInputBuffers.size()); + sp<ABuffer> codecBuffer = mInputBuffers[bufferIx]; + + sp<ABuffer> buffer; + bool hasBuffer = msg->findBuffer("buffer", &buffer); + if (buffer == NULL /* includes !hasBuffer */) { + int32_t streamErr = ERROR_END_OF_STREAM; + CHECK(msg->findInt32("err", &streamErr) || !hasBuffer); + + if (streamErr == OK) { + /* buffers are returned to hold on to */ + return; + } + + // attempt to queue EOS + status_t err = mCodec->queueInputBuffer( + bufferIx, + 0, + 0, + 0, + MediaCodec::BUFFER_FLAG_EOS); + if (streamErr == ERROR_END_OF_STREAM && err != OK) { + streamErr = err; + // err will not be ERROR_END_OF_STREAM + } + + if (streamErr != ERROR_END_OF_STREAM) { + handleError(streamErr); + } + } else { + int64_t timeUs = 0; + uint32_t flags = 0; + CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); + + int32_t eos; + // we do not expect CODECCONFIG or SYNCFRAME for decoder + if (buffer->meta()->findInt32("eos", &eos) && eos) { + flags |= MediaCodec::BUFFER_FLAG_EOS; + } + + // copy into codec buffer + if (buffer != codecBuffer) { + CHECK_LE(buffer->size(), codecBuffer->capacity()); + codecBuffer->setRange(0, buffer->size()); + memcpy(codecBuffer->data(), buffer->data(), buffer->size()); + } + + status_t err = mCodec->queueInputBuffer( + bufferIx, + codecBuffer->offset(), + codecBuffer->size(), + timeUs, + flags); + if (err != OK) { + ALOGE("Failed to queue input buffer for %s (err=%d)", + mComponentName.c_str(), err); + handleError(err); + } } } -void NuPlayer::Decoder::onFillThisBuffer(const sp<AMessage> &msg) { - sp<AMessage> reply; - CHECK(msg->findMessage("reply", &reply)); +bool NuPlayer::Decoder::handleAnOutputBuffer() { + size_t bufferIx = -1; + size_t offset; + size_t size; + int64_t timeUs; + uint32_t flags; + status_t res = mCodec->dequeueOutputBuffer( + &bufferIx, &offset, &size, &timeUs, &flags); + + if (res != OK) { + ALOGV("[%s] dequeued output: %d", mComponentName.c_str(), res); + } else { + ALOGV("[%s] dequeued output: %d (time=%lld flags=%" PRIu32 ")", + mComponentName.c_str(), (int)bufferIx, timeUs, flags); + } -#if 0 - sp<ABuffer> outBuffer; - CHECK(msg->findBuffer("buffer", &outBuffer)); -#else - sp<ABuffer> outBuffer; -#endif + if (res == INFO_OUTPUT_BUFFERS_CHANGED) { + res = mCodec->getOutputBuffers(&mOutputBuffers); + if (res != OK) { + ALOGE("Failed to get output buffers for %s after INFO event (err=%d)", + mComponentName.c_str(), res); + handleError(res); + return false; + } + // NuPlayer ignores this + return true; + } else if (res == INFO_FORMAT_CHANGED) { + sp<AMessage> format = new AMessage(); + res = mCodec->getOutputFormat(&format); + if (res != OK) { + ALOGE("Failed to get output format for %s after INFO event (err=%d)", + mComponentName.c_str(), res); + handleError(res); + return false; + } - if (mCSDIndex < mCSD.size()) { - outBuffer = mCSD.editItemAt(mCSDIndex++); - outBuffer->meta()->setInt64("timeUs", 0); + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatOutputFormatChanged); + notify->setMessage("format", format); + notify->post(); + return true; + } else if (res == INFO_DISCONTINUITY) { + // nothing to do + return true; + } else if (res != OK) { + if (res != -EAGAIN) { + handleError(res); + } + return false; + } - reply->setBuffer("buffer", outBuffer); - reply->post(); - return; + CHECK_LT(bufferIx, mOutputBuffers.size()); + sp<ABuffer> buffer = mOutputBuffers[bufferIx]; + buffer->setRange(offset, size); + buffer->meta()->clear(); + buffer->meta()->setInt64("timeUs", timeUs); + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + buffer->meta()->setInt32("eos", true); } + // we do not expect CODECCONFIG or SYNCFRAME for decoder + + sp<AMessage> reply = new AMessage(kWhatRenderBuffer, id()); + reply->setSize("buffer-ix", bufferIx); + reply->setInt32("generation", mBufferGeneration); sp<AMessage> notify = mNotify->dup(); - notify->setMessage("codec-request", msg); + notify->setInt32("what", kWhatDrainThisBuffer); + notify->setBuffer("buffer", buffer); + notify->setMessage("reply", reply); notify->post(); + + // FIXME: This should be handled after rendering is complete, + // but Renderer needs it now + if (flags & MediaCodec::BUFFER_FLAG_EOS) { + ALOGV("queueing eos [%s]", mComponentName.c_str()); + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatEOS); + notify->setInt32("err", ERROR_END_OF_STREAM); + notify->post(); + } + return true; } -void NuPlayer::Decoder::signalFlush() { - if (mCodec != NULL) { - mCodec->signalFlush(); +void NuPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) { + status_t err; + int32_t render; + size_t bufferIx; + CHECK(msg->findSize("buffer-ix", &bufferIx)); + if (msg->findInt32("render", &render) && render) { + err = mCodec->renderOutputBufferAndRelease(bufferIx); + } else { + err = mCodec->releaseOutputBuffer(bufferIx); + } + if (err != OK) { + ALOGE("failed to release output buffer for %s (err=%d)", + mComponentName.c_str(), err); + handleError(err); } } -void NuPlayer::Decoder::signalResume() { +void NuPlayer::Decoder::onFlush() { + status_t err = OK; if (mCodec != NULL) { - mCodec->signalResume(); + err = mCodec->flush(); + ++mBufferGeneration; } + + if (err != OK) { + ALOGE("failed to flush %s (err=%d)", mComponentName.c_str(), err); + handleError(err); + return; + } + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatFlushCompleted); + notify->post(); } -void NuPlayer::Decoder::initiateShutdown() { +void NuPlayer::Decoder::onShutdown() { + status_t err = OK; if (mCodec != NULL) { - mCodec->initiateShutdown(); + err = mCodec->release(); + mCodec = NULL; + ++mBufferGeneration; + + if (mNativeWindow != NULL) { + // reconnect to surface as MediaCodec disconnected from it + CHECK_EQ((int)NO_ERROR, + native_window_api_connect( + mNativeWindow->getNativeWindow().get(), + NATIVE_WINDOW_API_MEDIA)); + } + mComponentName = "decoder"; + } + + if (err != OK) { + ALOGE("failed to release %s (err=%d)", mComponentName.c_str(), err); + handleError(err); + return; + } + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatShutdownCompleted); + notify->post(); +} + +void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) { + ALOGV("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str()); + + switch (msg->what()) { + case kWhatConfigure: + { + sp<AMessage> format; + CHECK(msg->findMessage("format", &format)); + onConfigure(format); + break; + } + + case kWhatCodecNotify: + { + if (!isStaleReply(msg)) { + while (handleAnInputBuffer()) { + } + + while (handleAnOutputBuffer()) { + } + } + + requestCodecNotification(); + break; + } + + case kWhatInputBufferFilled: + { + if (!isStaleReply(msg)) { + onInputBufferFilled(msg); + } + break; + } + + case kWhatRenderBuffer: + { + if (!isStaleReply(msg)) { + onRenderBuffer(msg); + } + break; + } + + case kWhatFlush: + { + onFlush(); + break; + } + + case kWhatShutdown: + { + onShutdown(); + break; + } + + default: + TRESPASS(); + break; } } +void NuPlayer::Decoder::signalFlush() { + (new AMessage(kWhatFlush, id()))->post(); +} + +void NuPlayer::Decoder::signalResume() { + // nothing to do +} + +void NuPlayer::Decoder::initiateShutdown() { + (new AMessage(kWhatShutdown, id()))->post(); +} + bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const { if (targetFormat == NULL) { return true; @@ -163,14 +469,16 @@ bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &ta const char * keys[] = { "channel-count", "sample-rate", "is-adts" }; for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { int32_t oldVal, newVal; - if (!mFormat->findInt32(keys[i], &oldVal) || !targetFormat->findInt32(keys[i], &newVal) - || oldVal != newVal) { + if (!mOutputFormat->findInt32(keys[i], &oldVal) || + !targetFormat->findInt32(keys[i], &newVal) || + oldVal != newVal) { return false; } } sp<ABuffer> oldBuf, newBuf; - if (mFormat->findBuffer("csd-0", &oldBuf) && targetFormat->findBuffer("csd-0", &newBuf)) { + if (mOutputFormat->findBuffer("csd-0", &oldBuf) && + targetFormat->findBuffer("csd-0", &newBuf)) { if (oldBuf->size() != newBuf->size()) { return false; } @@ -181,7 +489,7 @@ bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &ta } bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const { - if (mFormat == NULL) { + if (mOutputFormat == NULL) { return false; } @@ -190,7 +498,7 @@ bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetF } AString oldMime, newMime; - if (!mFormat->findString("mime", &oldMime) + if (!mOutputFormat->findString("mime", &oldMime) || !targetFormat->findString("mime", &newMime) || !(oldMime == newMime)) { return false; @@ -201,7 +509,10 @@ bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetF if (audio) { seamless = supportsSeamlessAudioFormatChange(targetFormat); } else { - seamless = mCodec != NULL && mCodec->isConfiguredForAdaptivePlayback(); + int32_t isAdaptive; + seamless = (mCodec != NULL && + mInputFormat->findInt32("adaptive-playback", &isAdaptive) && + isAdaptive); } ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str()); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index 78ea74a..94243fc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -25,12 +25,14 @@ namespace android { struct ABuffer; +struct MediaCodec; struct NuPlayer::Decoder : public AHandler { Decoder(const sp<AMessage> ¬ify, const sp<NativeWindowWrapper> &nativeWindow = NULL); void configure(const sp<AMessage> &format); + void init(); void signalFlush(); void signalResume(); @@ -38,7 +40,18 @@ struct NuPlayer::Decoder : public AHandler { bool supportsSeamlessFormatChange(const sp<AMessage> &to) const; + enum { + kWhatFillThisBuffer = 'flTB', + kWhatDrainThisBuffer = 'drTB', + kWhatOutputFormatChanged = 'fmtC', + kWhatFlushCompleted = 'flsC', + kWhatShutdownCompleted = 'shDC', + kWhatEOS = 'eos ', + kWhatError = 'err ', + }; + protected: + virtual ~Decoder(); virtual void onMessageReceived(const sp<AMessage> &msg); @@ -46,21 +59,40 @@ protected: private: enum { kWhatCodecNotify = 'cdcN', + kWhatConfigure = 'conf', + kWhatInputBufferFilled = 'inpF', + kWhatRenderBuffer = 'rndr', + kWhatFlush = 'flus', + kWhatShutdown = 'shuD', }; sp<AMessage> mNotify; sp<NativeWindowWrapper> mNativeWindow; - sp<AMessage> mFormat; - sp<ACodec> mCodec; + sp<AMessage> mInputFormat; + sp<AMessage> mOutputFormat; + sp<MediaCodec> mCodec; sp<ALooper> mCodecLooper; + sp<ALooper> mDecoderLooper; + + Vector<sp<ABuffer> > mInputBuffers; + Vector<sp<ABuffer> > mOutputBuffers; + + void handleError(int32_t err); + bool handleAnInputBuffer(); + bool handleAnOutputBuffer(); - Vector<sp<ABuffer> > mCSD; - size_t mCSDIndex; + void requestCodecNotification(); + bool isStaleReply(const sp<AMessage> &msg); - sp<AMessage> makeFormat(const sp<MetaData> &meta); + void onConfigure(const sp<AMessage> &format); + void onFlush(); + void onInputBufferFilled(const sp<AMessage> &msg); + void onRenderBuffer(const sp<AMessage> &msg); + void onShutdown(); - void onFillThisBuffer(const sp<AMessage> &msg); + int32_t mBufferGeneration; + AString mComponentName; bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index bf5271e..a070c1a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -20,8 +20,6 @@ #include "NuPlayerRenderer.h" -#include "SoftwareRenderer.h" - #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -36,7 +34,6 @@ NuPlayer::Renderer::Renderer( const sp<AMessage> ¬ify, uint32_t flags) : mAudioSink(sink), - mSoftRenderer(NULL), mNotify(notify), mFlags(flags), mNumFramesWritten(0), @@ -60,12 +57,6 @@ NuPlayer::Renderer::Renderer( } NuPlayer::Renderer::~Renderer() { - delete mSoftRenderer; -} - -void NuPlayer::Renderer::setSoftRenderer(SoftwareRenderer *softRenderer) { - delete mSoftRenderer; - mSoftRenderer = softRenderer; } void NuPlayer::Renderer::queueBuffer( @@ -425,9 +416,6 @@ void NuPlayer::Renderer::onDrainVideoQueue() { ALOGV("rendering video at media time %.2f secs", (mFlags & FLAG_REAL_TIME ? realTimeUs : (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6); - if (mSoftRenderer != NULL) { - mSoftRenderer->render(entry->mBuffer->data(), entry->mBuffer->size(), NULL); - } } entry->mNotifyConsumed->setInt32("render", !tooLate); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 9124e03..94a05ea 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -23,7 +23,6 @@ namespace android { struct ABuffer; -class SoftwareRenderer; struct NuPlayer::Renderer : public AHandler { enum Flags { @@ -57,8 +56,6 @@ struct NuPlayer::Renderer : public AHandler { kWhatMediaRenderingStart = 'mdrd', }; - void setSoftRenderer(SoftwareRenderer *softRenderer); - protected: virtual ~Renderer(); @@ -86,7 +83,6 @@ private: static const int64_t kMinPositionUpdateDelayUs; sp<MediaPlayerBase::AudioSink> mAudioSink; - SoftwareRenderer *mSoftRenderer; sp<AMessage> mNotify; uint32_t mFlags; List<QueueEntry> mAudioQueue; diff --git a/media/libnbaio/MonoPipe.cpp b/media/libnbaio/MonoPipe.cpp index 9c8461c..4adf018 100644 --- a/media/libnbaio/MonoPipe.cpp +++ b/media/libnbaio/MonoPipe.cpp @@ -30,6 +30,23 @@ namespace android { +static uint64_t cacheN; // output of CCHelper::getLocalFreq() +static bool cacheValid; // whether cacheN is valid +static pthread_once_t cacheOnceControl = PTHREAD_ONCE_INIT; + +static void cacheOnceInit() +{ + CCHelper tmpHelper; + status_t res; + if (OK != (res = tmpHelper.getLocalFreq(&cacheN))) { + ALOGE("Failed to fetch local time frequency when constructing a" + " MonoPipe (res = %d). getNextWriteTimestamp calls will be" + " non-functional", res); + return; + } + cacheValid = true; +} + MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) : NBAIO_Sink(format), mUpdateSeq(0), @@ -47,8 +64,6 @@ MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBl mTimestampMutator(&mTimestampShared), mTimestampObserver(&mTimestampShared) { - CCHelper tmpHelper; - status_t res; uint64_t N, D; mNextRdPTS = AudioBufferProvider::kInvalidPTS; @@ -59,12 +74,13 @@ MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBl mSamplesToLocalTime.a_to_b_denom = 0; D = Format_sampleRate(format); - if (OK != (res = tmpHelper.getLocalFreq(&N))) { - ALOGE("Failed to fetch local time frequency when constructing a" - " MonoPipe (res = %d). getNextWriteTimestamp calls will be" - " non-functional", res); + + (void) pthread_once(&cacheOnceControl, cacheOnceInit); + if (!cacheValid) { + // log has already been done return; } + N = cacheN; LinearTransform::reduce(&N, &D); static const uint64_t kSignedHiBitsMask = ~(0x7FFFFFFFull); diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 9c48587..4aecb80 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -365,7 +365,7 @@ ACodec::ACodec() mIsEncoder(false), mUseMetadataOnEncoderOutput(false), mShutdownInProgress(false), - mIsConfiguredForAdaptivePlayback(false), + mExplicitShutdown(false), mEncoderDelay(0), mEncoderPadding(0), mChannelMaskPresent(false), @@ -643,18 +643,34 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( return err; } - // XXX: Is this the right logic to use? It's not clear to me what the OMX - // buffer counts refer to - how do they account for the renderer holding on - // to buffers? - if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) { - OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers; + // FIXME: assume that surface is controlled by app (native window + // returns the number for the case when surface is not controlled by app) + // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported + // For now, try to allocate 1 more buffer, but don't fail if unsuccessful + + // Use conservative allocation while also trying to reduce starvation + // + // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the + // minimum needed for the consumer to be able to work + // 2. try to allocate two (2) additional buffers to reduce starvation from + // the consumer + // plus an extra buffer to account for incorrect minUndequeuedBufs + for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) { + OMX_U32 newBufferCount = + def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers; def.nBufferCountActual = newBufferCount; err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err != OK) { - ALOGE("[%s] setting nBufferCountActual to %lu failed: %d", - mComponentName.c_str(), newBufferCount, err); + if (err == OK) { + *minUndequeuedBuffers += extraBuffers; + break; + } + + ALOGW("[%s] setting nBufferCountActual to %lu failed: %d", + mComponentName.c_str(), newBufferCount, err); + /* exit condition */ + if (extraBuffers == 0) { return err; } } @@ -679,6 +695,7 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { &bufferCount, &bufferSize, &minUndequeuedBuffers); if (err != 0) return err; + mNumUndequeuedBuffers = minUndequeuedBuffers; ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on " "output port", @@ -744,6 +761,7 @@ status_t ACodec::allocateOutputMetaDataBuffers() { &bufferCount, &bufferSize, &minUndequeuedBuffers); if (err != 0) return err; + mNumUndequeuedBuffers = minUndequeuedBuffers; ALOGV("[%s] Allocating %lu meta buffers on output port", mComponentName.c_str(), bufferCount); @@ -1041,6 +1059,9 @@ status_t ACodec::configureCodec( encoder = false; } + sp<AMessage> inputFormat = new AMessage(); + sp<AMessage> outputFormat = new AMessage(); + mIsEncoder = encoder; status_t err = setComponentRole(encoder /* isEncoder */, mime); @@ -1142,7 +1163,9 @@ status_t ACodec::configureCodec( int32_t haveNativeWindow = msg->findObject("native-window", &obj) && obj != NULL; mStoreMetaDataInOutputBuffers = false; - mIsConfiguredForAdaptivePlayback = false; + if (video && !encoder) { + inputFormat->setInt32("adaptive-playback", false); + } if (!encoder && video && haveNativeWindow) { err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE); if (err != OK) { @@ -1187,14 +1210,19 @@ status_t ACodec::configureCodec( ALOGW_IF(err != OK, "[%s] prepareForAdaptivePlayback failed w/ err %d", mComponentName.c_str(), err); - mIsConfiguredForAdaptivePlayback = (err == OK); + + if (err == OK) { + inputFormat->setInt32("max-width", maxWidth); + inputFormat->setInt32("max-height", maxHeight); + inputFormat->setInt32("adaptive-playback", true); + } } // allow failure err = OK; } else { ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str()); mStoreMetaDataInOutputBuffers = true; - mIsConfiguredForAdaptivePlayback = true; + inputFormat->setInt32("adaptive-playback", true); } int32_t push; @@ -1334,6 +1362,11 @@ status_t ACodec::configureCodec( err = setMinBufferSize(kPortIndexInput, 8192); // XXX } + CHECK_EQ(getPortFormat(kPortIndexInput, inputFormat), (status_t)OK); + CHECK_EQ(getPortFormat(kPortIndexOutput, outputFormat), (status_t)OK); + mInputFormat = inputFormat; + mOutputFormat = outputFormat; + return err; } @@ -2498,19 +2531,7 @@ void ACodec::waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs() { return; } - int minUndequeuedBufs = 0; - status_t err = mNativeWindow->query( - mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - &minUndequeuedBufs); - - if (err != OK) { - ALOGE("[%s] NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)", - mComponentName.c_str(), strerror(-err), -err); - - minUndequeuedBufs = 0; - } - - while (countBuffersOwnedByNativeWindow() > (size_t)minUndequeuedBufs + while (countBuffersOwnedByNativeWindow() > mNumUndequeuedBuffers && dequeueBufferFromNativeWindow() != NULL) { // these buffers will be submitted as regular buffers; account for this if (mStoreMetaDataInOutputBuffers && mMetaDataBuffersToSubmit > 0) { @@ -2556,79 +2577,78 @@ void ACodec::processDeferredMessages() { } } -void ACodec::sendFormatChange(const sp<AMessage> &reply) { - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatOutputFormatChanged); - +status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { + // TODO: catch errors an return them instead of using CHECK OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; + def.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)), (status_t)OK); - CHECK_EQ((int)def.eDir, (int)OMX_DirOutput); + CHECK_EQ((int)def.eDir, + (int)(portIndex == kPortIndexOutput ? OMX_DirOutput : OMX_DirInput)); switch (def.eDomain) { case OMX_PortDomainVideo: { OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video; + switch ((int)videoDef->eCompressionFormat) { + case OMX_VIDEO_CodingUnused: + { + CHECK(mIsEncoder ^ (portIndex == kPortIndexOutput)); + notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW); + + notify->setInt32("stride", videoDef->nStride); + notify->setInt32("slice-height", videoDef->nSliceHeight); + notify->setInt32("color-format", videoDef->eColorFormat); + + OMX_CONFIG_RECTTYPE rect; + InitOMXParams(&rect); + rect.nPortIndex = kPortIndexOutput; + + if (mOMX->getConfig( + mNode, OMX_IndexConfigCommonOutputCrop, + &rect, sizeof(rect)) != OK) { + rect.nLeft = 0; + rect.nTop = 0; + rect.nWidth = videoDef->nFrameWidth; + rect.nHeight = videoDef->nFrameHeight; + } - AString mime; - if (!mIsEncoder) { - notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW); - } else if (GetMimeTypeForVideoCoding( - videoDef->eCompressionFormat, &mime) != OK) { - notify->setString("mime", "application/octet-stream"); - } else { - notify->setString("mime", mime.c_str()); - } - - notify->setInt32("width", videoDef->nFrameWidth); - notify->setInt32("height", videoDef->nFrameHeight); - - if (!mIsEncoder) { - notify->setInt32("stride", videoDef->nStride); - notify->setInt32("slice-height", videoDef->nSliceHeight); - notify->setInt32("color-format", videoDef->eColorFormat); - - OMX_CONFIG_RECTTYPE rect; - InitOMXParams(&rect); - rect.nPortIndex = kPortIndexOutput; - - if (mOMX->getConfig( - mNode, OMX_IndexConfigCommonOutputCrop, - &rect, sizeof(rect)) != OK) { - rect.nLeft = 0; - rect.nTop = 0; - rect.nWidth = videoDef->nFrameWidth; - rect.nHeight = videoDef->nFrameHeight; - } + CHECK_GE(rect.nLeft, 0); + CHECK_GE(rect.nTop, 0); + CHECK_GE(rect.nWidth, 0u); + CHECK_GE(rect.nHeight, 0u); + CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth); + CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight); - CHECK_GE(rect.nLeft, 0); - CHECK_GE(rect.nTop, 0); - CHECK_GE(rect.nWidth, 0u); - CHECK_GE(rect.nHeight, 0u); - CHECK_LE(rect.nLeft + rect.nWidth - 1, videoDef->nFrameWidth); - CHECK_LE(rect.nTop + rect.nHeight - 1, videoDef->nFrameHeight); - - notify->setRect( - "crop", - rect.nLeft, - rect.nTop, - rect.nLeft + rect.nWidth - 1, - rect.nTop + rect.nHeight - 1); - - if (mNativeWindow != NULL) { - reply->setRect( + notify->setRect( "crop", rect.nLeft, rect.nTop, - rect.nLeft + rect.nWidth, - rect.nTop + rect.nHeight); + rect.nLeft + rect.nWidth - 1, + rect.nTop + rect.nHeight - 1); + + break; + } + default: + { + CHECK(mIsEncoder ^ (portIndex == kPortIndexInput)); + AString mime; + if (GetMimeTypeForVideoCoding( + videoDef->eCompressionFormat, &mime) != OK) { + notify->setString("mime", "application/octet-stream"); + } else { + notify->setString("mime", mime.c_str()); + } + break; } } + + notify->setInt32("width", videoDef->nFrameWidth); + notify->setInt32("height", videoDef->nFrameHeight); break; } @@ -2641,7 +2661,7 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { { OMX_AUDIO_PARAM_PCMMODETYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamAudioPcm, @@ -2661,20 +2681,6 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSamplingRate); - if (mEncoderDelay + mEncoderPadding) { - size_t frameSize = params.nChannels * sizeof(int16_t); - if (mSkipCutBuffer != NULL) { - size_t prevbufsize = mSkipCutBuffer->size(); - if (prevbufsize != 0) { - ALOGW("Replacing SkipCutBuffer holding %d " - "bytes", - prevbufsize); - } - } - mSkipCutBuffer = new SkipCutBuffer( - mEncoderDelay * frameSize, - mEncoderPadding * frameSize); - } if (mChannelMaskPresent) { notify->setInt32("channel-mask", mChannelMask); @@ -2686,7 +2692,7 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { { OMX_AUDIO_PARAM_AACPROFILETYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamAudioAac, @@ -2703,7 +2709,7 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { { OMX_AUDIO_PARAM_AMRTYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamAudioAmr, @@ -2729,7 +2735,7 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { { OMX_AUDIO_PARAM_FLACTYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ(mOMX->getParameter( mNode, OMX_IndexParamAudioFlac, @@ -2742,11 +2748,45 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { break; } + case OMX_AUDIO_CodingMP3: + { + OMX_AUDIO_PARAM_MP3TYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + CHECK_EQ(mOMX->getParameter( + mNode, OMX_IndexParamAudioMp3, + ¶ms, sizeof(params)), + (status_t)OK); + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_MPEG); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + + case OMX_AUDIO_CodingVORBIS: + { + OMX_AUDIO_PARAM_VORBISTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + CHECK_EQ(mOMX->getParameter( + mNode, OMX_IndexParamAudioVorbis, + ¶ms, sizeof(params)), + (status_t)OK); + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_VORBIS); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + case OMX_AUDIO_CodingAndroidAC3: { OMX_AUDIO_PARAM_ANDROID_AC3TYPE params; InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; + params.nPortIndex = portIndex; CHECK_EQ((status_t)OK, mOMX->getParameter( mNode, @@ -2761,6 +2801,7 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { } default: + ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding); TRESPASS(); } break; @@ -2770,6 +2811,43 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { TRESPASS(); } + return OK; +} + +void ACodec::sendFormatChange(const sp<AMessage> &reply) { + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatOutputFormatChanged); + + CHECK_EQ(getPortFormat(kPortIndexOutput, notify), (status_t)OK); + + AString mime; + CHECK(notify->findString("mime", &mime)); + + int32_t left, top, right, bottom; + if (mime == MEDIA_MIMETYPE_VIDEO_RAW && + mNativeWindow != NULL && + notify->findRect("crop", &left, &top, &right, &bottom)) { + // notify renderer of the crop change + // NOTE: native window uses extended right-bottom coordinate + reply->setRect("crop", left, top, right + 1, bottom + 1); + } else if (mime == MEDIA_MIMETYPE_AUDIO_RAW && + (mEncoderDelay || mEncoderPadding)) { + int32_t channelCount; + CHECK(notify->findInt32("channel-count", &channelCount)); + size_t frameSize = channelCount * sizeof(int16_t); + if (mSkipCutBuffer != NULL) { + size_t prevbufsize = mSkipCutBuffer->size(); + if (prevbufsize != 0) { + ALOGW("Replacing SkipCutBuffer holding %d " + "bytes", + prevbufsize); + } + } + mSkipCutBuffer = new SkipCutBuffer( + mEncoderDelay * frameSize, + mEncoderPadding * frameSize); + } + notify->post(); mSentFormat = true; @@ -3026,6 +3104,14 @@ bool ACodec::BaseState::onOMXMessage(const sp<AMessage> &msg) { int32_t type; CHECK(msg->findInt32("type", &type)); + // there is a possibility that this is an outstanding message for a + // codec that we have already destroyed + if (mCodec->mNode == NULL) { + ALOGI("ignoring message as already freed component: %s", + msg->debugString().c_str()); + return true; + } + IOMX::node_id nodeID; CHECK(msg->findPointer("node", &nodeID)); CHECK_EQ(nodeID, mCodec->mNode); @@ -3637,7 +3723,8 @@ bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) { int32_t keepComponentAllocated; CHECK(msg->findInt32( "keepComponentAllocated", &keepComponentAllocated)); - CHECK(!keepComponentAllocated); + ALOGW_IF(keepComponentAllocated, + "cannot keep component allocated on shutdown in Uninitialized state"); sp<AMessage> notify = mCodec->mNotify->dup(); notify->setInt32("what", ACodec::kWhatShutdownCompleted); @@ -3799,7 +3886,8 @@ void ACodec::LoadedState::stateEntered() { mCodec->mDequeueCounter = 0; mCodec->mMetaDataBuffersToSubmit = 0; mCodec->mRepeatFrameDelayUs = -1ll; - mCodec->mIsConfiguredForAdaptivePlayback = false; + mCodec->mInputFormat.clear(); + mCodec->mOutputFormat.clear(); if (mCodec->mShutdownInProgress) { bool keepComponentAllocated = mCodec->mKeepComponentAllocated; @@ -3809,6 +3897,7 @@ void ACodec::LoadedState::stateEntered() { onShutdown(keepComponentAllocated); } + mCodec->mExplicitShutdown = false; } void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { @@ -3818,9 +3907,12 @@ void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) { mCodec->changeState(mCodec->mUninitializedState); } - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", ACodec::kWhatShutdownCompleted); - notify->post(); + if (mCodec->mExplicitShutdown) { + sp<AMessage> notify = mCodec->mNotify->dup(); + notify->setInt32("what", ACodec::kWhatShutdownCompleted); + notify->post(); + mCodec->mExplicitShutdown = false; + } } bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) { @@ -3854,6 +3946,7 @@ bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) { CHECK(msg->findInt32( "keepComponentAllocated", &keepComponentAllocated)); + mCodec->mExplicitShutdown = true; onShutdown(keepComponentAllocated); handled = true; @@ -3913,6 +4006,8 @@ bool ACodec::LoadedState::onConfigureComponent( { sp<AMessage> notify = mCodec->mNotify->dup(); notify->setInt32("what", ACodec::kWhatComponentConfigured); + notify->setMessage("input-format", mCodec->mInputFormat); + notify->setMessage("output-format", mCodec->mOutputFormat); notify->post(); } @@ -4271,6 +4366,7 @@ bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) { "keepComponentAllocated", &keepComponentAllocated)); mCodec->mShutdownInProgress = true; + mCodec->mExplicitShutdown = true; mCodec->mKeepComponentAllocated = keepComponentAllocated; mActive = false; diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index 8623100..2669849 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -221,7 +221,8 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) { mAudioTrack = new AudioTrack( AUDIO_STREAM_MUSIC, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask, - 0, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, 0); + 0 /*frameCount*/, AUDIO_OUTPUT_FLAG_NONE, &AudioCallback, this, + 0 /*notificationFrames*/); if ((err = mAudioTrack->initCheck()) != OK) { mAudioTrack.clear(); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index fe21296..601dccf 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -352,6 +352,20 @@ status_t MediaCodec::getOutputFormat(sp<AMessage> *format) const { return OK; } +status_t MediaCodec::getInputFormat(sp<AMessage> *format) const { + sp<AMessage> msg = new AMessage(kWhatGetInputFormat, id()); + + sp<AMessage> response; + status_t err; + if ((err = PostAndAwaitResponse(msg, &response)) != OK) { + return err; + } + + CHECK(response->findMessage("format", format)); + + return OK; +} + status_t MediaCodec::getName(AString *name) const { sp<AMessage> msg = new AMessage(kWhatGetName, id()); @@ -589,6 +603,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { postActivityNotificationIfPossible(); cancelPendingDequeueOperations(); + setState(UNINITIALIZED); break; } @@ -598,6 +613,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { mFlags |= kFlagStickyError; postActivityNotificationIfPossible(); + setState(UNINITIALIZED); break; } } @@ -642,6 +658,9 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { // reset input surface flag mHaveInputSurface = false; + CHECK(msg->findMessage("input-format", &mInputFormat)); + CHECK(msg->findMessage("output-format", &mOutputFormat)); + (new AMessage)->postReply(mReplyID); break; } @@ -1330,14 +1349,19 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { break; } + case kWhatGetInputFormat: case kWhatGetOutputFormat: { + sp<AMessage> format = + (msg->what() == kWhatGetOutputFormat ? mOutputFormat : mInputFormat); + uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if ((mState != STARTED && mState != FLUSHING) + if ((mState != CONFIGURED && mState != STARTING && + mState != STARTED && mState != FLUSHING) || (mFlags & kFlagStickyError) - || mOutputFormat == NULL) { + || format == NULL) { sp<AMessage> response = new AMessage; response->setInt32("err", INVALID_OPERATION); @@ -1346,7 +1370,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { } sp<AMessage> response = new AMessage; - response->setMessage("format", mOutputFormat); + response->setMessage("format", format); response->postReply(replyID); break; } diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 6248e90..8a451c8 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -48,22 +48,43 @@ const MediaCodecList *MediaCodecList::getInstance() { MediaCodecList::MediaCodecList() : mInitCheck(NO_INIT) { - FILE *file = fopen("/etc/media_codecs.xml", "r"); + parseTopLevelXMLFile("/etc/media_codecs.xml"); +} - if (file == NULL) { - ALOGW("unable to open media codecs configuration xml file."); +void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) { + // get href_base + char *href_base_end = strrchr(codecs_xml, '/'); + if (href_base_end != NULL) { + mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1); + } + + mInitCheck = OK; + mCurrentSection = SECTION_TOPLEVEL; + mDepth = 0; + + parseXMLFile(codecs_xml); + + if (mInitCheck != OK) { + mCodecInfos.clear(); + mCodecQuirks.clear(); return; } - parseXMLFile(file); + // These are currently still used by the video editing suite. + addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm"); + addMediaCodec( + false /* encoder */, "OMX.google.raw.decoder", "audio/raw"); - if (mInitCheck == OK) { - // These are currently still used by the video editing suite. + for (size_t i = mCodecInfos.size(); i-- > 0;) { + CodecInfo *info = &mCodecInfos.editItemAt(i); - addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm"); + if (info->mTypes == 0) { + // No types supported by this component??? + ALOGW("Component %s does not support any type of media?", + info->mName.c_str()); - addMediaCodec( - false /* encoder */, "OMX.google.raw.decoder", "audio/raw"); + mCodecInfos.removeAt(i); + } } #if 0 @@ -84,9 +105,6 @@ MediaCodecList::MediaCodecList() ALOGI("%s", line.c_str()); } #endif - - fclose(file); - file = NULL; } MediaCodecList::~MediaCodecList() { @@ -96,10 +114,14 @@ status_t MediaCodecList::initCheck() const { return mInitCheck; } -void MediaCodecList::parseXMLFile(FILE *file) { - mInitCheck = OK; - mCurrentSection = SECTION_TOPLEVEL; - mDepth = 0; +void MediaCodecList::parseXMLFile(const char *path) { + FILE *file = fopen(path, "r"); + + if (file == NULL) { + ALOGW("unable to open media codecs configuration xml file: %s", path); + mInitCheck = NAME_NOT_FOUND; + return; + } XML_Parser parser = ::XML_ParserCreate(NULL); CHECK(parser != NULL); @@ -112,7 +134,7 @@ void MediaCodecList::parseXMLFile(FILE *file) { while (mInitCheck == OK) { void *buff = ::XML_GetBuffer(parser, BUFF_SIZE); if (buff == NULL) { - ALOGE("failed to in call to XML_GetBuffer()"); + ALOGE("failed in call to XML_GetBuffer()"); mInitCheck = UNKNOWN_ERROR; break; } @@ -124,8 +146,9 @@ void MediaCodecList::parseXMLFile(FILE *file) { break; } - if (::XML_ParseBuffer(parser, bytes_read, bytes_read == 0) - != XML_STATUS_OK) { + XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0); + if (status != XML_STATUS_OK) { + ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser))); mInitCheck = ERROR_MALFORMED; break; } @@ -137,25 +160,8 @@ void MediaCodecList::parseXMLFile(FILE *file) { ::XML_ParserFree(parser); - if (mInitCheck == OK) { - for (size_t i = mCodecInfos.size(); i-- > 0;) { - CodecInfo *info = &mCodecInfos.editItemAt(i); - - if (info->mTypes == 0) { - // No types supported by this component??? - - ALOGW("Component %s does not support any type of media?", - info->mName.c_str()); - - mCodecInfos.removeAt(i); - } - } - } - - if (mInitCheck != OK) { - mCodecInfos.clear(); - mCodecQuirks.clear(); - } + fclose(file); + file = NULL; } // static @@ -169,12 +175,63 @@ void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) { static_cast<MediaCodecList *>(me)->endElementHandler(name); } +status_t MediaCodecList::includeXMLFile(const char **attrs) { + const char *href = NULL; + size_t i = 0; + while (attrs[i] != NULL) { + if (!strcmp(attrs[i], "href")) { + if (attrs[i + 1] == NULL) { + return -EINVAL; + } + href = attrs[i + 1]; + ++i; + } else { + return -EINVAL; + } + ++i; + } + + // For security reasons and for simplicity, file names can only contain + // [a-zA-Z0-9_.] and must start with media_codecs_ and end with .xml + for (i = 0; href[i] != '\0'; i++) { + if (href[i] == '.' || href[i] == '_' || + (href[i] >= '0' && href[i] <= '9') || + (href[i] >= 'A' && href[i] <= 'Z') || + (href[i] >= 'a' && href[i] <= 'z')) { + continue; + } + ALOGE("invalid include file name: %s", href); + return -EINVAL; + } + + AString filename = href; + if (!filename.startsWith("media_codecs_") || + !filename.endsWith(".xml")) { + ALOGE("invalid include file name: %s", href); + return -EINVAL; + } + filename.insert(mHrefBase, 0); + + parseXMLFile(filename.c_str()); + return mInitCheck; +} + void MediaCodecList::startElementHandler( const char *name, const char **attrs) { if (mInitCheck != OK) { return; } + if (!strcmp(name, "Include")) { + mInitCheck = includeXMLFile(attrs); + if (mInitCheck == OK) { + mPastSections.push(mCurrentSection); + mCurrentSection = SECTION_INCLUDE; + } + ++mDepth; + return; + } + switch (mCurrentSection) { case SECTION_TOPLEVEL: { @@ -264,6 +321,15 @@ void MediaCodecList::endElementHandler(const char *name) { break; } + case SECTION_INCLUDE: + { + if (!strcmp(name, "Include") && mPastSections.size() > 0) { + mCurrentSection = mPastSections.top(); + mPastSections.pop(); + } + break; + } + default: break; } diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 4d3b5bd..1cfe6c0 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -94,6 +94,7 @@ static sp<MediaSource> InstantiateSoftwareEncoder( #define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__) #define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__) +#define CODEC_LOGW(x, ...) ALOGW("[%s] "x, mComponentName, ##__VA_ARGS__) #define CODEC_LOGE(x, ...) ALOGE("[%s] "x, mComponentName, ##__VA_ARGS__) struct OMXCodecObserver : public BnOMXObserver { @@ -1803,21 +1804,42 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { strerror(-err), -err); return err; } - - // XXX: Is this the right logic to use? It's not clear to me what the OMX - // buffer counts refer to - how do they account for the renderer holding on - // to buffers? - if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) { - OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs; + // FIXME: assume that surface is controlled by app (native window + // returns the number for the case when surface is not controlled by app) + // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported + // For now, try to allocate 1 more buffer, but don't fail if unsuccessful + + // Use conservative allocation while also trying to reduce starvation + // + // 1. allocate at least nBufferCountMin + minUndequeuedBuffers - that is the + // minimum needed for the consumer to be able to work + // 2. try to allocate two (2) additional buffers to reduce starvation from + // the consumer + // plus an extra buffer to account for incorrect minUndequeuedBufs + CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1", + def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); + + for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) { + OMX_U32 newBufferCount = + def.nBufferCountMin + minUndequeuedBufs + extraBuffers; def.nBufferCountActual = newBufferCount; err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err != OK) { - CODEC_LOGE("setting nBufferCountActual to %lu failed: %d", - newBufferCount, err); + + if (err == OK) { + minUndequeuedBufs += extraBuffers; + break; + } + + CODEC_LOGW("setting nBufferCountActual to %lu failed: %d", + newBufferCount, err); + /* exit condition */ + if (extraBuffers == 0) { return err; } } + CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1", + def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); err = native_window_set_buffer_count( mNativeWindow.get(), def.nBufferCountActual); diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index 4ac8999..532e36f 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -387,7 +387,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { bool signalError = false; if (inHeader->nFilledLen < 7) { ALOGE("Audio data too short to contain even the ADTS header. " - "Got %ld bytes.", inHeader->nFilledLen); + "Got %d bytes.", inHeader->nFilledLen); hexdump(adtsHeader, inHeader->nFilledLen); signalError = true; } else { @@ -400,7 +400,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { if (inHeader->nFilledLen < aac_frame_length) { ALOGE("Not enough audio data for the complete frame. " - "Got %ld bytes, frame size according to the ADTS " + "Got %d bytes, frame size according to the ADTS " "header is %u bytes.", inHeader->nFilledLen, aac_frame_length); hexdump(adtsHeader, inHeader->nFilledLen); diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp index 9a91579..6093621 100644 --- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp +++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp @@ -308,7 +308,7 @@ status_t SoftAACEncoder2::setAudioParams() { // We call this whenever sample rate, number of channels or bitrate change // in reponse to setParameter calls. - ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps", + ALOGV("setAudioParams: %u Hz, %u channels, %u bps", mSampleRate, mNumChannels, mBitRate); if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT, @@ -364,7 +364,7 @@ void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) { OMX_U32 actualBitRate = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE); if (mBitRate != actualBitRate) { - ALOGW("Requested bitrate %lu unsupported, using %lu", mBitRate, actualBitRate); + ALOGW("Requested bitrate %u unsupported, using %u", mBitRate, actualBitRate); } AACENC_InfoStruct encInfo; diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp index a15b040..0f4a00d 100644 --- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp +++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp @@ -827,7 +827,7 @@ void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mStoreMetaDataInBuffers) { if (inHeader->nFilledLen != 8) { ALOGE("MetaData buffer is wrong size! " - "(got %lu bytes, expected 8)", inHeader->nFilledLen); + "(got %u bytes, expected 8)", inHeader->nFilledLen); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); return; @@ -988,7 +988,7 @@ uint8_t *SoftAVCEncoder::extractGrallocData(void *data, buffer_handle_t *buffer) status_t res; if (type != kMetadataBufferTypeGrallocSource) { ALOGE("Data passed in with metadata mode does not have type " - "kMetadataBufferTypeGrallocSource (%d), has type %ld instead", + "kMetadataBufferTypeGrallocSource (%d), has type %d instead", kMetadataBufferTypeGrallocSource, type); return NULL; } diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp index 40661e7..1301060 100644 --- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp +++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp @@ -210,7 +210,7 @@ OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter( mNumChannels = pcmParams->nChannels; mSampleRate = pcmParams->nSamplingRate; - ALOGV("will encode %ld channels at %ldHz", mNumChannels, mSampleRate); + ALOGV("will encode %d channels at %dHz", mNumChannels, mSampleRate); return configureEncoder(); } @@ -247,7 +247,7 @@ OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter( if (defParams->nPortIndex == 0) { if (defParams->nBufferSize > kMaxInputBufferSize) { - ALOGE("Input buffer size must be at most %zu bytes", + ALOGE("Input buffer size must be at most %d bytes", kMaxInputBufferSize); return OMX_ErrorUnsupportedSetting; } @@ -264,7 +264,7 @@ OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter( void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) { UNUSED_UNLESS_VERBOSE(portIndex); - ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%ld)", portIndex); + ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%d)", portIndex); if (mSignalledError) { return; @@ -296,7 +296,7 @@ void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) { } if (inHeader->nFilledLen > kMaxInputBufferSize) { - ALOGE("input buffer too large (%ld).", inHeader->nFilledLen); + ALOGE("input buffer too large (%d).", inHeader->nFilledLen); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); return; @@ -354,12 +354,12 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( size_t bytes, unsigned samples, unsigned current_frame) { UNUSED_UNLESS_VERBOSE(current_frame); - ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%d, samples=%d, curr_frame=%d)", + ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%zu, samples=%u, curr_frame=%u)", bytes, samples, current_frame); #ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER if (samples == 0) { - ALOGI(" saving %d bytes of header", bytes); + ALOGI(" saving %zu bytes of header", bytes); memcpy(mHeader + mHeaderOffset, buffer, bytes); mHeaderOffset += bytes;// will contain header size when finished receiving header return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; @@ -370,7 +370,7 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( if ((samples == 0) || !mEncoderWriteData) { // called by the encoder because there's header data to save, but it's not the role // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined) - ALOGV("ignoring %d bytes of header data (samples=%d)", bytes, samples); + ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples); return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; } @@ -391,9 +391,9 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( #endif // write encoded data - ALOGV(" writing %d bytes of encoded data on output port", bytes); + ALOGV(" writing %zu bytes of encoded data on output port", bytes); if (bytes > outHeader->nAllocLen - outHeader->nOffset - outHeader->nFilledLen) { - ALOGE(" not enough space left to write encoded data, dropping %u bytes", bytes); + ALOGE(" not enough space left to write encoded data, dropping %zu bytes", bytes); // a fatal error would stop the encoding return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; } @@ -412,7 +412,7 @@ FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable( OMX_ERRORTYPE SoftFlacEncoder::configureEncoder() { - ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%ld, sampleRate=%ld", + ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%d, sampleRate=%d", mNumChannels, mSampleRate); if (mSignalledError || (mFlacStreamEncoder == NULL)) { diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp index 160ada0..240c0c1 100644 --- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp +++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp @@ -212,7 +212,7 @@ void SoftG711::onQueueFilled(OMX_U32 /* portIndex */) { } if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) { - ALOGE("input buffer too large (%ld).", inHeader->nFilledLen); + ALOGE("input buffer too large (%d).", inHeader->nFilledLen); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp index 18f7d29..4debc48 100644 --- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp +++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp @@ -202,13 +202,13 @@ void SoftGSM::onQueueFilled(OMX_U32 /* portIndex */) { } if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) { - ALOGE("input buffer too large (%ld).", inHeader->nFilledLen); + ALOGE("input buffer too large (%d).", inHeader->nFilledLen); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; } if(((inHeader->nFilledLen / 65) * 65) != inHeader->nFilledLen) { - ALOGE("input buffer not multiple of 65 (%ld).", inHeader->nFilledLen); + ALOGE("input buffer not multiple of 65 (%d).", inHeader->nFilledLen); notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); mSignalledError = true; } diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp index 2c73e57..e25709d 100644 --- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp @@ -33,6 +33,8 @@ #include "SoftMPEG4Encoder.h" +#include <inttypes.h> + namespace android { template<class T> @@ -683,7 +685,7 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { if (mStoreMetaDataInBuffers) { if (inHeader->nFilledLen != 8) { ALOGE("MetaData buffer is wrong size! " - "(got %lu bytes, expected 8)", inHeader->nFilledLen); + "(got %u bytes, expected 8)", inHeader->nFilledLen); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); return; @@ -725,7 +727,7 @@ void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { if (!PVEncodeVideoFrame(mHandle, &vin, &vout, &modTimeMs, outPtr, &dataLength, &nLayer) || !PVGetHintTrack(mHandle, &hintTrack)) { - ALOGE("Failed to encode frame or get hink track at frame %lld", + ALOGE("Failed to encode frame or get hink track at frame %" PRId64, mNumInputFrames); mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); @@ -771,7 +773,7 @@ uint8_t *SoftMPEG4Encoder::extractGrallocData(void *data, buffer_handle_t *buffe status_t res; if (type != kMetadataBufferTypeGrallocSource) { ALOGE("Data passed in with metadata mode does not have type " - "kMetadataBufferTypeGrallocSource (%d), has type %ld instead", + "kMetadataBufferTypeGrallocSource (%d), has type %d instead", kMetadataBufferTypeGrallocSource, type); return NULL; } diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index a09ab7c..5396022 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -146,6 +146,23 @@ OMX_ERRORTYPE SoftMP3::internalGetParameter( return OMX_ErrorNone; } + case OMX_IndexParamAudioMp3: + { + OMX_AUDIO_PARAM_MP3TYPE *mp3Params = + (OMX_AUDIO_PARAM_MP3TYPE *)params; + + if (mp3Params->nPortIndex > 1) { + return OMX_ErrorUndefined; + } + + mp3Params->nChannels = mNumChannels; + mp3Params->nBitRate = 0 /* unknown */; + mp3Params->nSampleRate = mSamplingRate; + // other fields are encoder-only + + return OMX_ErrorNone; + } + default: return SimpleSoftOMXComponent::internalGetParameter(index, params); } diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp index 5efe022..b3a6bcc 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp @@ -141,9 +141,9 @@ SoftVPXEncoder::SoftVPXEncoder(const char *name, mWidth(176), mHeight(144), mBitrate(192000), // in bps + mFramerate(30 << 16), // in Q16 format mBitrateUpdated(false), mBitrateControlMode(VPX_VBR), // variable bitrate - mFrameDurationUs(33333), // Defaults to 30 fps mDCTPartitions(0), mErrorResilience(OMX_FALSE), mColorFormat(OMX_COLOR_FormatYUV420Planar), @@ -180,9 +180,8 @@ void SoftVPXEncoder::initPorts() { inputPort.format.video.nStride = inputPort.format.video.nFrameWidth; inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight; inputPort.format.video.nBitrate = 0; - // frameRate is reciprocal of frameDuration, which is - // in microseconds. It is also in Q16 format. - inputPort.format.video.xFramerate = (1000000/mFrameDurationUs) << 16; + // frameRate is in Q16 format. + inputPort.format.video.xFramerate = mFramerate; inputPort.format.video.bFlagErrorConcealment = OMX_FALSE; inputPort.nPortIndex = kInputPortIndex; inputPort.eDir = OMX_DirInput; @@ -220,7 +219,7 @@ void SoftVPXEncoder::initPorts() { outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8; outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused; outputPort.format.video.pNativeWindow = NULL; - outputPort.nBufferSize = 256 * 1024; // arbitrary + outputPort.nBufferSize = 1024 * 1024; // arbitrary addPort(outputPort); } @@ -277,8 +276,39 @@ status_t SoftVPXEncoder::initEncoder() { mCodecConfiguration->g_timebase.num = 1; mCodecConfiguration->g_timebase.den = 1000000; // rc_target_bitrate is in kbps, mBitrate in bps - mCodecConfiguration->rc_target_bitrate = mBitrate/1000; + mCodecConfiguration->rc_target_bitrate = mBitrate / 1000; mCodecConfiguration->rc_end_usage = mBitrateControlMode; + // Disable frame drop - not allowed in MediaCodec now. + mCodecConfiguration->rc_dropframe_thresh = 0; + if (mBitrateControlMode == VPX_CBR) { + // Disable spatial resizing. + mCodecConfiguration->rc_resize_allowed = 0; + // Single-pass mode. + mCodecConfiguration->g_pass = VPX_RC_ONE_PASS; + // Minimum quantization level. + mCodecConfiguration->rc_min_quantizer = 2; + // Maximum quantization level. + mCodecConfiguration->rc_max_quantizer = 63; + // Maximum amount of bits that can be subtracted from the target + // bitrate - expressed as percentage of the target bitrate. + mCodecConfiguration->rc_undershoot_pct = 100; + // Maximum amount of bits that can be added to the target + // bitrate - expressed as percentage of the target bitrate. + mCodecConfiguration->rc_overshoot_pct = 15; + // Initial value of the buffer level in ms. + mCodecConfiguration->rc_buf_initial_sz = 500; + // Amount of data that the encoder should try to maintain in ms. + mCodecConfiguration->rc_buf_optimal_sz = 600; + // The amount of data that may be buffered by the decoding + // application in ms. + mCodecConfiguration->rc_buf_sz = 1000; + // Enable error resilience - needed for packet loss. + mCodecConfiguration->g_error_resilient = 1; + // Disable lagged encoding. + mCodecConfiguration->g_lag_in_frames = 0; + // Encoder determines optimal key frame placement automatically. + mCodecConfiguration->kf_mode = VPX_KF_AUTO; + } codec_return = vpx_codec_enc_init(mCodecContext, mCodecInterface, @@ -298,6 +328,33 @@ status_t SoftVPXEncoder::initEncoder() { return UNKNOWN_ERROR; } + // Extra CBR settings + if (mBitrateControlMode == VPX_CBR) { + codec_return = vpx_codec_control(mCodecContext, + VP8E_SET_STATIC_THRESHOLD, + 1); + if (codec_return == VPX_CODEC_OK) { + uint32_t rc_max_intra_target = + mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10; + // Don't go below 3 times per frame bandwidth. + if (rc_max_intra_target < 300) { + rc_max_intra_target = 300; + } + codec_return = vpx_codec_control(mCodecContext, + VP8E_SET_MAX_INTRA_BITRATE_PCT, + rc_max_intra_target); + } + if (codec_return == VPX_CODEC_OK) { + codec_return = vpx_codec_control(mCodecContext, + VP8E_SET_CPUUSED, + -8); + } + if (codec_return != VPX_CODEC_OK) { + ALOGE("Error setting cbr parameters for vpx encoder."); + return UNKNOWN_ERROR; + } + } + if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) { if (mConversionBuffer == NULL) { mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); @@ -361,9 +418,7 @@ OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index, } formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; - // Converting from microseconds - // Also converting to Q16 format - formatParams->xFramerate = (1000000/mFrameDurationUs) << 16; + formatParams->xFramerate = mFramerate; return OMX_ErrorNone; } else if (formatParams->nPortIndex == kOutputPortIndex) { formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8; @@ -660,9 +715,7 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( mHeight = port->format.video.nFrameHeight; // xFramerate comes in Q16 format, in frames per second unit - const uint32_t framerate = port->format.video.xFramerate >> 16; - // frame duration is in microseconds - mFrameDurationUs = (1000000/framerate); + mFramerate = port->format.video.xFramerate; if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar || port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || @@ -684,6 +737,13 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( return OMX_ErrorNone; } else if (port->nPortIndex == kOutputPortIndex) { mBitrate = port->format.video.nBitrate; + mWidth = port->format.video.nFrameWidth; + mHeight = port->format.video.nFrameHeight; + + OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; + def->format.video.nFrameWidth = mWidth; + def->format.video.nFrameHeight = mHeight; + def->format.video.nBitrate = mBitrate; return OMX_ErrorNone; } else { return OMX_ErrorBadPortIndex; @@ -814,11 +874,12 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { mBitrateUpdated = false; } + uint32_t frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate); codec_return = vpx_codec_encode( mCodecContext, &raw_frame, inputBufferHeader->nTimeStamp, // in timebase units - mFrameDurationUs, // frame duration in timebase units + frameDuration, // frame duration in timebase units flags, // frame flags VPX_DL_REALTIME); // encoding deadline if (codec_return != VPX_CODEC_OK) { diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h index 076830f..1c983ab 100644 --- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h +++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h @@ -130,16 +130,15 @@ private: // Target bitrate set for the encoder, in bits per second. uint32_t mBitrate; + // Target framerate set for the encoder. + uint32_t mFramerate; + // If a request for a change it bitrate has been received. bool mBitrateUpdated; // Bitrate control mode, either constant or variable vpx_rc_mode mBitrateControlMode; - // Frame duration is the reciprocal of framerate, denoted - // in microseconds - uint64_t mFrameDurationUs; - // vp8 specific configuration parameter // that enables token partitioning of // the stream into substreams diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml new file mode 100644 index 0000000..b1f93de --- /dev/null +++ b/media/libstagefright/data/media_codecs_google_audio.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- 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. +--> + +<Included> + <Decoders> + <MediaCodec name="OMX.google.mp3.decoder" type="audio/mpeg" /> + <MediaCodec name="OMX.google.amrnb.decoder" type="audio/3gpp" /> + <MediaCodec name="OMX.google.amrwb.decoder" type="audio/amr-wb" /> + <MediaCodec name="OMX.google.aac.decoder" type="audio/mp4a-latm" /> + <MediaCodec name="OMX.google.g711.alaw.decoder" type="audio/g711-alaw" /> + <MediaCodec name="OMX.google.g711.mlaw.decoder" type="audio/g711-mlaw" /> + <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis" /> + <MediaCodec name="OMX.google.opus.decoder" type="audio/opus" /> + </Decoders> + + <Encoders> + <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm" /> + <MediaCodec name="OMX.google.amrnb.encoder" type="audio/3gpp" /> + <MediaCodec name="OMX.google.amrwb.encoder" type="audio/amr-wb" /> + <MediaCodec name="OMX.google.flac.encoder" type="audio/flac" /> + </Encoders> +</Included> diff --git a/media/libstagefright/data/media_codecs_google_telephony.xml b/media/libstagefright/data/media_codecs_google_telephony.xml new file mode 100644 index 0000000..28f5ffc --- /dev/null +++ b/media/libstagefright/data/media_codecs_google_telephony.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- 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. +--> + +<Included> + <Decoders> + <MediaCodec name="OMX.google.gsm.decoder" type="audio/gsm" /> + </Decoders> +</Included> diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml new file mode 100644 index 0000000..41e0efb --- /dev/null +++ b/media/libstagefright/data/media_codecs_google_video.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- 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. +--> + +<Included> + <Decoders> + <MediaCodec name="OMX.google.mpeg4.decoder" type="video/mp4v-es" /> + <MediaCodec name="OMX.google.h263.decoder" type="video/3gpp" /> + <MediaCodec name="OMX.google.h264.decoder" type="video/avc" /> + <MediaCodec name="OMX.google.vp8.decoder" type="video/x-vnd.on2.vp8" /> + <MediaCodec name="OMX.google.vp9.decoder" type="video/x-vnd.on2.vp9" /> + </Decoders> + + <Encoders> + <MediaCodec name="OMX.google.h263.encoder" type="video/3gpp" /> + <MediaCodec name="OMX.google.h264.encoder" type="video/avc" /> + <MediaCodec name="OMX.google.mpeg4.encoder" type="video/mp4v-es" /> + <MediaCodec name="OMX.google.vp8.encoder" type="video/x-vnd.on2.vp8" /> + </Encoders> +</Included> diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp index 08c4a87..af5be70 100644 --- a/media/libstagefright/foundation/ANetworkSession.cpp +++ b/media/libstagefright/foundation/ANetworkSession.cpp @@ -579,7 +579,7 @@ status_t ANetworkSession::Session::writeMore() { if (err == -EAGAIN) { if (!mOutFragments.empty()) { - ALOGI("%d datagrams remain queued.", mOutFragments.size()); + ALOGI("%zu datagrams remain queued.", mOutFragments.size()); } err = OK; } diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 19db6eb..fd42e77 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -43,6 +43,7 @@ #include <utils/Mutex.h> #include <ctype.h> +#include <inttypes.h> #include <openssl/aes.h> #include <openssl/md5.h> @@ -168,7 +169,7 @@ status_t LiveSession::dequeueAccessUnit( if (stream == STREAMTYPE_AUDIO || stream == STREAMTYPE_VIDEO) { int64_t timeUs; CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); - ALOGV("[%s] read buffer at time %lld us", streamStr, timeUs); + ALOGV("[%s] read buffer at time %" PRId64 " us", streamStr, timeUs); mLastDequeuedTimeUs = timeUs; mRealTimeBaseUs = ALooper::GetNowUs() - timeUs; @@ -622,7 +623,7 @@ sp<PlaylistFetcher> LiveSession::addFetcher(const char *uri) { * - block_size == 0 means entire range * */ -status_t LiveSession::fetchFile( +ssize_t LiveSession::fetchFile( const char *url, sp<ABuffer> *out, int64_t range_offset, int64_t range_length, uint32_t block_size, /* download block size */ @@ -673,8 +674,9 @@ status_t LiveSession::fetchFile( buffer->setRange(0, 0); } + ssize_t bytesRead = 0; // adjust range_length if only reading partial block - if (block_size > 0 && (range_length == -1 || buffer->size() + block_size < range_length)) { + if (block_size > 0 && (range_length == -1 || (int64_t)(buffer->size() + block_size) < range_length)) { range_length = buffer->size() + block_size; } for (;;) { @@ -683,7 +685,7 @@ status_t LiveSession::fetchFile( if (bufferRemaining == 0 && getSizeErr != OK) { bufferRemaining = 32768; - ALOGV("increasing download buffer to %d bytes", + ALOGV("increasing download buffer to %zu bytes", buffer->size() + bufferRemaining); sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining); @@ -696,7 +698,7 @@ status_t LiveSession::fetchFile( size_t maxBytesToRead = bufferRemaining; if (range_length >= 0) { int64_t bytesLeftInRange = range_length - buffer->size(); - if (bytesLeftInRange < maxBytesToRead) { + if (bytesLeftInRange < (int64_t)maxBytesToRead) { maxBytesToRead = bytesLeftInRange; if (bytesLeftInRange == 0) { @@ -720,6 +722,7 @@ status_t LiveSession::fetchFile( } buffer->setRange(0, buffer->size() + (size_t)n); + bytesRead += n; } *out = buffer; @@ -730,7 +733,7 @@ status_t LiveSession::fetchFile( } } - return OK; + return bytesRead; } sp<M3UParser> LiveSession::fetchPlaylist( @@ -741,9 +744,9 @@ sp<M3UParser> LiveSession::fetchPlaylist( sp<ABuffer> buffer; String8 actualUrl; - status_t err = fetchFile(url, &buffer, 0, -1, 0, NULL, &actualUrl); + ssize_t err = fetchFile(url, &buffer, 0, -1, 0, NULL, &actualUrl); - if (err != OK) { + if (err <= 0) { return NULL; } @@ -962,7 +965,7 @@ void LiveSession::changeConfiguration( mPrevBandwidthIndex = bandwidthIndex; - ALOGV("changeConfiguration => timeUs:%lld us, bwIndex:%d, pickTrack:%d", + ALOGV("changeConfiguration => timeUs:%" PRId64 " us, bwIndex:%zu, pickTrack:%d", timeUs, bandwidthIndex, pickTrack); if (pickTrack) { diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index f489ec4..d7ed56f 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -203,7 +203,7 @@ private: // // For reused HTTP sources, the caller must download a file sequentially without // any overlaps or gaps to prevent reconnection. - status_t fetchFile( + ssize_t fetchFile( const char *url, sp<ABuffer> *out, /* request/open a file starting at range_offset for range_length bytes */ int64_t range_offset = 0, int64_t range_length = -1, diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index dacdd40..f22d650 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -163,21 +163,21 @@ status_t M3UParser::MediaGroup::selectTrack(size_t index, bool select) { if (select) { if (index >= mMediaItems.size()) { - ALOGE("track %d does not exist", index); + ALOGE("track %zu does not exist", index); return INVALID_OPERATION; } if (mSelectedIndex == (ssize_t)index) { - ALOGE("track %d already selected", index); + ALOGE("track %zu already selected", index); return BAD_VALUE; } - ALOGV("selected track %d", index); + ALOGV("selected track %zu", index); mSelectedIndex = index; } else { if (mSelectedIndex != (ssize_t)index) { - ALOGE("track %d is not selected", index); + ALOGE("track %zu is not selected", index); return BAD_VALUE; } - ALOGV("unselected track %d", index); + ALOGV("unselected track %zu", index); mSelectedIndex = -1; } diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp index 9d7cb99..5011bc1 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -40,6 +40,7 @@ #include <media/stagefright/Utils.h> #include <ctype.h> +#include <inttypes.h> #include <openssl/aes.h> #include <openssl/md5.h> @@ -48,6 +49,7 @@ namespace android { // static const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll; const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll; +const int32_t PlaylistFetcher::kDownloadBlockSize = 192; const int32_t PlaylistFetcher::kNumSkipFrames = 10; PlaylistFetcher::PlaylistFetcher( @@ -216,9 +218,9 @@ status_t PlaylistFetcher::decryptBuffer( if (index >= 0) { key = mAESKeyForURI.valueAt(index); } else { - status_t err = mSession->fetchFile(keyURI.c_str(), &key); + ssize_t err = mSession->fetchFile(keyURI.c_str(), &key); - if (err != OK) { + if (err < 0) { ALOGE("failed to fetch cipher key from '%s'.", keyURI.c_str()); return ERROR_IO; } else if (key->size() != 16) { @@ -315,7 +317,7 @@ void PlaylistFetcher::postMonitorQueue(int64_t delayUs, int64_t minDelayUs) { maxDelayUs = minDelayUs; } if (delayUs > maxDelayUs) { - ALOGV("Need to refresh playlist in %lld", maxDelayUs); + ALOGV("Need to refresh playlist in %" PRId64 , maxDelayUs); delayUs = maxDelayUs; } sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id()); @@ -626,7 +628,7 @@ void PlaylistFetcher::onMonitorQueue() { int64_t bufferedStreamDurationUs = mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult); - ALOGV("buffered %lld for stream %d", + ALOGV("buffered %" PRId64 " for stream %d", bufferedStreamDurationUs, mPacketSources.keyAt(i)); if (bufferedStreamDurationUs > bufferedDurationUs) { bufferedDurationUs = bufferedStreamDurationUs; @@ -639,7 +641,7 @@ void PlaylistFetcher::onMonitorQueue() { if (!mPrepared && bufferedDurationUs > targetDurationUs && downloadMore) { mPrepared = true; - ALOGV("prepared, buffered=%lld > %lld", + ALOGV("prepared, buffered=%" PRId64 " > %" PRId64 "", bufferedDurationUs, targetDurationUs); sp<AMessage> msg = mNotify->dup(); msg->setInt32("what", kWhatTemporarilyDoneFetching); @@ -647,7 +649,7 @@ void PlaylistFetcher::onMonitorQueue() { } if (finalResult == OK && downloadMore) { - ALOGV("monitoring, buffered=%lld < %lld", + ALOGV("monitoring, buffered=%" PRId64 " < %" PRId64 "", bufferedDurationUs, durationToBufferUs); // delay the next download slightly; hopefully this gives other concurrent fetchers // a better chance to run. @@ -663,7 +665,7 @@ void PlaylistFetcher::onMonitorQueue() { msg->post(); int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2; - ALOGV("pausing for %lld, buffered=%lld > %lld", + ALOGV("pausing for %" PRId64 ", buffered=%" PRId64 " > %" PRId64 "", delayUs, bufferedDurationUs, durationToBufferUs); // :TRICKY: need to enforce minimum delay because the delay to // refresh the playlist will become 0 @@ -704,6 +706,11 @@ status_t PlaylistFetcher::refreshPlaylist() { return OK; } +// static +bool PlaylistFetcher::bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer) { + return buffer->size() > 0 && buffer->data()[0] == 0x47; +} + void PlaylistFetcher::onDownloadNext() { if (refreshPlaylist() != OK) { return; @@ -732,7 +739,7 @@ void PlaylistFetcher::onDownloadNext() { if (mPlaylist->isComplete() || mPlaylist->isEvent()) { mSeqNumber = getSeqNumberForTime(mStartTimeUs); - ALOGV("Initial sequence number for time %lld is %d from (%d .. %d)", + ALOGV("Initial sequence number for time %" PRId64 " is %d from (%d .. %d)", mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist); } else { @@ -766,7 +773,7 @@ void PlaylistFetcher::onDownloadNext() { delayUs = kMaxMonitorDelayUs; } ALOGV("sequence number high: %d from (%d .. %d), " - "monitor in %lld (retry=%d)", + "monitor in %" PRId64 " (retry=%d)", mSeqNumber, firstSeqNumberInPlaylist, lastSeqNumberInPlaylist, delayUs, mNumRetries); postMonitorQueue(delayUs); @@ -791,7 +798,7 @@ void PlaylistFetcher::onDownloadNext() { ALOGE("Cannot find sequence number %d in playlist " "(contains %d - %d)", mSeqNumber, firstSeqNumberInPlaylist, - firstSeqNumberInPlaylist + mPlaylist->size() - 1); + firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1); notifyError(ERROR_END_OF_STREAM); return; @@ -824,66 +831,161 @@ void PlaylistFetcher::onDownloadNext() { ALOGV("fetching '%s'", uri.c_str()); - sp<ABuffer> buffer; - status_t err = mSession->fetchFile( - uri.c_str(), &buffer, range_offset, range_length); - - if (err != OK) { - ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str()); - notifyError(err); - return; + sp<DataSource> source; + sp<ABuffer> buffer, tsBuffer; + // decrypt a junk buffer to prefetch key; since a session uses only one http connection, + // this avoids interleaved connections to the key and segment file. + { + sp<ABuffer> junk = new ABuffer(16); + junk->setRange(0, 16); + status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, junk, + true /* first */); + if (err != OK) { + notifyError(err); + return; + } } - CHECK(buffer != NULL); + // block-wise download + ssize_t bytesRead; + do { + bytesRead = mSession->fetchFile( + uri.c_str(), &buffer, range_offset, range_length, kDownloadBlockSize, &source); - err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer); - if (err == OK) { - err = checkDecryptPadding(buffer); - } + if (bytesRead < 0) { + status_t err = bytesRead; + ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str()); + notifyError(err); + return; + } - if (err != OK) { - ALOGE("decryptBuffer failed w/ error %d", err); + CHECK(buffer != NULL); - notifyError(err); - return; - } + size_t size = buffer->size(); + // Set decryption range. + buffer->setRange(size - bytesRead, bytesRead); + status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer, + buffer->offset() == 0 /* first */); + // Unset decryption range. + buffer->setRange(0, size); - if (mStartup || seekDiscontinuity || explicitDiscontinuity) { - // Signal discontinuity. + if (err != OK) { + ALOGE("decryptBuffer failed w/ error %d", err); - if (mPlaylist->isComplete() || mPlaylist->isEvent()) { - // If this was a live event this made no sense since - // we don't have access to all the segment before the current - // one. - mNextPTSTimeUs = getSegmentStartTimeUs(mSeqNumber); + notifyError(err); + return; } - if (seekDiscontinuity || explicitDiscontinuity) { - ALOGI("queueing discontinuity (seek=%d, explicit=%d)", - seekDiscontinuity, explicitDiscontinuity); + if (mStartup || seekDiscontinuity || explicitDiscontinuity) { + // Signal discontinuity. + + if (mPlaylist->isComplete() || mPlaylist->isEvent()) { + // If this was a live event this made no sense since + // we don't have access to all the segment before the current + // one. + mNextPTSTimeUs = getSegmentStartTimeUs(mSeqNumber); + } + + if (seekDiscontinuity || explicitDiscontinuity) { + ALOGI("queueing discontinuity (seek=%d, explicit=%d)", + seekDiscontinuity, explicitDiscontinuity); - queueDiscontinuity( - explicitDiscontinuity - ? ATSParser::DISCONTINUITY_FORMATCHANGE - : ATSParser::DISCONTINUITY_SEEK, - NULL /* extra */); + queueDiscontinuity( + explicitDiscontinuity + ? ATSParser::DISCONTINUITY_FORMATCHANGE + : ATSParser::DISCONTINUITY_SEEK, + NULL /* extra */); + } } - } - err = extractAndQueueAccessUnits(buffer, itemMeta); + err = OK; + if (bufferStartsWithTsSyncByte(buffer)) { + // Incremental extraction is only supported for MPEG2 transport streams. + if (tsBuffer == NULL) { + tsBuffer = new ABuffer(buffer->data(), buffer->capacity()); + tsBuffer->setRange(0, 0); + } else if (tsBuffer->capacity() != buffer->capacity()) { + size_t tsOff = tsBuffer->offset(), tsSize = tsBuffer->size(); + tsBuffer = new ABuffer(buffer->data(), buffer->capacity()); + tsBuffer->setRange(tsOff, tsSize); + } + tsBuffer->setRange(tsBuffer->offset(), tsBuffer->size() + bytesRead); + + err = extractAndQueueAccessUnitsFromTs(tsBuffer); + } + + if (err == -EAGAIN) { + // bad starting sequence number hint + postMonitorQueue(); + return; + } + + if (err == ERROR_OUT_OF_RANGE) { + // reached stopping point + stopAsync(/* selfTriggered = */ true); + return; + } + + if (err != OK) { + notifyError(err); + return; + } + + mStartup = false; + } while (bytesRead != 0); + + if (bufferStartsWithTsSyncByte(buffer)) { + // If we still don't see a stream after fetching a full ts segment mark it as + // nonexistent. + const size_t kNumTypes = ATSParser::NUM_SOURCE_TYPES; + ATSParser::SourceType srcTypes[kNumTypes] = + { ATSParser::VIDEO, ATSParser::AUDIO }; + LiveSession::StreamType streamTypes[kNumTypes] = + { LiveSession::STREAMTYPE_VIDEO, LiveSession::STREAMTYPE_AUDIO }; + + for (size_t i = 0; i < kNumTypes; i++) { + ATSParser::SourceType srcType = srcTypes[i]; + LiveSession::StreamType streamType = streamTypes[i]; + + sp<AnotherPacketSource> source = + static_cast<AnotherPacketSource *>( + mTSParser->getSource(srcType).get()); + + if (source == NULL) { + ALOGW("MPEG2 Transport stream does not contain %s data.", + srcType == ATSParser::VIDEO ? "video" : "audio"); + + mStreamTypeMask &= ~streamType; + mPacketSources.removeItem(streamType); + } + } - if (err == -EAGAIN) { - // bad starting sequence number hint - postMonitorQueue(); - return; } - if (err == ERROR_OUT_OF_RANGE) { - // reached stopping point - stopAsync(/* selfTriggered = */ true); + if (checkDecryptPadding(buffer) != OK) { + ALOGE("Incorrect padding bytes after decryption."); + notifyError(ERROR_MALFORMED); return; } + status_t err = OK; + if (tsBuffer != NULL) { + AString method; + CHECK(buffer->meta()->findString("cipher-method", &method)); + if ((tsBuffer->size() > 0 && method == "NONE") + || tsBuffer->size() > 16) { + ALOGE("MPEG2 transport stream is not an even multiple of 188 " + "bytes in length."); + notifyError(ERROR_MALFORMED); + return; + } + } + + // bulk extract non-ts files + if (tsBuffer == NULL) { + err = extractAndQueueAccessUnits(buffer, itemMeta); + } + if (err != OK) { notifyError(err); return; @@ -892,8 +994,6 @@ void PlaylistFetcher::onDownloadNext() { ++mSeqNumber; postMonitorQueue(); - - mStartup = false; } int32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const { @@ -928,173 +1028,163 @@ int32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const { return firstSeqNumberInPlaylist + index; } -status_t PlaylistFetcher::extractAndQueueAccessUnits( - const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) { - if (buffer->size() > 0 && buffer->data()[0] == 0x47) { - // Let's assume this is an MPEG2 transport stream. - - if ((buffer->size() % 188) != 0) { - ALOGE("MPEG2 transport stream is not an even multiple of 188 " - "bytes in length."); - return ERROR_MALFORMED; - } - - if (mTSParser == NULL) { - // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers. - mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE); - } - - if (mNextPTSTimeUs >= 0ll) { - sp<AMessage> extra = new AMessage; - // Since we are using absolute timestamps, signal an offset of 0 to prevent - // ATSParser from skewing the timestamps of access units. - extra->setInt64(IStreamListener::kKeyMediaTimeUs, 0); +status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer) { + if (mTSParser == NULL) { + // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers. + mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE); + } - mTSParser->signalDiscontinuity( - ATSParser::DISCONTINUITY_SEEK, extra); + if (mNextPTSTimeUs >= 0ll) { + sp<AMessage> extra = new AMessage; + // Since we are using absolute timestamps, signal an offset of 0 to prevent + // ATSParser from skewing the timestamps of access units. + extra->setInt64(IStreamListener::kKeyMediaTimeUs, 0); - mNextPTSTimeUs = -1ll; - } + mTSParser->signalDiscontinuity( + ATSParser::DISCONTINUITY_SEEK, extra); - size_t offset = 0; - while (offset < buffer->size()) { - status_t err = mTSParser->feedTSPacket(buffer->data() + offset, 188); + mNextPTSTimeUs = -1ll; + } - if (err != OK) { - return err; - } + size_t offset = 0; + while (offset + 188 <= buffer->size()) { + status_t err = mTSParser->feedTSPacket(buffer->data() + offset, 188); - offset += 188; + if (err != OK) { + return err; } - status_t err = OK; - for (size_t i = mPacketSources.size(); i-- > 0;) { - sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i); - - const char *key; - ATSParser::SourceType type; - const LiveSession::StreamType stream = mPacketSources.keyAt(i); - switch (stream) { + offset += 188; + } + // setRange to indicate consumed bytes. + buffer->setRange(buffer->offset() + offset, buffer->size() - offset); - case LiveSession::STREAMTYPE_VIDEO: - type = ATSParser::VIDEO; - key = "timeUsVideo"; - break; + status_t err = OK; + for (size_t i = mPacketSources.size(); i-- > 0;) { + sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i); - case LiveSession::STREAMTYPE_AUDIO: - type = ATSParser::AUDIO; - key = "timeUsAudio"; - break; + const char *key; + ATSParser::SourceType type; + const LiveSession::StreamType stream = mPacketSources.keyAt(i); + switch (stream) { + case LiveSession::STREAMTYPE_VIDEO: + type = ATSParser::VIDEO; + key = "timeUsVideo"; + break; - case LiveSession::STREAMTYPE_SUBTITLES: - { - ALOGE("MPEG2 Transport streams do not contain subtitles."); - return ERROR_MALFORMED; - break; - } + case LiveSession::STREAMTYPE_AUDIO: + type = ATSParser::AUDIO; + key = "timeUsAudio"; + break; - default: - TRESPASS(); + case LiveSession::STREAMTYPE_SUBTITLES: + { + ALOGE("MPEG2 Transport streams do not contain subtitles."); + return ERROR_MALFORMED; + break; } - sp<AnotherPacketSource> source = - static_cast<AnotherPacketSource *>( - mTSParser->getSource(type).get()); + default: + TRESPASS(); + } - if (source == NULL) { - ALOGW("MPEG2 Transport stream does not contain %s data.", - type == ATSParser::VIDEO ? "video" : "audio"); + sp<AnotherPacketSource> source = + static_cast<AnotherPacketSource *>( + mTSParser->getSource(type).get()); - mStreamTypeMask &= ~mPacketSources.keyAt(i); - mPacketSources.removeItemsAt(i); - continue; - } + if (source == NULL) { + continue; + } - int64_t timeUs; - sp<ABuffer> accessUnit; - status_t finalResult; - while (source->hasBufferAvailable(&finalResult) - && source->dequeueAccessUnit(&accessUnit) == OK) { - - CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); - if (mMinStartTimeUs > 0) { - if (timeUs < mMinStartTimeUs) { - // TODO untested path - // try a later ts - int32_t targetDuration; - mPlaylist->meta()->findInt32("target-duration", &targetDuration); - int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration; - if (incr == 0) { - // increment mSeqNumber by at least one - incr = 1; - } - mSeqNumber += incr; - err = -EAGAIN; - break; - } else { - int64_t startTimeUs; - if (mStartTimeUsNotify != NULL - && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) { - mStartTimeUsNotify->setInt64(key, timeUs); - - uint32_t streamMask = 0; - mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask); - streamMask |= mPacketSources.keyAt(i); - mStartTimeUsNotify->setInt32("streamMask", streamMask); - - if (streamMask == mStreamTypeMask) { - mStartTimeUsNotify->post(); - mStartTimeUsNotify.clear(); - } + int64_t timeUs; + sp<ABuffer> accessUnit; + status_t finalResult; + while (source->hasBufferAvailable(&finalResult) + && source->dequeueAccessUnit(&accessUnit) == OK) { + + CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs)); + if (mMinStartTimeUs > 0) { + if (timeUs < mMinStartTimeUs) { + // TODO untested path + // try a later ts + int32_t targetDuration; + mPlaylist->meta()->findInt32("target-duration", &targetDuration); + int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration; + if (incr == 0) { + // increment mSeqNumber by at least one + incr = 1; + } + mSeqNumber += incr; + err = -EAGAIN; + break; + } else { + int64_t startTimeUs; + if (mStartTimeUsNotify != NULL + && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) { + mStartTimeUsNotify->setInt64(key, timeUs); + + uint32_t streamMask = 0; + mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask); + streamMask |= mPacketSources.keyAt(i); + mStartTimeUsNotify->setInt32("streamMask", streamMask); + + if (streamMask == mStreamTypeMask) { + mStartTimeUsNotify->post(); + mStartTimeUsNotify.clear(); } } } + } - if (mStopParams != NULL) { - // Queue discontinuity in original stream. - int64_t stopTimeUs; - if (!mStopParams->findInt64(key, &stopTimeUs) || timeUs >= stopTimeUs) { - packetSource->queueAccessUnit(mSession->createFormatChangeBuffer()); - mStreamTypeMask &= ~stream; - mPacketSources.removeItemsAt(i); - break; - } + if (mStopParams != NULL) { + // Queue discontinuity in original stream. + int64_t stopTimeUs; + if (!mStopParams->findInt64(key, &stopTimeUs) || timeUs >= stopTimeUs) { + packetSource->queueAccessUnit(mSession->createFormatChangeBuffer()); + mStreamTypeMask &= ~stream; + mPacketSources.removeItemsAt(i); + break; } + } - // Note that we do NOT dequeue any discontinuities except for format change. - - // for simplicity, store a reference to the format in each unit - sp<MetaData> format = source->getFormat(); - if (format != NULL) { - accessUnit->meta()->setObject("format", format); - } + // Note that we do NOT dequeue any discontinuities except for format change. - // Stash the sequence number so we can hint future fetchers where to start at. - accessUnit->meta()->setInt32("seq", mSeqNumber); - packetSource->queueAccessUnit(accessUnit); + // for simplicity, store a reference to the format in each unit + sp<MetaData> format = source->getFormat(); + if (format != NULL) { + accessUnit->meta()->setObject("format", format); } - if (err != OK) { - break; - } + // Stash the sequence number so we can hint future playlist where to start at. + accessUnit->meta()->setInt32("seq", mSeqNumber); + packetSource->queueAccessUnit(accessUnit); } if (err != OK) { - for (size_t i = mPacketSources.size(); i-- > 0;) { - sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i); - packetSource->clear(); - } - return err; + break; } + } - if (!mStreamTypeMask) { - // Signal gap is filled between original and new stream. - ALOGV("ERROR OUT OF RANGE"); - return ERROR_OUT_OF_RANGE; + if (err != OK) { + for (size_t i = mPacketSources.size(); i-- > 0;) { + sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i); + packetSource->clear(); } + return err; + } - return OK; - } else if (buffer->size() >= 7 && !memcmp("WEBVTT\n", buffer->data(), 7)) { + if (!mStreamTypeMask) { + // Signal gap is filled between original and new stream. + ALOGV("ERROR OUT OF RANGE"); + return ERROR_OUT_OF_RANGE; + } + + return OK; +} + +status_t PlaylistFetcher::extractAndQueueAccessUnits( + const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) { + if (buffer->size() >= 7 && !memcmp("WEBVTT\n", buffer->data(), 7)) { if (mStreamTypeMask != LiveSession::STREAMTYPE_SUBTITLES) { ALOGE("This stream only contains subtitles."); return ERROR_MALFORMED; diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h index 8404b8d..7e21523 100644 --- a/media/libstagefright/httplive/PlaylistFetcher.h +++ b/media/libstagefright/httplive/PlaylistFetcher.h @@ -87,8 +87,11 @@ private: static const int64_t kMinBufferedDurationUs; static const int64_t kMaxMonitorDelayUs; + static const int32_t kDownloadBlockSize; static const int32_t kNumSkipFrames; + static bool bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer); + // notifications to mSession sp<AMessage> mNotify; sp<AMessage> mStartTimeUsNotify; @@ -169,6 +172,8 @@ private: // Resume a fetcher to continue until the stopping point stored in msg. status_t onResumeUntil(const sp<AMessage> &msg); + status_t extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer); + status_t extractAndQueueAccessUnits( const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta); diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index f0f203c..7f221a0 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -41,9 +41,9 @@ struct MemorySource : public DataSource { } virtual ssize_t readAt(off64_t offset, void *data, size_t size) { - off64_t available = (offset >= mSize) ? 0ll : mSize - offset; + off64_t available = (offset >= (off64_t)mSize) ? 0ll : mSize - offset; - size_t copy = (available > size) ? size : available; + size_t copy = (available > (off64_t)size) ? size : available; memcpy(data, mData + offset, copy); return copy; @@ -172,7 +172,7 @@ struct id3_header { } if (size > kMaxMetadataSize) { - ALOGE("skipping huge ID3 metadata of size %d", size); + ALOGE("skipping huge ID3 metadata of size %zu", size); return false; } @@ -633,8 +633,8 @@ void ID3::Iterator::findFrame() { mFrameSize += 6; if (mOffset + mFrameSize > mParent.mSize) { - ALOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)", - mOffset, mFrameSize, mParent.mSize - mOffset - 6); + ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)", + mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)6); return; } @@ -674,8 +674,8 @@ void ID3::Iterator::findFrame() { mFrameSize = 10 + baseSize; if (mOffset + mFrameSize > mParent.mSize) { - ALOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)", - mOffset, mFrameSize, mParent.mSize - mOffset - 10); + ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)", + mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)10); return; } diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index 6ec9263..d4a7c7f 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -33,6 +33,8 @@ #include <media/stagefright/Utils.h> #include <utils/String8.h> +#include <inttypes.h> + namespace android { struct DataSourceReader : public mkvparser::IMkvReader { @@ -103,7 +105,7 @@ struct BlockIterator { private: MatroskaExtractor *mExtractor; - unsigned long mTrackNum; + long long mTrackNum; const mkvparser::Cluster *mCluster; const mkvparser::BlockEntry *mBlockEntry; @@ -183,7 +185,7 @@ MatroskaSource::MatroskaSource( CHECK_GE(avccSize, 5u); mNALSizeLen = 1 + (avcc[4] & 3); - ALOGV("mNALSizeLen = %d", mNALSizeLen); + ALOGV("mNALSizeLen = %zu", mNALSizeLen); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { mType = AAC; } @@ -320,7 +322,7 @@ void BlockIterator::seek( // Special case the 0 seek to avoid loading Cues when the application // extraneously seeks to 0 before playing. if (seekTimeNs <= 0) { - ALOGV("Seek to beginning: %lld", seekTimeUs); + ALOGV("Seek to beginning: %" PRId64, seekTimeUs); mCluster = pSegment->GetFirst(); mBlockEntryIndex = 0; do { @@ -329,7 +331,7 @@ void BlockIterator::seek( return; } - ALOGV("Seeking to: %lld", seekTimeUs); + ALOGV("Seeking to: %" PRId64, seekTimeUs); // If the Cues have not been located then find them. const mkvparser::Cues* pCues = pSegment->GetCues(); @@ -378,7 +380,7 @@ void BlockIterator::seek( for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) { pTrack = pTracks->GetTrackByIndex(index); if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK - ALOGV("Video track located at %d", index); + ALOGV("Video track located at %zu", index); break; } } @@ -409,7 +411,7 @@ void BlockIterator::seek( if (isAudio || block()->IsKey()) { // Accept the first key frame *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL; - ALOGV("Requested seek point: %lld actual: %lld", + ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64, seekTimeUs, *actualFrameTimeUs); break; } diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index d039f7d..d1afd8b 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -36,6 +36,8 @@ #include <media/IStreamSource.h> #include <utils/KeyedVector.h> +#include <inttypes.h> + namespace android { // I want the expression "y" evaluated even if verbose logging is off. @@ -586,7 +588,7 @@ status_t ATSParser::Stream::parse( // Increment in multiples of 64K. neededSize = (neededSize + 65535) & ~65535; - ALOGI("resizing buffer to %d bytes", neededSize); + ALOGI("resizing buffer to %zu bytes", neededSize); sp<ABuffer> newBuffer = new ABuffer(neededSize); memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size()); @@ -748,7 +750,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { PTS |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - ALOGV("PTS = 0x%016llx (%.2f)", PTS, PTS / 90000.0); + ALOGV("PTS = 0x%016" PRIx64 " (%.2f)", PTS, PTS / 90000.0); optional_bytes_remaining -= 5; @@ -764,7 +766,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { DTS |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - ALOGV("DTS = %llu", DTS); + ALOGV("DTS = %" PRIu64, DTS); optional_bytes_remaining -= 5; } @@ -782,7 +784,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { ESCR |= br->getBits(15); CHECK_EQ(br->getBits(1), 1u); - ALOGV("ESCR = %llu", ESCR); + ALOGV("ESCR = %" PRIu64, ESCR); MY_LOGV("ESCR_extension = %u", br->getBits(9)); CHECK_EQ(br->getBits(1), 1u); @@ -812,7 +814,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { if (br->numBitsLeft() < dataLength * 8) { ALOGE("PES packet does not carry enough data to contain " - "payload. (numBitsLeft = %d, required = %d)", + "payload. (numBitsLeft = %zu, required = %u)", br->numBitsLeft(), dataLength * 8); return ERROR_MALFORMED; @@ -832,7 +834,7 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { size_t payloadSizeBits = br->numBitsLeft(); CHECK_EQ(payloadSizeBits % 8, 0u); - ALOGV("There's %d bytes of payload.", payloadSizeBits / 8); + ALOGV("There's %zu bytes of payload.", payloadSizeBits / 8); } } else if (stream_id == 0xbe) { // padding_stream CHECK_NE(PES_packet_length, 0u); @@ -850,7 +852,7 @@ status_t ATSParser::Stream::flush() { return OK; } - ALOGV("flushing stream 0x%04x size = %d", mElementaryPID, mBuffer->size()); + ALOGV("flushing stream 0x%04x size = %zu", mElementaryPID, mBuffer->size()); ABitReader br(mBuffer->data(), mBuffer->size()); @@ -1172,7 +1174,7 @@ void ATSParser::parseAdaptationField(ABitReader *br, unsigned PID) { uint64_t PCR = PCR_base * 300 + PCR_ext; - ALOGV("PID 0x%04x: PCR = 0x%016llx (%.2f)", + ALOGV("PID 0x%04x: PCR = 0x%016" PRIx64 " (%.2f)", PID, PCR, PCR / 27E6); // The number of bytes received by this parser up to and @@ -1268,7 +1270,7 @@ bool ATSParser::PTSTimeDeltaEstablished() { void ATSParser::updatePCR( unsigned /* PID */, uint64_t PCR, size_t byteOffsetFromStart) { - ALOGV("PCR 0x%016llx @ %d", PCR, byteOffsetFromStart); + ALOGV("PCR 0x%016" PRIx64 " @ %zu", PCR, byteOffsetFromStart); if (mNumPCRs == 2) { mPCR[0] = mPCR[1]; diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index d4e30b4..86b025f 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -71,8 +71,9 @@ struct ATSParser : public RefBase { void signalEOS(status_t finalResult); enum SourceType { - VIDEO, - AUDIO + VIDEO = 0, + AUDIO = 1, + NUM_SOURCE_TYPES = 2 }; sp<MediaSource> getSource(SourceType type); diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index 6dfaa94..021b640 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -26,6 +26,8 @@ #include <media/stagefright/MetaData.h> #include <utils/Vector.h> +#include <inttypes.h> + namespace android { const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs @@ -186,7 +188,7 @@ void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { int64_t lastQueuedTimeUs; CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs)); mLastQueuedTimeUs = lastQueuedTimeUs; - ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6); + ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6); Mutex::Autolock autoLock(mLock); mBuffers.push_back(buffer); diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index c0c9717..f7abf01 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -31,6 +31,7 @@ #include "include/avc_utils.h" +#include <inttypes.h> #include <netinet/in.h> namespace android { @@ -264,7 +265,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an H.264/MPEG syncword " - "at offset %d", + "at offset %zd", startOffset); } @@ -297,7 +298,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an H.264/MPEG syncword " - "at offset %d", + "at offset %zd", startOffset); } @@ -330,7 +331,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an AAC syncword at " - "offset %d", + "offset %zd", startOffset); } @@ -358,7 +359,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an AC3 syncword at " - "offset %d", + "offset %zd", startOffset); } @@ -385,7 +386,7 @@ status_t ElementaryStreamQueue::appendData( if (startOffset > 0) { ALOGI("found something resembling an MPEG audio " - "syncword at offset %d", + "syncword at offset %zd", startOffset); } @@ -409,7 +410,7 @@ status_t ElementaryStreamQueue::appendData( if (mBuffer == NULL || neededSize > mBuffer->capacity()) { neededSize = (neededSize + 65535) & ~65535; - ALOGV("resizing buffer to size %d", neededSize); + ALOGV("resizing buffer to size %zu", neededSize); sp<ABuffer> buffer = new ABuffer(neededSize); if (mBuffer != NULL) { @@ -432,7 +433,7 @@ status_t ElementaryStreamQueue::appendData( #if 0 if (mMode == AAC) { - ALOGI("size = %d, timeUs = %.2f secs", size, timeUs / 1E6); + ALOGI("size = %zu, timeUs = %.2f secs", size, timeUs / 1E6); hexdump(data, size); } #endif @@ -1027,7 +1028,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() { accessUnit->meta()->setInt64("timeUs", timeUs); - ALOGV("returning MPEG video access unit at time %lld us", + ALOGV("returning MPEG video access unit at time %" PRId64 " us", timeUs); // hexdump(accessUnit->data(), accessUnit->size()); @@ -1186,7 +1187,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() { accessUnit->meta()->setInt64("timeUs", timeUs); - ALOGV("returning MPEG4 video access unit at time %lld us", + ALOGV("returning MPEG4 video access unit at time %" PRId64 " us", timeUs); // hexdump(accessUnit->data(), accessUnit->size()); diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp index bc2a16d..85859f7 100644 --- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp @@ -36,6 +36,8 @@ #include <media/stagefright/Utils.h> #include <utils/String8.h> +#include <inttypes.h> + namespace android { struct MPEG2PSExtractor::Track : public MediaSource { @@ -409,7 +411,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { PTS |= br.getBits(15); CHECK_EQ(br.getBits(1), 1u); - ALOGV("PTS = %llu", PTS); + ALOGV("PTS = %" PRIu64, PTS); // ALOGI("PTS = %.2f secs", PTS / 90000.0f); optional_bytes_remaining -= 5; @@ -426,7 +428,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { DTS |= br.getBits(15); CHECK_EQ(br.getBits(1), 1u); - ALOGV("DTS = %llu", DTS); + ALOGV("DTS = %" PRIu64, DTS); optional_bytes_remaining -= 5; } @@ -444,7 +446,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { ESCR |= br.getBits(15); CHECK_EQ(br.getBits(1), 1u); - ALOGV("ESCR = %llu", ESCR); + ALOGV("ESCR = %" PRIu64, ESCR); /* unsigned ESCR_extension = */br.getBits(9); CHECK_EQ(br.getBits(1), 1u); @@ -473,7 +475,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { if (br.numBitsLeft() < dataLength * 8) { ALOGE("PES packet does not carry enough data to contain " - "payload. (numBitsLeft = %d, required = %d)", + "payload. (numBitsLeft = %zu, required = %u)", br.numBitsLeft(), dataLength * 8); return ERROR_MALFORMED; diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk index 8b79af4..447b29e 100644 --- a/media/libstagefright/omx/tests/Android.mk +++ b/media/libstagefright/omx/tests/Android.mk @@ -17,4 +17,6 @@ LOCAL_MODULE := omx_tests LOCAL_MODULE_TAGS := tests +LOCAL_32_BIT_ONLY := true + include $(BUILD_EXECUTABLE) diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp index a6825eb..4bc67e8 100644 --- a/media/libstagefright/rtsp/AAVCAssembler.cpp +++ b/media/libstagefright/rtsp/AAVCAssembler.cpp @@ -124,7 +124,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addNALUnit( } void AAVCAssembler::addSingleNALUnit(const sp<ABuffer> &buffer) { - ALOGV("addSingleNALUnit of size %d", buffer->size()); + ALOGV("addSingleNALUnit of size %zu", buffer->size()); #if !LOG_NDEBUG hexdump(buffer->data(), buffer->size()); #endif @@ -191,7 +191,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( CHECK((indicator & 0x1f) == 28); if (size < 2) { - ALOGV("Ignoring malformed FU buffer (size = %d)", size); + ALOGV("Ignoring malformed FU buffer (size = %zu)", size); queue->erase(queue->begin()); ++mNextExpectedSeqNo; @@ -225,7 +225,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( } else { List<sp<ABuffer> >::iterator it = ++queue->begin(); while (it != queue->end()) { - ALOGV("sequence length %d", totalCount); + ALOGV("sequence length %zu", totalCount); const sp<ABuffer> &buffer = *it; @@ -294,7 +294,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( for (size_t i = 0; i < totalCount; ++i) { const sp<ABuffer> &buffer = *it; - ALOGV("piece #%d/%d", i + 1, totalCount); + ALOGV("piece #%zu/%zu", i + 1, totalCount); #if !LOG_NDEBUG hexdump(buffer->data(), buffer->size()); #endif @@ -317,7 +317,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( void AAVCAssembler::submitAccessUnit() { CHECK(!mNALUnits.empty()); - ALOGV("Access unit complete (%d nal units)", mNALUnits.size()); + ALOGV("Access unit complete (%zu nal units)", mNALUnits.size()); size_t totalSize = 0; for (List<sp<ABuffer> >::iterator it = mNALUnits.begin(); diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp index eefceba..98b50dd 100644 --- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -365,7 +365,7 @@ ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( void AMPEG4ElementaryAssembler::submitAccessUnit() { CHECK(!mPackets.empty()); - ALOGV("Access unit complete (%d nal units)", mPackets.size()); + ALOGV("Access unit complete (%zu nal units)", mPackets.size()); sp<ABuffer> accessUnit; diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp index af369b5..372fbe9 100644 --- a/media/libstagefright/rtsp/ARTPConnection.cpp +++ b/media/libstagefright/rtsp/ARTPConnection.cpp @@ -563,7 +563,7 @@ status_t ARTPConnection::parseRTCP(StreamInfo *s, const sp<ABuffer> &buffer) { default: { - ALOGW("Unknown RTCP packet type %u of size %d", + ALOGW("Unknown RTCP packet type %u of size %zu", (unsigned)data[1], headerLength); break; } diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp index c46d16f..793d116 100644 --- a/media/libstagefright/rtsp/ARTPWriter.cpp +++ b/media/libstagefright/rtsp/ARTPWriter.cpp @@ -277,7 +277,7 @@ void ARTPWriter::onRead(const sp<AMessage> &msg) { } if (mediaBuf->range_length() > 0) { - ALOGV("read buffer of size %d", mediaBuf->range_length()); + ALOGV("read buffer of size %zu", mediaBuf->range_length()); if (mMode == H264) { StripStartcode(mediaBuf); diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 16549ff..f3dfc59 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -488,21 +488,32 @@ struct MyHandler : public AHandler { sp<ARTSPResponse> response = static_cast<ARTSPResponse *>(obj.get()); - if (response->mStatusCode == 302) { + if (response->mStatusCode == 301 || response->mStatusCode == 302) { ssize_t i = response->mHeaders.indexOfKey("location"); CHECK_GE(i, 0); - mSessionURL = response->mHeaders.valueAt(i); - - AString request; - request = "DESCRIBE "; - request.append(mSessionURL); - request.append(" RTSP/1.0\r\n"); - request.append("Accept: application/sdp\r\n"); - request.append("\r\n"); + mOriginalSessionURL = response->mHeaders.valueAt(i); + mSessionURL = mOriginalSessionURL; + + // Strip any authentication info from the session url, we don't + // want to transmit user/pass in cleartext. + AString host, path, user, pass; + unsigned port; + if (ARTSPConnection::ParseURL( + mSessionURL.c_str(), &host, &port, &path, &user, &pass) + && user.size() > 0) { + mSessionURL.clear(); + mSessionURL.append("rtsp://"); + mSessionURL.append(host); + mSessionURL.append(":"); + mSessionURL.append(StringPrintf("%u", port)); + mSessionURL.append(path); + + ALOGI("rewritten session url: '%s'", mSessionURL.c_str()); + } - sp<AMessage> reply = new AMessage('desc', id()); - mConn->sendRequest(request.c_str(), reply); + sp<AMessage> reply = new AMessage('conn', id()); + mConn->connect(mOriginalSessionURL.c_str(), reply); break; } diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp index 13e8da3..09f7eee 100644 --- a/media/libstagefright/rtsp/SDPLoader.cpp +++ b/media/libstagefright/rtsp/SDPLoader.cpp @@ -125,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 = %d", readSize); + ALOGE("Failed to read SDP, error code = %zu", readSize); err = UNKNOWN_ERROR; } else { desc = new ASessionDescription; diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk index 06ce16b..903af49 100644 --- a/media/libstagefright/tests/Android.mk +++ b/media/libstagefright/tests/Android.mk @@ -41,6 +41,8 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/include \ $(TOP)/frameworks/native/include/media/openmax \ +LOCAL_32_BIT_ONLY := true + include $(BUILD_EXECUTABLE) endif diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp index 9fb0afe..a070487 100644 --- a/media/libstagefright/timedtext/TimedTextPlayer.cpp +++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "TimedTextPlayer" #include <utils/Log.h> +#include <inttypes.h> #include <limits.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> @@ -271,7 +272,7 @@ int64_t TimedTextPlayer::delayUsFromCurrentTime(int64_t fireTimeUs) { sp<MediaPlayerBase> listener = mListener.promote(); if (listener == NULL) { // TODO: it may be better to return kInvalidTimeUs - ALOGE("%s: Listener is NULL. (fireTimeUs = %lld)", + ALOGE("%s: Listener is NULL. (fireTimeUs = %" PRId64" )", __FUNCTION__, fireTimeUs); return 0; } diff --git a/media/libstagefright/webm/WebmElement.cpp b/media/libstagefright/webm/WebmElement.cpp index c978966..a008cab 100644 --- a/media/libstagefright/webm/WebmElement.cpp +++ b/media/libstagefright/webm/WebmElement.cpp @@ -119,7 +119,7 @@ int WebmElement::write(int fd, uint64_t& size) { off64_t mapSize = curOff - alignedOff; off64_t pageOff = off - alignedOff; void *dst = ::mmap64(NULL, mapSize, PROT_WRITE, MAP_SHARED, fd, alignedOff); - if ((int) dst == -1) { + if (dst == MAP_FAILED) { ALOGE("mmap64 failed; errno = %d", errno); ALOGE("fd %d; flags: %o", fd, ::fcntl(fd, F_GETFL, 0)); return errno; diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp index 5addd3c..a4b8a42 100644 --- a/media/libstagefright/webm/WebmFrameThread.cpp +++ b/media/libstagefright/webm/WebmFrameThread.cpp @@ -48,7 +48,7 @@ status_t WebmFrameThread::start() { status_t WebmFrameThread::stop() { void *status; pthread_join(mThread, &status); - return (status_t) status; + return (status_t)(intptr_t)status; } //================================================================================================= diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index f848054..d3e546a 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libaudioflinger \ + libaudiopolicy \ libcamera_metadata\ libcameraservice \ libmedialogservice \ @@ -33,8 +34,10 @@ LOCAL_C_INCLUDES := \ frameworks/av/media/libmediaplayerservice \ frameworks/av/services/medialog \ frameworks/av/services/audioflinger \ + frameworks/av/services/audiopolicy \ frameworks/av/services/camera/libcameraservice LOCAL_MODULE:= mediaserver +LOCAL_32_BIT_ONLY := true include $(BUILD_EXECUTABLE) diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp index 3838ce8..c500901 100644 --- a/media/mtp/MtpProperty.cpp +++ b/media/mtp/MtpProperty.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "MtpProperty" #include <inttypes.h> +#include <cutils/compiler.h> #include "MtpDataPacket.h" #include "MtpDebug.h" #include "MtpProperty.h" @@ -518,8 +519,14 @@ void MtpProperty::writeValue(MtpDataPacket& packet, MtpPropertyValue& value) { MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, int& length) { length = packet.getUInt32(); - if (length == 0) + // Fail if resulting array is over 2GB. This is because the maximum array + // size may be less than SIZE_MAX on some platforms. + if ( CC_UNLIKELY( + length == 0 || + length >= INT32_MAX / sizeof(MtpPropertyValue)) ) { + length = 0; return NULL; + } MtpPropertyValue* result = new MtpPropertyValue[length]; for (int i = 0; i < length; i++) readValue(packet, result[i]); |