diff options
45 files changed, 890 insertions, 406 deletions
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index af091f4..99e5df4 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -16,6 +16,7 @@ */ #define LOG_TAG "CameraParams" +// #define LOG_NDEBUG 0 #include <utils/Log.h> #include <string.h> @@ -198,6 +199,8 @@ String8 CameraParameters::flatten() const flattened += ";"; } + ALOGV("%s: Flattened params = %s", __FUNCTION__, flattened.string()); + return flattened; } @@ -247,7 +250,9 @@ void CameraParameters::set(const char *key, const char *value) return; } - mMap.replaceValueFor(String8(key), String8(value)); + // Replacing a value updates the key's order to be the new largest order + ssize_t res = mMap.replaceValueFor(String8(key), String8(value)); + LOG_ALWAYS_FATAL_IF(res < 0, "replaceValueFor(%s,%s) failed", key, value); } void CameraParameters::set(const char *key, int value) @@ -266,10 +271,12 @@ void CameraParameters::setFloat(const char *key, float value) const char *CameraParameters::get(const char *key) const { - String8 v = mMap.valueFor(String8(key)); - if (v.length() == 0) - return 0; - return v.string(); + ssize_t idx = mMap.indexOfKey(String8(key)); + if (idx < 0) { + return NULL; + } else { + return mMap.valueAt(idx).string(); + } } int CameraParameters::getInt(const char *key) const @@ -287,6 +294,36 @@ float CameraParameters::getFloat(const char *key) const return strtof(v, 0); } +status_t CameraParameters::compareSetOrder(const char *key1, const char *key2, + int *order) const { + if (key1 == NULL) { + ALOGE("%s: key1 must not be NULL", __FUNCTION__); + return BAD_VALUE; + } else if (key2 == NULL) { + ALOGE("%s: key2 must not be NULL", __FUNCTION__); + return BAD_VALUE; + } else if (order == NULL) { + ALOGE("%s: order must not be NULL", __FUNCTION__); + return BAD_VALUE; + } + + ssize_t index1 = mMap.indexOfKey(String8(key1)); + ssize_t index2 = mMap.indexOfKey(String8(key2)); + if (index1 < 0) { + ALOGW("%s: Key1 (%s) was not set", __FUNCTION__, key1); + return NAME_NOT_FOUND; + } else if (index2 < 0) { + ALOGW("%s: Key2 (%s) was not set", __FUNCTION__, key2); + return NAME_NOT_FOUND; + } + + *order = (index1 == index2) ? 0 : + (index1 < index2) ? -1 : + 1; + + return OK; +} + void CameraParameters::remove(const char *key) { mMap.removeItem(String8(key)); @@ -412,6 +449,12 @@ void CameraParameters::getPreviewFpsRange(int *min_fps, int *max_fps) const parse_pair(p, min_fps, max_fps, ','); } +void CameraParameters::setPreviewFpsRange(int min_fps, int max_fps) +{ + String8 str = String8::format("%d,%d", min_fps, max_fps); + set(KEY_PREVIEW_FPS_RANGE, str.string()); +} + void CameraParameters::setPreviewFormat(const char *format) { set(KEY_PREVIEW_FORMAT, format); diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index d521543..833ba76 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -18,6 +18,7 @@ #define ANDROID_HARDWARE_CAMERA_PARAMETERS_H #include <utils/KeyedVector.h> +#include <utils/Vector.h> #include <utils/String8.h> namespace android { @@ -50,10 +51,26 @@ public: void set(const char *key, const char *value); void set(const char *key, int value); void setFloat(const char *key, float value); + // Look up string value by key. + // -- The string remains valid until the next set/remove of the same key, + // or until the map gets cleared. const char *get(const char *key) const; int getInt(const char *key) const; float getFloat(const char *key) const; + // Compare the order that key1 was set vs the order that key2 was set. + // + // Sets the order parameter to an integer less than, equal to, or greater + // than zero if key1's set order was respectively, to be less than, to + // match, or to be greater than key2's set order. + // + // Error codes: + // * NAME_NOT_FOUND - if either key has not been set previously + // * BAD_VALUE - if any of the parameters are NULL + status_t compareSetOrder(const char *key1, const char *key2, + /*out*/ + int *order) const; + void remove(const char *key); void setPreviewSize(int width, int height); @@ -91,6 +108,7 @@ public: void setPreviewFrameRate(int fps); int getPreviewFrameRate() const; void getPreviewFpsRange(int *min_fps, int *max_fps) const; + void setPreviewFpsRange(int min_fps, int max_fps); void setPreviewFormat(const char *format); const char *getPreviewFormat() const; void setPictureSize(int width, int height); @@ -675,7 +693,91 @@ public: static const char LIGHTFX_HDR[]; private: - DefaultKeyedVector<String8,String8> mMap; + + // Quick and dirty map that maintains insertion order + template <typename KeyT, typename ValueT> + struct OrderedKeyedVector { + + ssize_t add(const KeyT& key, const ValueT& value) { + return mList.add(Pair(key, value)); + } + + size_t size() const { + return mList.size(); + } + + const KeyT& keyAt(size_t idx) const { + return mList[idx].mKey; + } + + const ValueT& valueAt(size_t idx) const { + return mList[idx].mValue; + } + + const ValueT& valueFor(const KeyT& key) const { + ssize_t i = indexOfKey(key); + LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__); + + return valueAt(i); + } + + ssize_t indexOfKey(const KeyT& key) const { + size_t vectorIdx = 0; + for (; vectorIdx < mList.size(); ++vectorIdx) { + if (mList[vectorIdx].mKey == key) { + return (ssize_t) vectorIdx; + } + } + + return NAME_NOT_FOUND; + } + + ssize_t removeItem(const KeyT& key) { + size_t vectorIdx = (size_t) indexOfKey(key); + + if (vectorIdx < 0) { + return vectorIdx; + } + + return mList.removeAt(vectorIdx); + } + + void clear() { + mList.clear(); + } + + // Same as removing and re-adding. The key's index changes to max. + ssize_t replaceValueFor(const KeyT& key, const ValueT& value) { + removeItem(key); + return add(key, value); + } + + private: + + struct Pair { + Pair() : mKey(), mValue() {} + Pair(const KeyT& key, const ValueT& value) : + mKey(key), + mValue(value) {} + KeyT mKey; + ValueT mValue; + }; + + Vector<Pair> mList; + }; + + /** + * Order matters: Keys that are set() later are stored later in the map. + * + * If two keys have meaning that conflict, then the later-set key + * wins. + * + * For example, preview FPS and preview FPS range conflict since only + * we only want to use the FPS range if that's the last thing that was set. + * So in that case, only use preview FPS range if it was set later than + * the preview FPS. + */ + OrderedKeyedVector<String8,String8> mMap; }; }; // namespace android diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h index f8e4e3b..3ca3095 100644 --- a/include/media/mediaplayer.h +++ b/include/media/mediaplayer.h @@ -223,6 +223,7 @@ public: status_t getDuration(int *msec); status_t reset(); status_t setAudioStreamType(audio_stream_type_t type); + status_t getAudioStreamType(audio_stream_type_t *type); status_t setLooping(int loop); bool isLooping(); status_t setVolume(float leftVolume, float rightVolume); diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h index 590623b..01a5daf 100644 --- a/include/media/stagefright/MediaCodecList.h +++ b/include/media/stagefright/MediaCodecList.h @@ -60,6 +60,7 @@ private: SECTION_DECODER, SECTION_ENCODERS, SECTION_ENCODER, + SECTION_INCLUDE, }; struct CodecInfo { @@ -73,7 +74,9 @@ private: status_t mInitCheck; Section mCurrentSection; + Vector<Section> mPastSections; int32_t mDepth; + AString mHrefBase; Vector<CodecInfo> mCodecInfos; KeyedVector<AString, size_t> mCodecQuirks; @@ -83,7 +86,8 @@ private: ~MediaCodecList(); status_t initCheck() const; - void parseXMLFile(FILE *file); + void parseXMLFile(const char *path); + void parseTopLevelXMLFile(const char *path); static void StartElementHandlerWrapper( void *me, const char *name, const char **attrs); @@ -93,6 +97,7 @@ private: void startElementHandler(const char *name, const char **attrs); void endElementHandler(const char *name); + status_t includeXMLFile(const char **attrs); status_t addMediaCodecFromAttributes(bool encoder, const char **attrs); void addMediaCodec(bool encoder, const char *name, const char *type = NULL); diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk index 77a21ac..8318d28 100755 --- a/libvideoeditor/lvpp/Android.mk +++ b/libvideoeditor/lvpp/Android.mk @@ -46,7 +46,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_SHARED_LIBRARIES := \ - libaudioflinger \ + libaudioresampler \ libaudioutils \ libbinder \ libcutils \ @@ -80,7 +80,6 @@ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/av/services/audioflinger \ $(TOP)/frameworks/native/include/media/editor \ $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/native/services/audioflinger LOCAL_SHARED_LIBRARIES += libdl @@ -99,8 +98,6 @@ LOCAL_CFLAGS += -Wno-multichar \ -DUSE_STAGEFRIGHT_READERS \ -DUSE_STAGEFRIGHT_3GPP_READER -LOCAL_32_BIT_ONLY := true - include $(BUILD_SHARED_LIBRARY) #include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libvideoeditor/vss/src/Android.mk b/libvideoeditor/vss/src/Android.mk index 8856c41..47627ec 100755 --- a/libvideoeditor/vss/src/Android.mk +++ b/libvideoeditor/vss/src/Android.mk @@ -53,7 +53,7 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE_TAGS := optional LOCAL_SHARED_LIBRARIES := \ - libaudioflinger \ + libaudioresampler \ libaudioutils \ libbinder \ libcutils \ @@ -81,7 +81,6 @@ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/av/libvideoeditor/vss/stagefrightshells/inc \ $(TOP)/frameworks/av/services/audioflinger \ $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/native/services/audioflinger \ $(TOP)/system/media/audio_effects/include \ $(TOP)/system/media/audio_utils/include @@ -96,6 +95,4 @@ LOCAL_CFLAGS += -Wno-multichar \ -DM4xVSS_RESERVED_MOOV_DISK_SPACEno \ -DDECODE_GIF_ON_SAVING -LOCAL_32_BIT_ONLY := true - include $(BUILD_SHARED_LIBRARY) diff --git a/libvideoeditor/vss/src/VideoEditorResampler.cpp b/libvideoeditor/vss/src/VideoEditorResampler.cpp index 1129c3c..53537f0 100755 --- a/libvideoeditor/vss/src/VideoEditorResampler.cpp +++ b/libvideoeditor/vss/src/VideoEditorResampler.cpp @@ -17,7 +17,7 @@ #define LOG_NDEBUG 1 #include <audio_utils/primitives.h> #include <utils/Log.h> -#include "AudioMixer.h" +#include "AudioResampler.h" #include "VideoEditorResampler.h" namespace android { diff --git a/libvideoeditor/vss/stagefrightshells/src/Android.mk b/libvideoeditor/vss/stagefrightshells/src/Android.mk index a060c0d..9188942 100755 --- a/libvideoeditor/vss/stagefrightshells/src/Android.mk +++ b/libvideoeditor/vss/stagefrightshells/src/Android.mk @@ -64,6 +64,4 @@ LOCAL_MODULE:= libvideoeditor_stagefrightshells LOCAL_MODULE_TAGS := optional -LOCAL_32_BIT_ONLY := true - include $(BUILD_STATIC_LIBRARY) diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp index eb091ac..5a3bf9d 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,7 +171,7 @@ 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") || @@ -137,15 +180,20 @@ void CharacterEncodingDetector::detectAndConvert() { // 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/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/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index e9e96d1..9164e5c 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -644,8 +644,8 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( // FIXME: assume that surface is controlled by app (native window // returns the number for the case when surface is not controlled by app) - (*minUndequeuedBuffers)++; - + // 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 // @@ -653,7 +653,8 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( // minimum needed for the consumer to be able to work // 2. try to allocate two (2) additional buffers to reduce starvation from // the consumer - for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) { + // 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; diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index a9b0c73..714b5e0 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -118,8 +118,6 @@ LOCAL_MODULE:= libstagefright LOCAL_MODULE_TAGS := optional -LOCAL_32_BIT_ONLY := true - include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH)) 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 545ca9d..1cfe6c0 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1806,7 +1806,8 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { } // FIXME: assume that surface is controlled by app (native window // returns the number for the case when surface is not controlled by app) - minUndequeuedBufs++; + // 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 // @@ -1814,10 +1815,11 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { // minimum needed for the consumer to be able to work // 2. try to allocate two (2) additional buffers to reduce starvation from // the consumer - CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d", + // 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; /* condition inside loop */; extraBuffers--) { + for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) { OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs + extraBuffers; def.nBufferCountActual = newBufferCount; @@ -1836,7 +1838,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { return err; } } - CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d", + CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1", def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs); err = native_window_set_buffer_count( diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk index 04dc487..58ec3ba 100644 --- a/media/libstagefright/codecs/aacenc/Android.mk +++ b/media/libstagefright/codecs/aacenc/Android.mk @@ -117,7 +117,6 @@ ifeq ($(AAC_LIBRARY), fraunhofer) LOCAL_MODULE := libstagefright_soft_aacenc LOCAL_MODULE_TAGS := optional - LOCAL_32_BIT_ONLY := true include $(BUILD_SHARED_LIBRARY) diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk index c2e7b81..537ba42 100644 --- a/media/libstagefright/codecs/avc/enc/Android.mk +++ b/media/libstagefright/codecs/avc/enc/Android.mk @@ -20,7 +20,6 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := libstagefright_avcenc -LOCAL_32_BIT_ONLY := true LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/src \ @@ -71,7 +70,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := libstagefright_soft_h264enc LOCAL_MODULE_TAGS := optional -LOCAL_32_BIT_ONLY := true LOCAL_CFLAGS += -Werror diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp index 40661e7..0c62ec0 100644 --- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp +++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp @@ -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; } @@ -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; } diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp index 2c73e57..ee8dcf2 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> @@ -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); 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/Android.mk b/media/libstagefright/httplive/Android.mk index 9c1994a..e8d558c 100644 --- a/media/libstagefright/httplive/Android.mk +++ b/media/libstagefright/httplive/Android.mk @@ -30,6 +30,4 @@ ifeq ($(TARGET_ARCH),arm) LOCAL_CFLAGS += -Wno-psabi endif -LOCAL_32_BIT_ONLY := true - include $(BUILD_SHARED_LIBRARY) 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/Android.mk b/media/libstagefright/id3/Android.mk index bbe807e..2194c38 100644 --- a/media/libstagefright/id3/Android.mk +++ b/media/libstagefright/id3/Android.mk @@ -29,6 +29,4 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE := testid3 -LOCAL_32_BIT_ONLY := true - include $(BUILD_EXECUTABLE) 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/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/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/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/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk index d27a8ff..f70454a 100644 --- a/media/libstagefright/wifi-display/Android.mk +++ b/media/libstagefright/wifi-display/Android.mk @@ -34,6 +34,4 @@ LOCAL_MODULE:= libstagefright_wfd LOCAL_MODULE_TAGS:= optional -LOCAL_32_BIT_ONLY := true - include $(BUILD_SHARED_LIBRARY) diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index de7e3c3..6cb0299 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -29,10 +29,6 @@ LOCAL_SRC_FILES:= \ Tracks.cpp \ Effects.cpp \ AudioMixer.cpp.arm \ - AudioResampler.cpp.arm \ - AudioResamplerCubic.cpp.arm \ - AudioResamplerSinc.cpp.arm \ - AudioResamplerDyn.cpp.arm LOCAL_SRC_FILES += StateQueue.cpp @@ -42,6 +38,7 @@ LOCAL_C_INCLUDES := \ $(call include-path-for, audio-utils) LOCAL_SHARED_LIBRARIES := \ + libaudioresampler \ libaudioutils \ libcommon_time_client \ libcutils \ @@ -53,7 +50,6 @@ LOCAL_SHARED_LIBRARIES := \ libhardware \ libhardware_legacy \ libeffects \ - libdl \ libpowermanager LOCAL_STATIC_LIBRARIES := \ @@ -87,10 +83,6 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ test-resample.cpp \ - AudioResampler.cpp.arm \ - AudioResamplerCubic.cpp.arm \ - AudioResamplerSinc.cpp.arm \ - AudioResamplerDyn.cpp.arm LOCAL_C_INCLUDES := \ $(call include-path-for, audio-utils) @@ -99,6 +91,7 @@ LOCAL_STATIC_LIBRARIES := \ libsndfile LOCAL_SHARED_LIBRARIES := \ + libaudioresampler \ libaudioutils \ libdl \ libcutils \ @@ -111,4 +104,21 @@ LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + AudioResampler.cpp.arm \ + AudioResamplerCubic.cpp.arm \ + AudioResamplerSinc.cpp.arm \ + AudioResamplerDyn.cpp.arm + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libdl \ + liblog + +LOCAL_MODULE := libaudioresampler + +include $(BUILD_SHARED_LIBRARY) + include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index 2cf0d29..75ec426 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "Camera2-Parameters" #define ATRACE_TAG ATRACE_TAG_CAMERA -//#define LOG_NDEBUG 0 +// #define LOG_NDEBUG 0 #include <utils/Log.h> #include <utils/Trace.h> @@ -92,26 +92,6 @@ status_t Parameters::initialize(const CameraMetadata *info) { staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2); if (!availableFpsRanges.count) return NO_INIT; - previewFpsRange[0] = availableFpsRanges.data.i32[0]; - previewFpsRange[1] = availableFpsRanges.data.i32[1]; - - params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, - String8::format("%d,%d", - previewFpsRange[0] * kFpsToApiScale, - previewFpsRange[1] * kFpsToApiScale)); - - { - String8 supportedPreviewFpsRange; - for (size_t i=0; i < availableFpsRanges.count; i += 2) { - if (i != 0) supportedPreviewFpsRange += ","; - supportedPreviewFpsRange += String8::format("(%d,%d)", - availableFpsRanges.data.i32[i] * kFpsToApiScale, - availableFpsRanges.data.i32[i+1] * kFpsToApiScale); - } - params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, - supportedPreviewFpsRange); - } - previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; params.set(CameraParameters::KEY_PREVIEW_FORMAT, formatEnumToString(previewFormat)); // NV21 @@ -179,6 +159,9 @@ status_t Parameters::initialize(const CameraMetadata *info) { supportedPreviewFormats); } + previewFpsRange[0] = availableFpsRanges.data.i32[0]; + previewFpsRange[1] = availableFpsRanges.data.i32[1]; + // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but // still have to do something sane for them @@ -187,6 +170,27 @@ status_t Parameters::initialize(const CameraMetadata *info) { params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE, previewFps); + // PREVIEW_FPS_RANGE + // -- Order matters. Set range after single value to so that a roundtrip + // of setParameters(getParameters()) would keep the FPS range in higher + // order. + params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE, + String8::format("%d,%d", + previewFpsRange[0] * kFpsToApiScale, + previewFpsRange[1] * kFpsToApiScale)); + + { + String8 supportedPreviewFpsRange; + for (size_t i=0; i < availableFpsRanges.count; i += 2) { + if (i != 0) supportedPreviewFpsRange += ","; + supportedPreviewFpsRange += String8::format("(%d,%d)", + availableFpsRanges.data.i32[i] * kFpsToApiScale, + availableFpsRanges.data.i32[i+1] * kFpsToApiScale); + } + params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, + supportedPreviewFpsRange); + } + { SortedVector<int32_t> sortedPreviewFrameRates; @@ -1127,29 +1131,72 @@ status_t Parameters::set(const String8& paramString) { // RECORDING_HINT (always supported) validatedParams.recordingHint = boolFromString( newParams.get(CameraParameters::KEY_RECORDING_HINT) ); - bool recordingHintChanged = validatedParams.recordingHint != recordingHint; - ALOGV_IF(recordingHintChanged, "%s: Recording hint changed to %d", - __FUNCTION__, recordingHintChanged); + IF_ALOGV() { // Avoid unused variable warning + bool recordingHintChanged = + validatedParams.recordingHint != recordingHint; + if (recordingHintChanged) { + ALOGV("%s: Recording hint changed to %d", + __FUNCTION__, validatedParams.recordingHint); + } + } // PREVIEW_FPS_RANGE - bool fpsRangeChanged = false; - int32_t lastSetFpsRange[2]; - params.getPreviewFpsRange(&lastSetFpsRange[0], &lastSetFpsRange[1]); - lastSetFpsRange[0] /= kFpsToApiScale; - lastSetFpsRange[1] /= kFpsToApiScale; + /** + * Use the single FPS value if it was set later than the range. + * Otherwise, use the range value. + */ + bool fpsUseSingleValue; + { + const char *fpsRange, *fpsSingle; + + fpsRange = params.get(CameraParameters::KEY_PREVIEW_FRAME_RATE); + fpsSingle = params.get(CameraParameters::KEY_PREVIEW_FPS_RANGE); + /** + * Pick either the range or the single key if only one was set. + * + * If both are set, pick the one that has greater set order. + */ + if (fpsRange == NULL && fpsSingle == NULL) { + ALOGE("%s: FPS was not set. One of %s or %s must be set.", + __FUNCTION__, CameraParameters::KEY_PREVIEW_FRAME_RATE, + CameraParameters::KEY_PREVIEW_FPS_RANGE); + return BAD_VALUE; + } else if (fpsRange == NULL) { + fpsUseSingleValue = true; + ALOGV("%s: FPS range not set, using FPS single value", + __FUNCTION__); + } else if (fpsSingle == NULL) { + fpsUseSingleValue = false; + ALOGV("%s: FPS single not set, using FPS range value", + __FUNCTION__); + } else { + int fpsKeyOrder; + res = params.compareSetOrder( + CameraParameters::KEY_PREVIEW_FRAME_RATE, + CameraParameters::KEY_PREVIEW_FPS_RANGE, + &fpsKeyOrder); + LOG_ALWAYS_FATAL_IF(res != OK, "Impossibly bad FPS keys"); + + fpsUseSingleValue = (fpsKeyOrder > 0); + + } + + ALOGV("%s: Preview FPS value is used from '%s'", + __FUNCTION__, fpsUseSingleValue ? "single" : "range"); + } newParams.getPreviewFpsRange(&validatedParams.previewFpsRange[0], &validatedParams.previewFpsRange[1]); validatedParams.previewFpsRange[0] /= kFpsToApiScale; validatedParams.previewFpsRange[1] /= kFpsToApiScale; - // Compare the FPS range value from the last set() to the current set() - // to determine if the client has changed it - if (validatedParams.previewFpsRange[0] != lastSetFpsRange[0] || - validatedParams.previewFpsRange[1] != lastSetFpsRange[1]) { + // Ignore the FPS range if the FPS single has higher precedence + if (!fpsUseSingleValue) { + ALOGV("%s: Preview FPS range (%d, %d)", __FUNCTION__, + validatedParams.previewFpsRange[0], + validatedParams.previewFpsRange[1]); - fpsRangeChanged = true; camera_metadata_ro_entry_t availablePreviewFpsRanges = staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2); for (i = 0; i < availablePreviewFpsRanges.count; i += 2) { @@ -1200,14 +1247,13 @@ status_t Parameters::set(const String8& paramString) { } } - // PREVIEW_FRAME_RATE Deprecated, only use if the preview fps range is - // unchanged this time. The single-value FPS is the same as the minimum of - // the range. To detect whether the application has changed the value of - // previewFps, compare against their last-set preview FPS. - if (!fpsRangeChanged) { + // PREVIEW_FRAME_RATE Deprecated + // - Use only if the single FPS value was set later than the FPS range + if (fpsUseSingleValue) { int previewFps = newParams.getPreviewFrameRate(); - int lastSetPreviewFps = params.getPreviewFrameRate(); - if (previewFps != lastSetPreviewFps || recordingHintChanged) { + ALOGV("%s: Preview FPS single value requested: %d", + __FUNCTION__, previewFps); + { camera_metadata_ro_entry_t availableFrameRates = staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES); /** @@ -1276,6 +1322,35 @@ status_t Parameters::set(const String8& paramString) { } } + /** + * Update Preview FPS and Preview FPS ranges based on + * what we actually set. + * + * This updates the API-visible (Camera.Parameters#getParameters) values of + * the FPS fields, not only the internal versions. + * + * Order matters: The value that was set last takes precedence. + * - If the client does a setParameters(getParameters()) we retain + * the same order for preview FPS. + */ + if (!fpsUseSingleValue) { + // Set fps single, then fps range (range wins) + validatedParams.params.setPreviewFrameRate( + fpsFromRange(/*min*/validatedParams.previewFpsRange[0], + /*max*/validatedParams.previewFpsRange[1])); + validatedParams.params.setPreviewFpsRange( + validatedParams.previewFpsRange[0], + validatedParams.previewFpsRange[1]); + } else { + // Set fps range, then fps single (single wins) + validatedParams.params.setPreviewFpsRange( + validatedParams.previewFpsRange[0], + validatedParams.previewFpsRange[1]); + validatedParams.params.setPreviewFrameRate( + fpsFromRange(/*min*/validatedParams.previewFpsRange[0], + /*max*/validatedParams.previewFpsRange[1])); + } + // PICTURE_SIZE newParams.getPictureSize(&validatedParams.pictureWidth, &validatedParams.pictureHeight); |