Merge "Removing widevine classic"
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index 77b9a33..7c37955 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -51,8 +51,13 @@
ACaptureRequest* req, const ACameraOutputTarget* target) {
ATRACE_CALL();
if (req == nullptr || req->targets == nullptr || target == nullptr) {
+ void* req_targets;
+ if (req != nullptr)
+ req_targets = req->targets;
+ else
+ req_targets = nullptr;
ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
- __FUNCTION__, req, req->targets, target);
+ __FUNCTION__, req, req_targets, target);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
auto pair = req->targets->mOutputs.insert(*target);
@@ -67,8 +72,13 @@
ACaptureRequest* req, const ACameraOutputTarget* target) {
ATRACE_CALL();
if (req == nullptr || req->targets == nullptr || target == nullptr) {
+ void* req_targets;
+ if (req != nullptr)
+ req_targets = req->targets;
+ else
+ req_targets = nullptr;
ALOGE("%s: Error: invalid input: req %p, req-targets %p, target %p",
- __FUNCTION__, req, req->targets, target);
+ __FUNCTION__, req, req_targets, target);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
req->targets->mOutputs.erase(*target);
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 8fe1dd4..76dbb78 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -230,7 +230,8 @@
mCodec->signalResume();
(new AMessage(kWhatSeek, this))->post(5000000ll);
- } else if (what == CodecBase::kWhatShutdownCompleted) {
+ } else if (what == CodecBase::kWhatStopCompleted ||
+ what == CodecBase::kWhatReleaseCompleted) {
mDecodeLooper->unregisterHandler(mCodec->id());
if (mDecodeLooper != looper()) {
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index edcca64..99ef59f 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -23,6 +23,8 @@
#include <utils/KeyedVector.h>
#include <system/audio.h>
+#include <media/IMediaSource.h>
+
// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
// global, and not in android::
struct sockaddr_in;
@@ -38,6 +40,8 @@
struct AudioPlaybackRate;
struct AVSyncSettings;
+typedef IMediaSource::ReadOptions::SeekMode MediaPlayerSeekMode;
+
class IMediaPlayer: public IInterface
{
public:
@@ -65,14 +69,9 @@
virtual status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) = 0;
virtual status_t getSyncSettings(AVSyncSettings* sync /* nonnull */,
float* videoFps /* nonnull */) = 0;
- // When |precise| is true, it's required that the first rendered media position after seekTo
- // is precisely at |msec|, up to rounding error of granuality, e.g., video frame interval or
- // audio length of decoding buffer. In this case, it might take a little long time to finish
- // seekTo.
- // When |precise| is false, |msec| is a hint to the mediaplayer which will try its best to
- // fulfill the request, but it's not guaranteed. This option could result in fast finish of
- // seekTo.
- virtual status_t seekTo(int msec, bool precise = false) = 0;
+ virtual status_t seekTo(
+ int msec,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) = 0;
virtual status_t getCurrentPosition(int* msec) = 0;
virtual status_t getDuration(int* msec) = 0;
virtual status_t reset() = 0;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index b488159..4e4878a 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -205,7 +205,8 @@
*videoFps = -1.f;
return OK;
}
- virtual status_t seekTo(int msec, bool precise = false) = 0;
+ virtual status_t seekTo(
+ int msec, MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) = 0;
virtual status_t getCurrentPosition(int *msec) = 0;
virtual status_t getDuration(int *msec) = 0;
virtual status_t reset() = 0;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index c556f0a..be34d02 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -233,7 +233,9 @@
float* videoFps /* nonnull */);
status_t getVideoWidth(int *w);
status_t getVideoHeight(int *h);
- status_t seekTo(int msec, bool precise = false);
+ status_t seekTo(
+ int msec,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
status_t getCurrentPosition(int *msec);
status_t getDuration(int *msec);
status_t reset();
@@ -257,7 +259,7 @@
private:
void clear_l();
- status_t seekTo_l(int msec, bool precise);
+ status_t seekTo_l(int msec, MediaPlayerSeekMode mode);
status_t prepareAsync_l();
status_t getDuration_l(int *msec);
status_t attachNewPlayer(const sp<IMediaPlayer>& player);
@@ -274,9 +276,9 @@
void* mCookie;
media_player_states mCurrentState;
int mCurrentPosition;
- bool mCurrentSeekPrecise;
+ MediaPlayerSeekMode mCurrentSeekMode;
int mSeekPosition;
- int mSeekPrecise;
+ MediaPlayerSeekMode mSeekMode;
bool mPrepareSync;
status_t mPrepareStatus;
audio_stream_type_t mStreamType;
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index d8c43a4..39a9089 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -43,7 +43,8 @@
kWhatFillThisBuffer = 'fill',
kWhatDrainThisBuffer = 'drai',
kWhatEOS = 'eos ',
- kWhatShutdownCompleted = 'scom',
+ kWhatStopCompleted = 'scom',
+ kWhatReleaseCompleted = 'rcom',
kWhatFlushCompleted = 'fcom',
kWhatError = 'erro',
kWhatComponentAllocated = 'cAll',
diff --git a/include/media/stagefright/foundation/Flagged.h b/include/media/stagefright/foundation/Flagged.h
new file mode 100644
index 0000000..bf0afbf
--- /dev/null
+++ b/include/media/stagefright/foundation/Flagged.h
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_FOUNDATION_FLAGGED_H_
+#define STAGEFRIGHT_FOUNDATION_FLAGGED_H_
+
+#include <media/stagefright/foundation/TypeTraits.h>
+
+namespace android {
+
+/**
+ * Flagged<T, Flag> is basically a specialized std::pair<Flag, T> that automatically optimizes out
+ * the flag if the wrapped type T is already flagged and we can combine the outer and inner flags.
+ *
+ * Flags can be queried/manipulated via flags() an setFlags(Flags). The wrapped value can be
+ * accessed via get(). This template is meant to be inherited by other utility/wrapper classes
+ * that need to store integral information along with the value.
+ *
+ * Users must specify the used bits (MASK) in the flags. Flag getters and setters will enforce this
+ * mask. _Flagged_helper::minMask<Flag> is provided to easily calculate a mask for a max value.
+ *
+ * E.g. adding a safe flag can be achieved like this:
+ *
+ *
+ * enum SafeFlags : uint32_t {
+ * kUnsafe,
+ * kSafe,
+ * kSafeMask = _Flagged_helper::minMask(kSafe),
+ * };
+ * typedef Flagged<int32_t, SafeFlags, kSafeMask> safeInt32;
+ *
+ * safeInt32 a;
+ * a.setFlags(kSafe);
+ * a.get() = 15;
+ * EXPECT_EQ(a.flags(), kSafe);
+ * EXPECT_EQ(a.get(), 15);
+ *
+ *
+ * Flagged also supports lazy or calculated wrapping of already flagged types. Lazy wrapping is
+ * provided automatically (flags are automatically shared if possible, e.g. mask is shifted
+ * automatically to not overlap with used bits of the wrapped type's flags, and fall back to
+ * unshared version of the template.):
+ *
+ * enum OriginFlags : uint32_t {
+ * kUnknown,
+ * kConst,
+ * kCalculated,
+ * kComponent,
+ * kApplication,
+ * kFile,
+ * kBinder,
+ * kOriginMask = _Flagged_helper::minMask(kBinder),
+ * };
+ * typedef Flagged<safeInt32, OriginFlags, kOriginMask>
+ * trackedSafeInt32;
+ *
+ * static_assert(sizeof(trackedSafeInt32) == sizeof(safeInt32), "");
+ *
+ * trackedSafeInt32 b(kConst, kSafe, 1);
+ * EXPECT_EQ(b.flags(), kConst);
+ * EXPECT_EQ(b.get().flags(), kSafe);
+ * EXPECT_EQ(b.get().get(), 1);
+ * b.setFlags(kCalculated);
+ * b.get().setFlags(overflow ? kUnsafe : kSafe);
+ *
+ * One can also choose to share some flag-bits with the wrapped class:
+ *
+ * enum ValidatedFlags : uint32_t {
+ * kUnsafeV = kUnsafe,
+ * kSafeV = kSafe,
+ * kValidated = kSafe | 2,
+ * kSharedMaskV = kSafeMask,
+ * kValidatedMask = _Flagged_helper::minMask(kValidated),
+ * };
+ * typedef Flagged<safeInt32, ValidatedFlags, kValidatedMask, kSharedMaskV> validatedInt32;
+ *
+ * validatedInt32 v(kUnsafeV, kSafe, 10);
+ * EXPECT_EQ(v.flags(), kUnsafeV);
+ * EXPECT_EQ(v.get().flags(), kUnsafe); // !kUnsafeV overrides kSafe
+ * EXPECT_EQ(v.get().get(), 10);
+ * v.setFlags(kValidated);
+ * EXPECT_EQ(v.flags(), kValidated);
+ * EXPECT_EQ(v.get().flags(), kSafe);
+ * v.get().setFlags(kUnsafe);
+ * EXPECT_EQ(v.flags(), 2); // NOTE: sharing masks with enums allows strange situations to occur
+ */
+
+/**
+ * Helper class for Flagged support. Encapsulates common utilities used by all
+ * templated classes.
+ */
+struct _Flagged_helper {
+ /**
+ * Calculates the value with a given number of top-most bits set.
+ *
+ * This method may be called with a signed flag.
+ *
+ * \param num number of bits to set. This must be between 0 and the number of bits in Flag.
+ *
+ * \return the value where only the given number of top-most bits are set.
+ */
+ template<typename Flag>
+ static constexpr Flag topBits(int num) {
+ return Flag(num > 0 ?
+ ~((Flag(1) << (sizeof(Flag) * 8 - is_signed_integral<Flag>::value - num)) - 1) :
+ 0);
+ }
+
+ /**
+ * Calculates the minimum mask required to cover a value. Used with the maximum enum value for
+ * an unsigned flag.
+ *
+ * \param maxValue maximum value to cover
+ * \param shift DO NO USE. used internally
+ *
+ * \return mask that can be used that covers the maximum value.
+ */
+ template<typename Flag>
+ static constexpr Flag minMask(Flag maxValue, int shift=sizeof(Flag) * 4) {
+ static_assert(is_unsigned_integral<Flag>::value,
+ "this method only makes sense for unsigned flags");
+ return shift ? minMask<Flag>(Flag(maxValue | (maxValue >> shift)), shift >> 1) : maxValue;
+ }
+
+ /**
+ * Returns a value left-shifted by an argument as a potential constexpr.
+ *
+ * This method helps around the C-language limitation, when left-shift of a negative value with
+ * even 0 cannot be a constexpr.
+ *
+ * \param value value to shift
+ * \param shift amount of shift
+ * \returns the shifted value as an integral type
+ */
+ template<typename Flag, typename IntFlag = typename underlying_integral_type<Flag>::type>
+ static constexpr IntFlag lshift(Flag value, int shift) {
+ return shift ? value << shift : value;
+ }
+
+private:
+
+ /**
+ * Determines whether mask can be combined with base-mask for a given left shift.
+ *
+ * \param mask desired mask
+ * \param baseMask mask used by T or 0 if T is not flagged by Flag
+ * \param sharedMask desired shared mask (if this is non-0, this must be mask & baseMask)
+ * \param shift desired left shift to be used for mask
+ * \param baseShift left shift used by T or 0 if T is not flagged by Flag
+ * \param effectiveMask effective mask used by T or 0 if T is not flagged by Flag
+ *
+ * \return bool whether mask can be combined with baseMask using the desired values.
+ */
+ template<typename Flag, typename IntFlag=typename underlying_integral_type<Flag>::type>
+ static constexpr bool canCombine(
+ Flag mask, IntFlag baseMask, Flag sharedMask, int shift,
+ int baseShift, IntFlag effectiveMask) {
+ return
+ // verify that shift is valid and mask can be shifted
+ shift >= 0 && (mask & topBits<Flag>(shift)) == 0 &&
+
+ // verify that base mask is part of effective mask (sanity check on arguments)
+ (baseMask & ~(effectiveMask >> baseShift)) == 0 &&
+
+ // if sharing masks, shift must be the base's shift.
+ // verify that shared mask is the overlap of base mask and mask
+ (sharedMask ?
+ ((sharedMask ^ (baseMask & mask)) == 0 &&
+ shift == baseShift) :
+
+
+ // otherwise, verify that there is no overlap between mask and base's effective mask
+ (mask & (effectiveMask >> shift)) == 0);
+ }
+
+
+ /**
+ * Calculates the minimum (left) shift required to combine a mask with the mask of an
+ * underlying type (T, also flagged by Flag).
+ *
+ * \param mask desired mask
+ * \param baseMask mask used by T or 0 if T is not flagged by Flag
+ * \param sharedMask desired shared mask (if this is non-0, this must be mask & baseMask)
+ * \param baseShift left shift used by T
+ * \param effectiveMask effective mask used by T
+ *
+ * \return a non-negative minimum left shift value if mask can be combined with baseMask,
+ * or -1 if the masks cannot be combined. -2 if the input is invalid.
+ */
+ template<typename Flag,
+ typename IntFlag = typename underlying_integral_type<Flag>::type>
+ static constexpr int getShift(
+ Flag mask, IntFlag baseMask, Flag sharedMask, int baseShift, IntFlag effectiveMask) {
+ return
+ // baseMask must be part of the effective mask
+ (baseMask & ~(effectiveMask >> baseShift)) ? -2 :
+
+ // if sharing masks, shift must be base's shift. verify that shared mask is part of
+ // base mask and mask, and that desired mask still fits with base's shift value
+ sharedMask ?
+ (canCombine(mask, baseMask, sharedMask, baseShift /* shift */,
+ baseShift, effectiveMask) ? baseShift : -1) :
+
+ // otherwise, see if 0-shift works
+ ((mask & effectiveMask) == 0) ? 0 :
+
+ // otherwise, verify that mask can be shifted up
+ ((mask & topBits<Flag>(1)) || (mask < 0)) ? -1 :
+
+ incShift(getShift(Flag(mask << 1), baseMask /* unused */, sharedMask /* 0 */,
+ baseShift /* unused */, effectiveMask));
+ }
+
+ /**
+ * Helper method that increments a non-negative (shift) value.
+ *
+ * This method is used to make it easier to create a constexpr for getShift.
+ *
+ * \param shift (shift) value to increment
+ *
+ * \return original shift if it was negative; otherwise, the shift incremented by one.
+ */
+ static constexpr int incShift(int shift) {
+ return shift + (shift >= 0);
+ }
+
+#ifdef FRIEND_TEST
+ FRIEND_TEST(FlaggedTest, _Flagged_helper_Test);
+#endif
+
+public:
+ /**
+ * Base class for all Flagged<T, Flag> classes.
+ *
+ * \note flagged types do not have a member variable for the mask used by the type. As such,
+ * they should be be cast to this base class.
+ *
+ * \todo can we replace this base class check with a static member check to remove possibility
+ * of cast?
+ */
+ template<typename Flag>
+ struct base {};
+
+ /**
+ * Type support utility that retrieves the mask of a class (T) if it is a type flagged by
+ * Flag (e.g. Flagged<T, Flag>).
+ *
+ * \note This retrieves 0 if T is a flagged class, that is not flagged by Flag or an equivalent
+ * underlying type.
+ *
+ * Generic implementation for a non-flagged class.
+ */
+ template<
+ typename T, typename Flag,
+ bool=std::is_base_of<base<typename underlying_integral_type<Flag>::type>, T>::value>
+ struct mask_of {
+ using IntFlag = typename underlying_integral_type<Flag>::type;
+ static constexpr IntFlag value = Flag(0); ///< mask of a potentially flagged class
+ static constexpr int shift = 0; ///<left shift of flags in a potentially flagged class
+ static constexpr IntFlag effective_value = IntFlag(0); ///<effective mask of flagged class
+ };
+
+ /**
+ * Type support utility that calculates the minimum (left) shift required to combine a mask
+ * with the mask of an underlying type T also flagged by Flag.
+ *
+ * \note if T is not flagged, not flagged by Flag, or the masks cannot be combined due to
+ * incorrect sharing or the flags not having enough bits, the minimum is -1.
+ *
+ * \param MASK desired mask
+ * \param SHARED_MASK desired shared mask (if this is non-0, T must be an type flagged by
+ * Flag with a mask that has exactly these bits common with MASK)
+ */
+ template<typename T, typename Flag, Flag MASK, Flag SHARED_MASK>
+ struct min_shift {
+ /// minimum (left) shift required, or -1 if masks cannot be combined
+ static constexpr int value =
+ getShift(MASK, mask_of<T, Flag>::value, SHARED_MASK,
+ mask_of<T, Flag>::shift, mask_of<T, Flag>::effective_value);
+ };
+
+ /**
+ * Type support utility that calculates whether the flags of T can be combined with MASK.
+ *
+ * \param MASK desired mask
+ * \param SHARED_MASK desired shared mask (if this is non-0, T MUST be an type flagged by
+ * Flag with a mask that has exactly these bits common with MASK)
+ */
+ template<
+ typename T, typename Flag, Flag MASK,
+ Flag SHARED_MASK=Flag(0),
+ int SHIFT=min_shift<T, Flag, MASK, SHARED_MASK>::value>
+ struct can_combine {
+ using IntFlag = typename underlying_integral_type<Flag>::type;
+ /// true if this mask can be combined with T's existing flag. false otherwise.
+ static constexpr bool value =
+ std::is_base_of<base<IntFlag>, T>::value
+ && canCombine(MASK, mask_of<T, Flag>::value, SHARED_MASK, SHIFT,
+ mask_of<T, Flag>::shift, mask_of<T, Flag>::effective_value);
+ };
+};
+
+/**
+ * Template specialization for the case when T is flagged by Flag or a compatible type.
+ */
+template<typename T, typename Flag>
+struct _Flagged_helper::mask_of<T, Flag, true> {
+ using IntType = typename underlying_integral_type<Flag>::type;
+ static constexpr IntType value = T::sFlagMask;
+ static constexpr int shift = T::sFlagShift;
+ static constexpr IntType effective_value = T::sEffectiveMask;
+};
+
+/**
+ * Main Flagged template that adds flags to an object of another type (in essence, creates a pair)
+ *
+ * Flag must be an integral type (enums are allowed).
+ *
+ * \note We could make SHARED_MASK be a boolean as it must be either 0 or MASK & base's mask, but we
+ * want it to be spelled out for safety.
+ *
+ * \param T type of object wrapped
+ * \param Flag type of flag
+ * \param MASK mask for the bits used in flag (before any shift)
+ * \param SHARED_MASK optional mask to be shared with T (if this is not zero, SHIFT must be 0, and
+ * it must equal to MASK & T's mask)
+ * \param SHIFT optional left shift for MASK to combine with T's mask (or -1, if masks should not
+ * be combined.)
+ */
+template<
+ typename T, typename Flag, Flag MASK, Flag SHARED_MASK=(Flag)0,
+ int SHIFT=_Flagged_helper::min_shift<T, Flag, MASK, SHARED_MASK>::value,
+ typename IntFlag=typename underlying_integral_type<Flag>::type,
+ bool=_Flagged_helper::can_combine<T, IntFlag, MASK, SHARED_MASK, SHIFT>::value>
+class Flagged : public _Flagged_helper::base<IntFlag> {
+ static_assert(SHARED_MASK == 0,
+ "shared mask can only be used with common flag types "
+ "and must be part of mask and mask of base type");
+ static_assert((_Flagged_helper::topBits<Flag>(SHIFT) & MASK) == 0, "SHIFT overflows MASK");
+
+ static constexpr Flag sFlagMask = MASK; ///< the mask
+ static constexpr int sFlagShift = SHIFT > 0 ? SHIFT : 0; ///< the left shift applied to flags
+
+ friend struct _Flagged_helper;
+#ifdef FRIEND_TEST
+ static constexpr bool sFlagCombined = false;
+ FRIEND_TEST(FlaggedTest, _Flagged_helper_Test);
+#endif
+
+ T mValue; ///< wrapped value
+ IntFlag mFlags; ///< flags
+
+protected:
+ /// The effective combined mask used by this class and any wrapped classes if the flags are
+ /// combined.
+ static constexpr IntFlag sEffectiveMask = _Flagged_helper::lshift(MASK, sFlagShift);
+
+ /**
+ * Helper method used by subsequent flagged wrappers to query flags. Returns the
+ * flags for a particular mask and left shift.
+ *
+ * \param mask bitmask to use
+ * \param shift left shifts to use
+ *
+ * \return the requested flags
+ */
+ inline constexpr IntFlag getFlagsHelper(IntFlag mask, int shift) const {
+ return (mFlags >> shift) & mask;
+ }
+
+ /**
+ * Helper method used by subsequent flagged wrappers to apply combined flags. Sets the flags
+ * in the bitmask using a particulare left shift.
+ *
+ * \param mask bitmask to use
+ * \param shift left shifts to use
+ * \param flags flags to update (any flags within the bitmask are updated to their value in this
+ * argument)
+ */
+ inline void setFlagsHelper(IntFlag mask, int shift, IntFlag flags) {
+ mFlags = Flag((mFlags & ~(mask << shift)) | ((flags & mask) << shift));
+ }
+
+public:
+ /**
+ * Wrapper around base class constructor. These take the flags as their first
+ * argument and pass the rest of the arguments to the base class constructor.
+ *
+ * \param flags initial flags
+ */
+ template<typename ...Args>
+ constexpr Flagged(Flag flags, Args... args)
+ : mValue(std::forward<Args>(args)...),
+ mFlags(Flag(_Flagged_helper::lshift(flags & sFlagMask, sFlagShift))) { }
+
+ /** Gets the wrapped value as const. */
+ inline constexpr const T &get() const { return mValue; }
+
+ /** Gets the wrapped value. */
+ inline T &get() { return mValue; }
+
+ /** Gets the flags. */
+ constexpr Flag flags() const {
+ return Flag(getFlagsHelper(sFlagMask, sFlagShift));
+ }
+
+ /** Sets the flags. */
+ void setFlags(Flag flags) {
+ setFlagsHelper(sFlagMask, sFlagShift, flags);
+ }
+};
+
+/*
+ * TRICKY: we cannot implement the specialization as:
+ *
+ * class Flagged : base<Flag> {
+ * T value;
+ * };
+ *
+ * Because T also inherits from base<Flag> and this runs into a compiler bug where
+ * sizeof(Flagged) > sizeof(T).
+ *
+ * Instead, we must inherit directly from the wrapped class
+ *
+ */
+#if 0
+template<
+ typename T, typename Flag, Flag MASK, Flag SHARED_MASK, int SHIFT>
+class Flagged<T, Flag, MASK, SHARED_MASK, SHIFT, true> : public _Flagged_helper::base<Flag> {
+private:
+ T mValue;
+};
+#else
+/**
+ * Specialization for the case when T is derived from Flagged<U, Flag> and flags can be combined.
+ */
+template<
+ typename T, typename Flag, Flag MASK, Flag SHARED_MASK, int SHIFT, typename IntFlag>
+class Flagged<T, Flag, MASK, SHARED_MASK, SHIFT, IntFlag, true> : private T {
+ static_assert(is_integral_or_enum<Flag>::value, "flag must be integer or enum");
+
+ static_assert(SHARED_MASK == 0 || SHIFT == 0, "cannot overlap masks when using SHIFT");
+ static_assert((SHARED_MASK & ~MASK) == 0, "shared mask must be part of the mask");
+ static_assert((SHARED_MASK & ~T::sEffectiveMask) == 0,
+ "shared mask must be part of the base mask");
+ static_assert(SHARED_MASK == 0 || (~SHARED_MASK & (MASK & T::sEffectiveMask)) == 0,
+ "mask and base mask can only overlap in shared mask");
+
+ static constexpr Flag sFlagMask = MASK; ///< the mask
+ static constexpr int sFlagShift = SHIFT; ///< the left shift applied to the flags
+
+#ifdef FRIEND_TEST
+ const static bool sFlagCombined = true;
+ FRIEND_TEST(FlaggedTest, _Flagged_helper_Test);
+#endif
+
+protected:
+ /// The effective combined mask used by this class and any wrapped classes if the flags are
+ /// combined.
+ static constexpr IntFlag sEffectiveMask = Flag((MASK << SHIFT) | T::sEffectiveMask);
+ friend struct _Flagged_helper;
+
+public:
+ /**
+ * Wrapper around base class constructor. These take the flags as their first
+ * argument and pass the rest of the arguments to the base class constructor.
+ *
+ * \param flags initial flags
+ */
+ template<typename ...Args>
+ constexpr Flagged(Flag flags, Args... args)
+ : T(std::forward<Args>(args)...) {
+ // we construct the base class first and apply the flags afterwards as
+ // base class may not have a constructor that takes flags even if it is derived from
+ // Flagged<U, Flag>
+ setFlags(flags);
+ }
+
+ /** Gets the wrapped value as const. */
+ inline constexpr T &get() const { return *this; }
+
+ /** Gets the wrapped value. */
+ inline T &get() { return *this; }
+
+ /** Gets the flags. */
+ Flag constexpr flags() const {
+ return Flag(this->getFlagsHelper(sFlagMask, sFlagShift));
+ }
+
+ /** Sets the flags. */
+ void setFlags(Flag flags) {
+ this->setFlagsHelper(sFlagMask, sFlagShift, flags);
+ }
+};
+#endif
+
+} // namespace android
+
+#endif // STAGEFRIGHT_FOUNDATION_FLAGGED_H_
+
diff --git a/include/media/stagefright/foundation/TypeTraits.h b/include/media/stagefright/foundation/TypeTraits.h
new file mode 100644
index 0000000..2eaec35
--- /dev/null
+++ b/include/media/stagefright/foundation/TypeTraits.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
+#define STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
+
+#include <type_traits>
+
+namespace android {
+
+/**
+ * std::is_signed, is_unsigned and is_integral does not consider enums even though the standard
+ * considers them integral. Create modified versions of these here. Also create a wrapper around
+ * std::underlying_type that does not require checking if the type is an enum.
+ */
+
+/**
+ * Type support utility class to check if a type is an integral type or an enum.
+ */
+template<typename T>
+struct is_integral_or_enum
+ : std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value> { };
+
+/**
+ * Type support utility class to get the underlying std::is_integral supported type for a type.
+ * This returns the underlying type for enums, and the same type for types covered by
+ * std::is_integral.
+ *
+ * This is also used as a conditional to return an alternate type if the template param is not
+ * an integral or enum type (as in underlying_integral_type<T, TypeIfNotEnumOrIntegral>::type).
+ */
+template<typename T,
+ typename U=typename std::enable_if<is_integral_or_enum<T>::value>::type,
+ bool=std::is_enum<T>::value,
+ bool=std::is_integral<T>::value>
+struct underlying_integral_type {
+ static_assert(!std::is_enum<T>::value, "T should not be enum here");
+ static_assert(!std::is_integral<T>::value, "T should not be integral here");
+ typedef U type;
+};
+
+/** Specialization for enums. */
+template<typename T, typename U>
+struct underlying_integral_type<T, U, true, false> {
+ static_assert(std::is_enum<T>::value, "T should be enum here");
+ static_assert(!std::is_integral<T>::value, "T should not be integral here");
+ typedef typename std::underlying_type<T>::type type;
+};
+
+/** Specialization for non-enum std-integral types. */
+template<typename T, typename U>
+struct underlying_integral_type<T, U, false, true> {
+ static_assert(!std::is_enum<T>::value, "T should not be enum here");
+ static_assert(std::is_integral<T>::value, "T should be integral here");
+ typedef T type;
+};
+
+/**
+ * Type support utility class to check if the underlying integral type is signed.
+ */
+template<typename T>
+struct is_signed_integral
+ : std::integral_constant<bool, std::is_signed<
+ typename underlying_integral_type<T, unsigned>::type>::value> { };
+
+/**
+ * Type support utility class to check if the underlying integral type is unsigned.
+ */
+template<typename T>
+struct is_unsigned_integral
+ : std::integral_constant<bool, std::is_unsigned<
+ typename underlying_integral_type<T, signed>::type>::value> {
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_FOUNDATION_TYPE_TRAITS_H_
+
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 243e302..a3d6761 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -340,8 +340,10 @@
}
delete pContext;
}
- *pHandle = (effect_handle_t)NULL;
+ if (pHandle != NULL)
+ *pHandle = (effect_handle_t)NULL;
} else {
+ if (pHandle != NULL)
*pHandle = (effect_handle_t)pContext;
}
ALOGV("\tEffectCreate end..\n\n");
@@ -2669,8 +2671,8 @@
case VOLUME_PARAM_ENABLESTEREOPOSITION:
positionEnabled = *(uint32_t *)pValue;
- status = VolumeEnableStereoPosition(pContext, positionEnabled);
- status = VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
+ (void) VolumeEnableStereoPosition(pContext, positionEnabled);
+ (void) VolumeSetStereoPosition(pContext, pContext->pBundledContext->positionSaved);
//ALOGV("\tVolume_setParameter() VOLUME_PARAM_ENABLESTEREOPOSITION called");
break;
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 41b6988..dda2570 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -246,12 +246,12 @@
return reply.readInt32();
}
- status_t seekTo(int msec, bool precise)
+ status_t seekTo(int msec, MediaPlayerSeekMode mode)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
data.writeInt32(msec);
- data.writeBool(precise);
+ data.writeInt32(mode);
remote()->transact(SEEK_TO, data, &reply);
return reply.readInt32();
}
@@ -575,8 +575,8 @@
case SEEK_TO: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
int msec = data.readInt32();
- bool precise = data.readBool();
- reply->writeInt32(seekTo(msec, precise));
+ MediaPlayerSeekMode mode = (MediaPlayerSeekMode)data.readInt32();
+ reply->writeInt32(seekTo(msec, mode));
return NO_ERROR;
} break;
case GET_CURRENT_POSITION: {
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 846a24c..699172b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -55,9 +55,9 @@
mStreamType = AUDIO_STREAM_MUSIC;
mAudioAttributesParcel = NULL;
mCurrentPosition = -1;
- mCurrentSeekPrecise = false;
+ mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
mSeekPosition = -1;
- mSeekPrecise = false;
+ mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
mCurrentState = MEDIA_PLAYER_IDLE;
mPrepareSync = false;
mPrepareStatus = NO_ERROR;
@@ -102,9 +102,9 @@
void MediaPlayer::clear_l()
{
mCurrentPosition = -1;
- mCurrentSeekPrecise = false;
+ mCurrentSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
mSeekPosition = -1;
- mSeekPrecise = false;
+ mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
mVideoWidth = mVideoHeight = 0;
mRetransmitEndpointValid = false;
}
@@ -512,9 +512,9 @@
return getDuration_l(msec);
}
-status_t MediaPlayer::seekTo_l(int msec, bool precise)
+status_t MediaPlayer::seekTo_l(int msec, MediaPlayerSeekMode mode)
{
- ALOGV("seekTo (%d, %d)", msec, precise);
+ ALOGV("seekTo (%d, %d)", msec, mode);
if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
if ( msec < 0 ) {
@@ -541,14 +541,14 @@
// cache duration
mCurrentPosition = msec;
- mCurrentSeekPrecise = precise;
+ mCurrentSeekMode = mode;
if (mSeekPosition < 0) {
mSeekPosition = msec;
- mSeekPrecise = precise;
- return mPlayer->seekTo(msec, precise);
+ mSeekMode = mode;
+ return mPlayer->seekTo(msec, mode);
}
else {
- ALOGV("Seek in progress - queue up seekTo[%d, %d]", msec, precise);
+ ALOGV("Seek in progress - queue up seekTo[%d, %d]", msec, mode);
return NO_ERROR;
}
}
@@ -557,11 +557,11 @@
return INVALID_OPERATION;
}
-status_t MediaPlayer::seekTo(int msec, bool precise)
+status_t MediaPlayer::seekTo(int msec, MediaPlayerSeekMode mode)
{
mLockThreadId = getThreadId();
Mutex::Autolock _l(mLock);
- status_t result = seekTo_l(msec, precise);
+ status_t result = seekTo_l(msec, mode);
mLockThreadId = 0;
return result;
@@ -875,16 +875,16 @@
break;
case MEDIA_SEEK_COMPLETE:
ALOGV("Received seek complete");
- if (mSeekPosition != mCurrentPosition || (!mSeekPrecise && mCurrentSeekPrecise)) {
- ALOGV("Executing queued seekTo(%d, %d)", mCurrentPosition, mCurrentSeekPrecise);
+ if (mSeekPosition != mCurrentPosition || (mSeekMode != mCurrentSeekMode)) {
+ ALOGV("Executing queued seekTo(%d, %d)", mCurrentPosition, mCurrentSeekMode);
mSeekPosition = -1;
- mSeekPrecise = false;
- seekTo_l(mCurrentPosition, mCurrentSeekPrecise);
+ mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
+ seekTo_l(mCurrentPosition, mCurrentSeekMode);
}
else {
ALOGV("All seeks complete - return to regularly scheduled program");
mCurrentPosition = mSeekPosition = -1;
- mCurrentSeekPrecise = mSeekPrecise = false;
+ mCurrentSeekMode = mSeekMode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC;
}
break;
case MEDIA_BUFFERING_UPDATE:
diff --git a/media/libmediaplayerservice/ActivityManager.cpp b/media/libmediaplayerservice/ActivityManager.cpp
index 60a209f..0e6cf7b 100644
--- a/media/libmediaplayerservice/ActivityManager.cpp
+++ b/media/libmediaplayerservice/ActivityManager.cpp
@@ -24,7 +24,7 @@
namespace android {
-const uint32_t OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 4;
+const uint32_t OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION;
// Perform ContentProvider.openFile() on the given URI, returning
// the resulting native file descriptor. Returns < 0 on error.
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3ff9d98..6e163d9 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1121,12 +1121,12 @@
return OK;
}
-status_t MediaPlayerService::Client::seekTo(int msec, bool precise)
+status_t MediaPlayerService::Client::seekTo(int msec, MediaPlayerSeekMode mode)
{
- ALOGV("[%d] seekTo(%d)", mConnId, msec);
+ ALOGV("[%d] seekTo(%d, %d)", mConnId, msec, mode);
sp<MediaPlayerBase> p = getPlayer();
if (p == 0) return UNKNOWN_ERROR;
- return p->seekTo(msec, precise);
+ return p->seekTo(msec, mode);
}
status_t MediaPlayerService::Client::reset()
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index ef82b48..a4ea37f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -298,7 +298,9 @@
virtual status_t setSyncSettings(const AVSyncSettings& rate, float videoFpsHint);
virtual status_t getSyncSettings(AVSyncSettings* rate /* nonnull */,
float* videoFps /* nonnull */);
- virtual status_t seekTo(int msec, bool precise = false);
+ virtual status_t seekTo(
+ int msec,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
virtual status_t getCurrentPosition(int* msec);
virtual status_t getDuration(int* msec);
virtual status_t reset();
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 94ceae4..49c221b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -369,9 +369,13 @@
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.camera"));
- mCameraDeathListener = new ServiceDeathNotifier(binder, listener,
- MediaPlayerService::CAMERA_PROCESS_DEATH);
- binder->linkToDeath(mCameraDeathListener);
+
+ // If the device does not have a camera, do not create a death listener for it.
+ if (binder != NULL) {
+ mCameraDeathListener = new ServiceDeathNotifier(binder, listener,
+ MediaPlayerService::CAMERA_PROCESS_DEATH);
+ binder->linkToDeath(mCameraDeathListener);
+ }
binder = sm->getService(String16("media.codec"));
mCodecDeathListener = new ServiceDeathNotifier(binder, listener,
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
index c0d6a59..11fddf6 100644
--- a/media/libmediaplayerservice/TestPlayerStub.h
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -87,7 +87,11 @@
virtual status_t stop() {return mPlayer->stop();}
virtual status_t pause() {return mPlayer->pause();}
virtual bool isPlaying() {return mPlayer->isPlaying();}
- virtual status_t seekTo(int msec, bool precise = false) {return mPlayer->seekTo(msec, precise);}
+ virtual status_t seekTo(
+ int msec,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) {
+ return mPlayer->seekTo(msec, mode);
+ }
virtual status_t getCurrentPosition(int *p) {
return mPlayer->getCurrentPosition(p);
}
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 846d7a6..cf1f84b 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -608,8 +608,10 @@
} else {
timeUs = mVideoLastDequeueTimeUs;
}
- readBuffer(trackType, timeUs, false /* precise */, &actualTimeUs, formatChange);
- readBuffer(counterpartType, -1, false /* precise */, NULL, !formatChange);
+ readBuffer(trackType, timeUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
+ &actualTimeUs, formatChange);
+ readBuffer(counterpartType, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
+ NULL, !formatChange);
ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs);
break;
@@ -688,7 +690,7 @@
CHECK(msg->findInt64("timeUs", &timeUs));
int64_t subTimeUs;
- readBuffer(type, timeUs, false /* precise */, &subTimeUs);
+ readBuffer(type, timeUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs);
int64_t delayUs = subTimeUs - timeUs;
if (msg->what() == kWhatFetchSubtitleData) {
@@ -719,7 +721,7 @@
}
int64_t nextSubTimeUs;
- readBuffer(type, -1, false /* precise */, &nextSubTimeUs);
+ readBuffer(type, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs);
sp<ABuffer> buffer;
status_t dequeueStatus = packets->dequeueAccessUnit(&buffer);
@@ -1110,10 +1112,10 @@
return INVALID_OPERATION;
}
-status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, bool precise) {
+status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
sp<AMessage> msg = new AMessage(kWhatSeek, this);
msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("precise", precise);
+ msg->setInt32("mode", mode);
sp<AMessage> response;
status_t err = msg->postAndAwaitResponse(&response);
@@ -1126,12 +1128,12 @@
void NuPlayer::GenericSource::onSeek(const sp<AMessage>& msg) {
int64_t seekTimeUs;
- int32_t precise;
+ int32_t mode;
CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("precise", &precise));
+ CHECK(msg->findInt32("mode", &mode));
sp<AMessage> response = new AMessage;
- status_t err = doSeek(seekTimeUs, precise);
+ status_t err = doSeek(seekTimeUs, (MediaPlayerSeekMode)mode);
response->setInt32("err", err);
sp<AReplyToken> replyID;
@@ -1139,7 +1141,7 @@
response->postReply(replyID);
}
-status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, bool precise) {
+status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
mBufferingMonitor->updateDequeuedBufferTime(-1ll);
// If the Widevine source is stopped, do not attempt to read any
@@ -1152,9 +1154,9 @@
}
if (mVideoTrack.mSource != NULL) {
int64_t actualTimeUs;
- readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, precise, &actualTimeUs);
+ readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs);
- if (!precise) {
+ if (mode != MediaPlayerSeekMode::SEEK_CLOSEST) {
seekTimeUs = actualTimeUs;
}
mVideoLastDequeueTimeUs = actualTimeUs;
@@ -1288,7 +1290,7 @@
}
void NuPlayer::GenericSource::readBuffer(
- media_track_type trackType, int64_t seekTimeUs, bool precise,
+ media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode,
int64_t *actualTimeUs, bool formatChange) {
// Do not read data if Widevine source is stopped
//
@@ -1330,7 +1332,7 @@
bool seeking = false;
if (seekTimeUs >= 0) {
- options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+ options.setSeekTo(seekTimeUs, mode);
seeking = true;
}
@@ -1383,7 +1385,8 @@
}
if (seeking && buffer != nullptr) {
sp<AMessage> meta = buffer->meta();
- if (meta != nullptr && precise && seekTimeUs > timeUs) {
+ if (meta != nullptr && mode == MediaPlayerSeekMode::SEEK_CLOSEST
+ && seekTimeUs > timeUs) {
sp<AMessage> extra = new AMessage;
extra->setInt64("resume-at-mediaTimeUs", seekTimeUs);
meta->setMessage("extra", extra);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 7126153..38d8616 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -70,7 +70,9 @@
virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
virtual ssize_t getSelectedTrack(media_track_type type) const;
virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
- virtual status_t seekTo(int64_t seekTimeUs, bool precise = false) override;
+ virtual status_t seekTo(
+ int64_t seekTimeUs,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) override;
virtual status_t setBuffers(bool audio, Vector<MediaBuffer *> &buffers);
@@ -251,7 +253,7 @@
status_t doSelectTrack(size_t trackIndex, bool select, int64_t timeUs);
void onSeek(const sp<AMessage>& msg);
- status_t doSeek(int64_t seekTimeUs, bool precise);
+ status_t doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
void onPrepareAsync();
@@ -273,14 +275,15 @@
void postReadBuffer(media_track_type trackType);
void onReadBuffer(const sp<AMessage>& msg);
- // |precise| is a modifier of |seekTimeUs|.
- // When |precise| is true, the buffer read shall include an item indicating skipping
- // rendering all buffers with timestamp earlier than |seekTimeUs|.
- // When |precise| is false, the buffer read will not include the item as above in order
+ // When |mode| is MediaPlayerSeekMode::SEEK_CLOSEST, the buffer read shall
+ // include an item indicating skipping rendering all buffers with timestamp
+ // earlier than |seekTimeUs|.
+ // For other modes, the buffer read will not include the item as above in order
// to facilitate fast seek operation.
void readBuffer(
media_track_type trackType,
- int64_t seekTimeUs = -1ll, bool precise = false,
+ int64_t seekTimeUs = -1ll,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC,
int64_t *actualTimeUs = NULL, bool formatChange = false);
void queueDiscontinuityIfNeeded(
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 1a6a233..51bfad4 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -214,8 +214,8 @@
return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
}
-status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, bool precise) {
- return mLiveSession->seekTo(seekTimeUs, precise);
+status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
+ return mLiveSession->seekTo(seekTimeUs, mode);
}
void NuPlayer::HTTPLiveSource::pollForRawData(
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 16c3c37..45fc8c1 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -47,7 +47,9 @@
virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
virtual ssize_t getSelectedTrack(media_track_type /* type */) const;
virtual status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
- virtual status_t seekTo(int64_t seekTimeUs, bool precise = false) override;
+ virtual status_t seekTo(
+ int64_t seekTimeUs,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) override;
protected:
virtual ~HTTPLiveSource();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index fb4656f..1476206 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -70,18 +70,18 @@
};
struct NuPlayer::SeekAction : public Action {
- explicit SeekAction(int64_t seekTimeUs, bool precise)
+ explicit SeekAction(int64_t seekTimeUs, MediaPlayerSeekMode mode)
: mSeekTimeUs(seekTimeUs),
- mPrecise(precise) {
+ mMode(mode) {
}
virtual void execute(NuPlayer *player) {
- player->performSeek(mSeekTimeUs, mPrecise);
+ player->performSeek(mSeekTimeUs, mMode);
}
private:
int64_t mSeekTimeUs;
- bool mPrecise;
+ MediaPlayerSeekMode mMode;
DISALLOW_EVIL_CONSTRUCTORS(SeekAction);
};
@@ -419,10 +419,10 @@
(new AMessage(kWhatReset, this))->post();
}
-void NuPlayer::seekToAsync(int64_t seekTimeUs, bool precise, bool needNotify) {
+void NuPlayer::seekToAsync(int64_t seekTimeUs, MediaPlayerSeekMode mode, bool needNotify) {
sp<AMessage> msg = new AMessage(kWhatSeek, this);
msg->setInt64("seekTimeUs", seekTimeUs);
- msg->setInt32("precise", precise);
+ msg->setInt32("mode", mode);
msg->setInt32("needNotify", needNotify);
msg->post();
}
@@ -681,7 +681,8 @@
int64_t currentPositionUs = 0;
if (getCurrentPosition(¤tPositionUs) == OK) {
mDeferredActions.push_back(
- new SeekAction(currentPositionUs, false /* precise */));
+ new SeekAction(currentPositionUs,
+ MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */));
}
}
@@ -1197,14 +1198,14 @@
case kWhatSeek:
{
int64_t seekTimeUs;
- int32_t precise;
+ int32_t mode;
int32_t needNotify;
CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
- CHECK(msg->findInt32("precise", &precise));
+ CHECK(msg->findInt32("mode", &mode));
CHECK(msg->findInt32("needNotify", &needNotify));
- ALOGV("kWhatSeek seekTimeUs=%lld us, precise=%d, needNotify=%d",
- (long long)seekTimeUs, precise, needNotify);
+ ALOGV("kWhatSeek seekTimeUs=%lld us, mode=%d, needNotify=%d",
+ (long long)seekTimeUs, mode, needNotify);
if (!mStarted) {
// Seek before the player is started. In order to preview video,
@@ -1212,7 +1213,7 @@
// only once if needed. After the player is started, any seek
// operation will go through normal path.
// Audio-only cases are handled separately.
- onStart(seekTimeUs, precise);
+ onStart(seekTimeUs, (MediaPlayerSeekMode)mode);
if (mStarted) {
onPause();
mPausedByClient = true;
@@ -1228,7 +1229,7 @@
FLUSH_CMD_FLUSH /* video */));
mDeferredActions.push_back(
- new SeekAction(seekTimeUs, precise));
+ new SeekAction(seekTimeUs, (MediaPlayerSeekMode)mode));
// After a flush without shutdown, decoder is paused.
// Don't resume it until source seek is done, otherwise it could
@@ -1317,13 +1318,13 @@
return OK;
}
-void NuPlayer::onStart(int64_t startPositionUs, bool precise) {
+void NuPlayer::onStart(int64_t startPositionUs, MediaPlayerSeekMode mode) {
if (!mSourceStarted) {
mSourceStarted = true;
mSource->start();
}
if (startPositionUs > 0) {
- performSeek(startPositionUs, precise);
+ performSeek(startPositionUs, mode);
if (mSource->getFormat(false /* audio */) == NULL) {
return;
}
@@ -1539,7 +1540,7 @@
mRenderer->flush(false /* audio */, false /* notifyComplete */);
}
- performSeek(currentPositionUs, false /* precise */);
+ performSeek(currentPositionUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */);
if (forceNonOffload) {
mRenderer->signalDisableOffloadAudio();
@@ -1973,9 +1974,9 @@
}
}
-void NuPlayer::performSeek(int64_t seekTimeUs, bool precise) {
- ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), precise=%d",
- (long long)seekTimeUs, seekTimeUs / 1E6, precise);
+void NuPlayer::performSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
+ ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), mode=%d",
+ (long long)seekTimeUs, seekTimeUs / 1E6, mode);
if (mSource == NULL) {
// This happens when reset occurs right before the loop mode
@@ -1986,7 +1987,7 @@
return;
}
mPreviousSeekTimeUs = seekTimeUs;
- mSource->seekTo(seekTimeUs, precise);
+ mSource->seekTo(seekTimeUs, mode);
++mTimedTextGeneration;
// everything's flushed, continue playback.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 3ae2ada..c8b0102 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -70,7 +70,10 @@
// Will notify the driver through "notifySeekComplete" once finished
// and needNotify is true.
- void seekToAsync(int64_t seekTimeUs, bool precise = false, bool needNotify = false);
+ void seekToAsync(
+ int64_t seekTimeUs,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC,
+ bool needNotify = false);
status_t setVideoScalingMode(int32_t mode);
status_t getTrackInfo(Parcel* reply) const;
@@ -245,7 +248,9 @@
void handleFlushComplete(bool audio, bool isDecoder);
void finishFlushIfPossible();
- void onStart(int64_t startPositionUs = -1, bool precise = false);
+ void onStart(
+ int64_t startPositionUs = -1,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
void onResume();
void onPause();
@@ -263,7 +268,7 @@
void processDeferredActions();
- void performSeek(int64_t seekTimeUs, bool precise);
+ void performSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode);
void performDecoderFlush(FlushCommand audio, FlushCommand video);
void performReset();
void performScanSources();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7f287e3..3efa54c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -208,7 +208,8 @@
mAtEOS = false;
mState = STATE_STOPPED_AND_PREPARING;
mIsAsyncPrepare = false;
- mPlayer->seekToAsync(0, false /* precise */, true /* needNotify */);
+ mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
+ true /* needNotify */);
while (mState == STATE_STOPPED_AND_PREPARING) {
mCondition.wait(mLock);
}
@@ -233,7 +234,8 @@
mAtEOS = false;
mState = STATE_STOPPED_AND_PREPARING;
mIsAsyncPrepare = true;
- mPlayer->seekToAsync(0, false /* precise */, true /* needNotify */);
+ mPlayer->seekToAsync(0, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */,
+ true /* needNotify */);
return OK;
default:
return INVALID_OPERATION;
@@ -382,8 +384,8 @@
return mPlayer->getSyncSettings(sync, videoFps);
}
-status_t NuPlayerDriver::seekTo(int msec, bool precise) {
- ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, precise, mState);
+status_t NuPlayerDriver::seekTo(int msec, MediaPlayerSeekMode mode) {
+ ALOGD("seekTo(%p) (%d ms, %d) at state %d", this, msec, mode, mState);
Mutex::Autolock autoLock(mLock);
int64_t seekTimeUs = msec * 1000ll;
@@ -398,7 +400,7 @@
mSeekInProgress = true;
// seeks can take a while, so we essentially paused
notifyListener_l(MEDIA_PAUSED);
- mPlayer->seekToAsync(seekTimeUs, precise, true /* needNotify */);
+ mPlayer->seekToAsync(seekTimeUs, mode, true /* needNotify */);
break;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 034b3f9..317b34c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -53,7 +53,8 @@
virtual status_t getPlaybackSettings(AudioPlaybackRate *rate);
virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint);
virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps);
- virtual status_t seekTo(int msec, bool precise = false);
+ virtual status_t seekTo(
+ int msec, MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC);
virtual status_t getCurrentPosition(int *msec);
virtual status_t getDuration(int *msec);
virtual status_t reset();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index fe4fc63..5197167 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -104,8 +104,9 @@
return INVALID_OPERATION;
}
- // Refer to comment of seekTo in IMediaPlayer.h for meaning of |precise|.
- virtual status_t seekTo(int64_t /* seekTimeUs */, bool /* precise */ = false) {
+ virtual status_t seekTo(
+ int64_t /* seekTimeUs */,
+ MediaPlayerSeekMode /* mode */ = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) {
return INVALID_OPERATION;
}
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index f430f03..fb1f31a 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -279,11 +279,11 @@
return OK;
}
-status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs, bool precise) {
+status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) {
sp<AMessage> msg = new AMessage(kWhatPerformSeek, this);
msg->setInt32("generation", ++mSeekGeneration);
msg->setInt64("timeUs", seekTimeUs);
- msg->setInt32("precise", precise);
+ msg->setInt32("mode", mode);
sp<AMessage> response;
status_t err = msg->postAndAwaitResponse(&response);
@@ -466,12 +466,12 @@
}
int64_t seekTimeUs;
- int32_t precise;
+ int32_t mode;
CHECK(msg->findInt64("timeUs", &seekTimeUs));
- CHECK(msg->findInt32("precise", &precise));
+ CHECK(msg->findInt32("mode", &mode));
- // TODO: add "precise" to performSeek.
- performSeek(seekTimeUs);
+ // TODO: add "mode" to performSeek.
+ performSeek(seekTimeUs/*, (MediaPlayerSeekMode)mode */);
return;
} else if (msg->what() == kWhatPollBuffering) {
onPollBuffering();
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index b2962ed6..363f8bb 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -49,7 +49,9 @@
virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
virtual status_t getDuration(int64_t *durationUs);
- virtual status_t seekTo(int64_t seekTimeUs, bool precise = false) override;
+ virtual status_t seekTo(
+ int64_t seekTimeUs,
+ MediaPlayerSeekMode mode = MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC) override;
void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cf0a031..21c90f0 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1201,6 +1201,10 @@
info.mDequeuedAt = mDequeueCounter;
info.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));
+
+ // Initialize fence fd to -1 to avoid warning in freeBuffer().
+ ((VideoNativeMetadata *)info.mData->base())->nFenceFd = -1;
+
info.mCodecData = info.mData;
err = mOMXNode->useBuffer(kPortIndexOutput, OMXBuffer::sPreset, &info.mBufferID);
@@ -1836,11 +1840,8 @@
inputFormat->setInt32("adaptive-playback", true);
}
}
- // Fall back to legacy mode (use fixed ANWBuffer)
- err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
- if (err != OK) {
- return err;
- }
+ // allow failure
+ err = OK;
} else {
ALOGV("[%s] setPortMode on output to %s succeeded",
mComponentName.c_str(), asString(IOMX::kPortModeDynamicANWBuffer));
@@ -1873,6 +1874,12 @@
if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) {
usingSwRenderer = true;
haveNativeWindow = false;
+ (void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);
+ } else if (haveNativeWindow && !storingMetadataInDecodedBuffers()) {
+ err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);
+ if (err != OK) {
+ return err;
+ }
}
if (encoder) {
@@ -1887,10 +1894,8 @@
if (haveNativeWindow) {
mNativeWindow = static_cast<Surface *>(obj.get());
- }
- // fallback for devices that do not handle flex-YUV for native buffers
- if (haveNativeWindow) {
+ // fallback for devices that do not handle flex-YUV for native buffers
int32_t requestedColorFormat = OMX_COLOR_FormatUnused;
if (msg->findInt32("color-format", &requestedColorFormat) &&
requestedColorFormat == OMX_COLOR_FormatYUV420Flexible) {
@@ -5258,7 +5263,7 @@
ALOGE_IF("[%s] failed to release codec instance: err=%d",
mCodec->mComponentName.c_str(), err);
sp<AMessage> notify = mCodec->mNotify->dup();
- notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+ notify->setInt32("what", CodecBase::kWhatReleaseCompleted);
notify->post();
break;
}
@@ -6147,7 +6152,8 @@
"cannot keep component allocated on shutdown in Uninitialized state");
sp<AMessage> notify = mCodec->mNotify->dup();
- notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+ notify->setInt32("what", keepComponentAllocated ?
+ CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
notify->post();
handled = true;
@@ -6344,7 +6350,8 @@
if (mCodec->mExplicitShutdown) {
sp<AMessage> notify = mCodec->mNotify->dup();
- notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+ notify->setInt32("what", keepComponentAllocated ?
+ CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
notify->post();
mCodec->mExplicitShutdown = false;
}
@@ -7346,8 +7353,7 @@
case kWhatShutdown:
{
- // We're already doing that...
-
+ mCodec->deferMessage(msg);
handled = true;
break;
}
@@ -7456,8 +7462,7 @@
switch (msg->what()) {
case kWhatShutdown:
{
- // We're already doing that...
-
+ mCodec->deferMessage(msg);
handled = true;
break;
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index f2dfca7..5382689 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1550,19 +1550,26 @@
break;
}
- case CodecBase::kWhatShutdownCompleted:
+ case CodecBase::kWhatStopCompleted:
{
- if (mState == UNINITIALIZED) {
- // Ignore shutdown complete if we're already released.
+ if (mState != STOPPING) {
+ ALOGW("Received kWhatStopCompleted in state %d", mState);
break;
}
- if (mState == STOPPING) {
- setState(INITIALIZED);
- } else {
- CHECK_EQ(mState, RELEASING);
- setState(UNINITIALIZED);
- mComponentName.clear();
+ setState(INITIALIZED);
+ (new AMessage)->postReply(mReplyID);
+ break;
+ }
+
+ case CodecBase::kWhatReleaseCompleted:
+ {
+ if (mState != RELEASING) {
+ ALOGW("Received kWhatReleaseCompleted in state %d", mState);
+ break;
}
+ setState(UNINITIALIZED);
+ mComponentName.clear();
+
mFlags &= ~kFlagIsComponentAllocated;
mResourceManagerService->removeResource(getId(mResourceManagerClient));
@@ -2355,8 +2362,6 @@
if (info->mNotify != NULL) {
sp<AMessage> msg = info->mNotify;
info->mNotify = NULL;
- msg->setObject("buffer", (portIndex == kPortIndexInput && mCrypto != NULL)
- ? info->mSecureData : info->mData);
if (isReclaim && info->mOwnedByClient) {
ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
portIndex, i);
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 30e3643..877aead 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -676,7 +676,8 @@
}
sp<AMessage> notify = mNotify->dup();
- notify->setInt32("what", CodecBase::kWhatShutdownCompleted);
+ notify->setInt32("what", keepComponentAllocated ?
+ CodecBase::kWhatStopCompleted : CodecBase::kWhatReleaseCompleted);
notify->post();
}
diff --git a/media/libstagefright/foundation/tests/Android.mk b/media/libstagefright/foundation/tests/Android.mk
new file mode 100644
index 0000000..e7598ca
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Android.mk
@@ -0,0 +1,33 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE := sf_foundation_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ Flagged_test.cpp \
+ TypeTraits_test.cpp \
+ Utils_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_foundation \
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/include \
+
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
+include $(BUILD_NATIVE_TEST)
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/media/libstagefright/foundation/tests/Flagged_test.cpp b/media/libstagefright/foundation/tests/Flagged_test.cpp
new file mode 100644
index 0000000..3c90699
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Flagged_test.cpp
@@ -0,0 +1,639 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Flagged_test"
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/foundation/Flagged.h>
+
+namespace android {
+
+/**
+ * Helper template that can be used to print values in static_assert error messages.
+ *
+ * Use integers here.
+ */
+template<bool, int ...N>
+struct _print_as_warning { };
+
+template<int ...N>
+struct _print_as_warning<true, N...> : std::true_type { };
+
+#define static_assert_equals(a, b, msg) \
+static_assert(_print_as_warning<(a) == (b), a, b>::value, msg)
+
+class FlaggedTest : public ::testing::Test {
+protected:
+ // empty structs
+ struct A0 { };
+ struct A1 { };
+ struct A_A0 : public A0 { };
+
+ // simple struct
+ struct BB {
+ int32_t i;
+ uint32_t u;
+ };
+
+ // struct inheriting from A0
+ struct BB_A0 : public A0 {
+ int32_t i;
+ uint32_t u;
+ };
+
+ // struct inheriting from struct inheriting A0
+ struct BB_AA0 : public A_A0 {
+ int32_t i;
+ uint32_t u;
+ };
+
+ // struct that wraps
+ struct WBBA0 {
+ BB_A0 b;
+ };
+
+ struct WBBA0_A1 : public A1 {
+ BB_A0 b;
+ };
+
+ struct WBBA0_A0 : public A0 {
+ BB_A0 b;
+ };
+
+ struct WBB_A0 : public A0 {
+ BB b;
+ };
+
+ struct WBBA0_AA0 : public A_A0 {
+ BB_A0 b;
+ };
+
+ struct WBBAA0_A0 : public A0 {
+ BB_AA0 b;
+ };
+
+ struct WWBBA0_A0 : public A0 {
+ WBBA0 b;
+ };
+};
+
+/**
+ * This test is here to confirm the handling of wrapping classes that inherit from an interface
+ * while also inheriting from that same interface. While we no longer use this construct, we want
+ * to track if this defect is ever fixed.
+ */
+TEST_F(FlaggedTest, StaticSanityTests) {
+ static_assert(sizeof(A0) == 1, "");
+ static_assert(sizeof(A1) == 1, "");
+ static_assert(sizeof(A_A0) == 1, "");
+
+ static constexpr size_t size = sizeof(BB); // original [pair]
+
+ // inheriting from A0 does not increase size
+ static_assert(sizeof(BB_A0) == size, ""); // [pair]:A0
+ static_assert(sizeof(BB_AA0) == size, ""); // [pair]:[:A0]
+
+ // wrapping a class that inherits from A0 does not increase size
+ static_assert(sizeof(WBBA0) == size, ""); // [ [pair]:[:A0] ]
+
+ // wrapping a class that inherits from A0 while also inheriting from A1 does not increase size
+ static_assert(sizeof(WBBA0_A1) == size, ""); // [ [pair]:A0 ]:A1
+
+ // wrapping a class that inherits from A0 while also inheriting from A0 DOES increase size
+ EXPECT_GT(sizeof(WBBA0_A0), size); // [ [pair]:A0 ]:A0
+
+ // wrapping a class that does not inherit from A0 while inheriting from A0 does not increase
+ // size
+ static_assert(sizeof(WBB_A0) == size, ""); // [[pair]]:A0
+
+ // wrapping a class that inherits from A0 while also inheriting from a class that inherits
+ // from A0 does increase size
+ EXPECT_GT(sizeof(WBBA0_AA0), size); // [ [pair]:A0 ]:[:A0]
+
+ // wrapping a class that indirectly inherits from A0 while also inheriting from A0 does
+ // increase size
+ EXPECT_GT(sizeof(WBBAA0_A0), size); // [ [pair]:[:A0] ]:A0
+
+ // wrapping a class that inherits from A0 while also inheriting A0 does increase size
+ EXPECT_GT(sizeof(WWBBA0_A0), size); // [ [pair]:A0 ]:A0
+}
+
+enum FLAG : int32_t {
+ kMask0 = 0x0FF,
+ kFlag0_A = 0x0AA,
+ kFlag0_B = 0x0BB,
+ kFlag0_C = 0x0CC,
+ kMask1 = 0xFF0,
+ kFlag1_A = 0xAA0,
+ kFlag1_B = 0xBB0,
+ kFlag1_C = 0xCC0,
+ kMaskCommon = 0x0F0,
+};
+
+TEST_F(FlaggedTest, BasicExample) {
+ enum SafeFlags : uint32_t {
+ kUnsafe,
+ kSafe,
+ kSafeMask = _Flagged_helper::minMask(kSafe),
+ };
+ typedef Flagged<int32_t, SafeFlags, kSafeMask> safeInt32;
+
+ safeInt32 a(kUnsafe);
+ a.setFlags(kSafe);
+ a.get() = 15;
+ EXPECT_EQ(a.flags(), kSafe);
+ EXPECT_EQ(a.get(), 15);
+
+ enum OriginFlags : uint32_t {
+ kUnknown,
+ kConst,
+ kCalculated,
+ kComponent,
+ kApplication,
+ kFile,
+ kBinder,
+ kOriginMask = _Flagged_helper::minMask(kBinder),
+ };
+ typedef Flagged<safeInt32, OriginFlags, kOriginMask>
+ trackedSafeInt32;
+
+ static_assert(sizeof(trackedSafeInt32) == sizeof(safeInt32), "");
+
+ trackedSafeInt32 b(kConst, kSafe, 1);
+ EXPECT_EQ(b.flags(), kConst);
+ EXPECT_EQ(b.get().flags(), kSafe);
+ EXPECT_EQ(b.get().get(), 1);
+ b.setFlags(kCalculated);
+ volatile bool overflow = true;
+ b.get().setFlags(overflow ? kUnsafe : kSafe);
+
+ enum ValidatedFlags : uint32_t {
+ kUnsafeV = kUnsafe,
+ kSafeV = kSafe,
+ kValidated = kSafe | 2,
+ kSharedMaskV = kSafeMask,
+ kValidatedMask = _Flagged_helper::minMask(kValidated),
+ };
+ typedef Flagged<safeInt32, ValidatedFlags, kValidatedMask, kSharedMaskV> validatedInt32;
+
+ validatedInt32 v(kUnsafeV, kSafe, 10);
+ EXPECT_EQ(v.flags(), kUnsafeV);
+ EXPECT_EQ(v.get().flags(), kUnsafe); // !kUnsafeV overrides kSafe
+ EXPECT_EQ(v.get().get(), 10);
+ v.setFlags(kValidated);
+ EXPECT_EQ(v.flags(), kValidated);
+ EXPECT_EQ(v.get().flags(), kSafe);
+ v.get().setFlags(kUnsafe);
+ EXPECT_EQ(v.flags(), 2); // NOTE: sharing masks with enums allows strange situations to occur
+}
+
+TEST_F(FlaggedTest, _Flagged_helper_Test) {
+ using helper = _Flagged_helper;
+
+ using i32 = int32_t;
+ using u32 = uint32_t;
+ using u8 = uint8_t;
+
+ // base2
+ static_assert(Flagged<i32, u32, 0u, 0u, 0>::sFlagMask == 0u, "");
+ static_assert(Flagged<i32, u32, 0u, 0u, 0>::sFlagShift == 0, "");
+ static_assert(Flagged<i32, u32, 0u, 0u, 0>::sEffectiveMask == 0u, "");
+
+ static_assert(Flagged<i32, u32, 0u, 0u, 10>::sFlagMask == 0u, "");
+ static_assert(Flagged<i32, u32, 0u, 0u, 10>::sFlagShift == 10, "");
+ static_assert(Flagged<i32, u32, 0u, 0u, 10>::sEffectiveMask == 0u, "");
+
+ static_assert(Flagged<i32, u32, 0u, 0u, -1>::sFlagMask == 0u, "");
+ static_assert(Flagged<i32, u32, 0u, 0u, -1>::sFlagShift == 0, "");
+ static_assert(Flagged<i32, u32, 0u, 0u, -1>::sEffectiveMask == 0u, "");
+
+ static_assert(Flagged<i32, u32, 99u, 0u, 0>::sFlagMask == 99u, "");
+ static_assert(Flagged<i32, u32, 99u, 0u, 0>::sFlagShift == 0, "");
+ static_assert(Flagged<i32, u32, 99u, 0u, 0>::sEffectiveMask == 99u, "");
+
+ static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sFlagMask == 0x99u, "");
+ static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sFlagShift == 12, "");
+ static_assert(Flagged<i32, u32, 0x99u, 0u, 12>::sEffectiveMask == 0x99000u, "");
+
+ static_assert(Flagged<i32, u32, 99u, 0u, -1>::sFlagMask == 99u, "");
+ static_assert(Flagged<i32, u32, 99u, 0u, -1>::sFlagShift == 0, "");
+ static_assert(Flagged<i32, u32, 99u, 0u, -1>::sEffectiveMask == 99u, "");
+
+ // mask_of<T, Flag>
+ // also Flagged<> no default
+ typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 0 /* shift */> i32_800f_0;
+ typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 4 /* shift */> i32_800f_4;
+ // this also tests that these types can be instantiated
+ static_assert(sizeof(i32_800f_0) >= sizeof(i32) + sizeof(u32),
+ "should be at least size of component types");
+ static_assert(sizeof(i32_800f_4) == sizeof(i32_800f_0), "regardless of shift");
+ static_assert(!i32_800f_0::sFlagCombined, "");
+ static_assert(!i32_800f_4::sFlagCombined, "");
+
+ static_assert(helper::mask_of<i32_800f_0, u32>::value == 0x800F, "incorrect mask");
+ static_assert(helper::mask_of<i32_800f_0, i32>::value == 0,
+ "mask should be 0 when types mismatch");
+ static_assert(helper::mask_of<i32_800f_0, u32>::effective_value == 0x800F, "incorrect mask");
+ static_assert(helper::mask_of<i32_800f_0, i32>::effective_value == 0,
+ "mask should be 0 when types mismatch");
+ static_assert(helper::mask_of<i32_800f_0, u32>::shift == 0, "incorrect shift");
+ static_assert(helper::mask_of<i32_800f_0, i32>::shift == 0,
+ "shift should be 0 when types mismatch");
+
+ static_assert(helper::mask_of<i32_800f_4, u32>::value == 0x800F, "incorrect mask");
+ static_assert(helper::mask_of<i32_800f_4, i32>::value == 0,
+ "mask should be 0 when types mismatch");
+ static_assert(helper::mask_of<i32_800f_4, u32>::effective_value == 0x800F0, "incorrect mask");
+ static_assert(helper::mask_of<i32_800f_4, i32>::effective_value == 0,
+ "mask should be 0 when types mismatch");
+ static_assert(helper::mask_of<i32_800f_4, u32>::shift == 4, "incorrect shift");
+ static_assert(helper::mask_of<i32_800f_4, i32>::shift == 0,
+ "shift should be 0 when types mismatch");
+ static_assert(helper::mask_of<i32, u32>::value == 0, "mask should be 0 if not masked");
+ static_assert(helper::mask_of<i32, i32>::value == 0, "mask should be 0 if not masked");
+
+ // lshift(value, n)
+ static_assert(helper::lshift(0U, 0) == 0U, "");
+ static_assert(helper::lshift(0U, 30) == 0U, "");
+ static_assert(helper::lshift(1U, 0) == 1U, "");
+ static_assert(helper::lshift(1U, 10) == 1024U, "");
+ static_assert(helper::lshift(10U, 10) == 10240U, "");
+ static_assert(helper::lshift(10, 10) == 10240, "");
+ static_assert(helper::lshift(-10, 0) == -10, "");
+ // static_assert(helper::lshift(-10, 10) == -10240, ""); // error: left shift of negative value
+
+ // minMask(maxValue)
+ static_assert(helper::minMask(0U) == 0U, "lowest 0 bits");
+ static_assert(helper::minMask(1U) == 1U, "lowest 1 bit");
+ static_assert(helper::minMask(2U) == 3U, "lowest 2 bits");
+ static_assert(helper::minMask(3U) == 3U, "lowest 2 bits");
+ static_assert(helper::minMask(4U) == 7U, "lowest 3 bits");
+ static_assert(helper::minMask(~0U) == ~0U, "all bits");
+ // static_assert(helper::minMask(10) == 0xF, "all bits"); // error: must be unsigned
+
+ // topBits(n)
+ static_assert(helper::topBits<u32>(0) == 0U, "top 0 bit");
+ static_assert(helper::topBits<u32>(1) == 0x80000000U, "top 1 bit");
+ static_assert(helper::topBits<u32>(2) == 0xC0000000U, "top 2 bits");
+ static_assert(helper::topBits<u32>(12) == 0xFFF00000U, "top 12 bits");
+ static_assert(helper::topBits<u32>(32) == 0xFFFFFFFFU, "all bits");
+ // static_assert(helper::topBits<u32>(33) == 0xFFFFFFFFU, ""); // should OVERFLOW
+
+ static_assert(helper::topBits<u8>(0) == 0U, "top 0 bit");
+ static_assert(helper::topBits<u8>(1) == 0x80U, "top 1 bit");
+ static_assert(helper::topBits<u8>(2) == 0xC0U, "top 2 bit");
+ static_assert(helper::topBits<u8>(8) == 0xFFU, "all bits");
+ // static_assert(helper::topBits<u8>(9) == 0xFFU, ""); // should OVERFLOW
+
+ // getShift(mask, base, shared, base-shift, base-effective)
+ static_assert(helper::getShift(0u, 0u, 0u, 0, 0u) == 0, "no flag require no shift");
+ static_assert(helper::getShift(0u, 0u, 1u, 0, 0u) == -1,
+ "shared must be within mask and base mask");
+ static_assert(helper::getShift(0u, 1u, 1u, 0, 1u) == -1, "shared must be within mask");
+ static_assert(helper::getShift(0u, 1u, 0u, 0, 1u) == 0,
+ "no flags require no shift even with base mask");
+ static_assert(helper::getShift(0u, 1u, 0u, 1, 2u) == 0,
+ "no flags require no shift even with shifted base mask");
+ static_assert(helper::getShift(1u, 0u, 0u, 0, 0u) == 0, "no base mask requires no shift");
+ static_assert(helper::getShift(1u, 1u, 0u, 0, 1u) == 1,
+ "overlapping mask and basemask requires shift");
+ static_assert(helper::getShift(1u, 1u, 0u, 0, 1u) == 1,
+ "overlapping mask and basemask requires shift");
+ static_assert(helper::getShift(1u, 1u, 1u, 0, 1u) == 0,
+ "shared mask requires using base shift");
+ static_assert(helper::getShift(1u, 1u, 1u, 1, 2u) == 1,
+ "shared mask requires using base shift");
+ static_assert(helper::getShift(3u, 5u, 1u, 0, 5u) == 0,
+ "mask and basemask that overlap only in shared region requires no shift");
+ static_assert(helper::getShift(3u, 7u, 1u, 0, 7u) == -1,
+ "mask and basemask must not overlap in more than shared region");
+ static_assert(helper::getShift(1u, 0u, 1u, 0, 0u) == -1, "shared must be within base mask");
+
+ static_assert(helper::getShift(0u, 1u, 0u, 1, 1u) == -2, "effective mask must cover base mask");
+ static_assert(helper::getShift(0u, 5u, 0u, 1, 2u) == -2, "effective mask must cover base mask");
+ static_assert(helper::getShift(0u, 5u, 0u, 1, 10u) == 0, "");
+ static_assert(helper::getShift(0u, 5u, 0u, 1, 31u) == 0,
+ "effective mask can be larger than base mask");
+
+ static_assert(helper::getShift(0x800Fu, 0x800Fu, 0x800Fu, 0, 0x800Fu) == 0,
+ "(0x800F << 0) & 0x800F == 0x800F");
+ static_assert(helper::getShift(0x800Fu, 0x800Fu, 0x800Fu, 16, 0x800F0000u) == 16,
+ "(0x800F << 0) & 0x800F == 0x800F");
+ static_assert(helper::getShift(0x1800Fu, 0x800Fu, 0x800Fu, 0, 0x800Fu) == 0,
+ "(0x1800F << 0) & 0x800F == 0x800F");
+ static_assert(helper::getShift(0x1800Fu, 0x800Fu, 0x800Fu, 16, 0x800F0000u) == -1,
+ "(0x1800F << 16) overflows");
+
+ // verify that when not sharing masks, effective mask makes the difference
+ static_assert(helper::getShift(0x800Fu, 0u, 0u, 0, 0x800Fu) == 4,
+ "(0x800F << 4) & 0x800F == 0");
+ static_assert(helper::getShift(0x800Fu, 0x2u, 0u, 0, 0x8002u) == 2,
+ "(0x800F << 2) & 0x8002 == 0");
+ static_assert(helper::getShift(0x800Fu, 0x1u, 0u, 15, 0x8001u) == 1,
+ "(0x800F << 1) & 0x8001 == 0");
+ static_assert(helper::getShift(0x800Fu, 0x800Fu, 0u, 16, 0x800F0000u) == 0,
+ "0x800F & 0x800F0000 == 0");
+ static_assert(helper::getShift(0x800Fu, 0x800F8000u, 0u, 0, 0x800F8000u) == 5,
+ "(0x800F << 5) & 0x800F8000 == 0");
+ static_assert(helper::getShift(0x800Fu, 0xF0000u, 0u, 0, 0x800F8000u) == 5,
+ "(0x800F << 5) & 0x800F8000 == 0");
+ static_assert(helper::getShift(0x800Fu, 0x1Fu, 0u, 15, 0x800F8000u) == 5,
+ "(0x800F << 5) & 0x800F8000 == 0");
+ static_assert(helper::getShift(0xFFu, 0x80808080u, 0u, 0, 0x80808080u) == -1,
+ "0xFF always overlaps with 0x80808080");
+ static_assert(helper::getShift(0xFFu, 0x10001000u, 0u, 3, 0x80808080u) == -1,
+ "0xFF always overlaps with 0x80808080");
+ static_assert(helper::getShift(0xFFu, 0x80808040u, 0u, 0, 0x80808040u) == 7,
+ "(0xFF << 7) & 0x 80808040 == 0");
+
+ // verify min_shift (mask must be positive or no shift can be required)
+ static_assert(helper::getShift(0xFF, 0x40808040, 0, 0, 0x40808040) == 7, "");
+ static_assert(helper::getShift((i32)0x800000FF, 0x40808040, 0, 0, 0x40808040) == -1, "");
+ static_assert(helper::getShift(0x100000FF, 0x40808040, 0, 0, 0x40808040) == -1, "");
+ static_assert(helper::getShift(0xFF, (i32)0x80808040, 0, 0, (i32)0x80808040) == 7, "");
+ static_assert(helper::getShift((i32)0x80007F80, 0x40808040, 0, 0, 0x40808040) == 0, "");
+
+ // shared mask can also be negative (but not shift can be required)
+ static_assert(helper::getShift((i32)0x80007F80, (i32)0xC0808040, (i32)0x80000000,
+ 0, (i32)0xC0808040) == 0, "");
+ static_assert(helper::getShift((i32)0x80007F80, (i32)0xC0808040, (i32)0xC0000000,
+ 0, (i32)0xC0808040) == -1, "");
+ static_assert(helper::getShift((i32)0x80007F80, (i32)0x60404020, (i32)0x60000000,
+ 1, (i32)0xC0808040) == -1, "");
+
+ // min_shift
+ typedef Flagged<i32, u32, 0u> i32_0_0;
+ typedef Flagged<i32, u32, 1u> i32_1_0;
+ typedef Flagged<i32, u32, 1u, 0u, 1> i32_1_1;
+
+ // this is a wrapper over getShift, so same test cases apply when T is flagged
+ static_assert(helper::min_shift<i32_0_0, u32, 0u, 0u>::value == 0, "");
+ static_assert(helper::min_shift<i32_0_0, u32, 0u, 1u>::value == -1, "");
+ static_assert(helper::min_shift<i32_1_0, u32, 0u, 1u>::value == -1, "");
+ static_assert(helper::min_shift<i32_1_0, u32, 0u, 0u>::value == 0, "");
+ static_assert(helper::min_shift<i32_0_0, u32, 1u, 0u>::value == 0, "");
+ static_assert(helper::min_shift<i32_1_0, u32, 1u, 0u>::value == 1, "");
+ static_assert(helper::min_shift<i32_1_0, u32, 1u, 1u>::value == 0, "");
+ static_assert(helper::min_shift<i32_1_1, u32, 1u, 1u>::value == 1, "");
+ static_assert(helper::min_shift<i32_1_1, u32, 3u, 0u>::value == 2, "");
+ static_assert(helper::min_shift<Flagged<i32, u32, 5u>, u32, 3u, 1u>::value == 0, "");
+ static_assert(helper::min_shift<Flagged<i32, u32, 7u>, u32, 3u, 1u>::value == -1, "");
+ static_assert(helper::min_shift<i32_0_0, u32, 1u, 1u>::value == -1, "");
+
+ static_assert(helper::min_shift<i32_800f_0, u32, 0x800Fu, 0u>::value == 4, "");
+ static_assert(helper::min_shift<i32_800f_4, u32, 0x1800Fu, 0x800Fu>::value == 4, "");
+ static_assert(helper::min_shift<i32_800f_4, u32, 0x800Fu, 0u>::value == 0, "");
+ static_assert(helper::min_shift<Flagged<i32, u32, 0x8002u>, u32, 0x800Fu, 0u>::value == 2, "");
+ static_assert(helper::min_shift<Flagged<i32, u32, 0x8001u>, u32, 0x800Fu, 0u>::value == 1, "");
+ static_assert(
+ helper::min_shift<Flagged<i32, u32, 0x800Fu, 0u, 16>, u32, 0x800Fu, 0u>::value == 0, "");
+ static_assert(
+ helper::min_shift<Flagged<i32, u32, 0x800F8000u>, u32, 0x800Fu, 0u>::value == 5, "");
+ static_assert(
+ helper::min_shift<Flagged<i32, u32, 0x80808080u>, u32, 0xFFu, 0u>::value == -1, "");
+ static_assert(
+ helper::min_shift<Flagged<i32, u32, 0x80808040u>, u32, 0xFFu, 0u>::value == 7, "");
+
+ // for min_shift, non-tagged type behaves as if having base mask of 0
+ static_assert(helper::min_shift<i32, u32, 0u, 0u>::value == 0, "");
+ static_assert(helper::min_shift<u32, u32, 0u, 0u>::value == 0, "");
+ static_assert(helper::min_shift<i32, u32, 0u, 0u>::value == 0, "");
+ static_assert(helper::min_shift<i32, u32, 0u, 1u>::value == -1, "");
+ static_assert(helper::min_shift<i32, u32, 1u, 0u>::value == 0, "");
+ static_assert(helper::min_shift<i32, u32, 1u, 1u>::value == -1, "");
+
+ // verify min_shift (mask must be positive or no shift can be required)
+ static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>, i32, 0xFF, 0>::value == 7, "");
+ static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
+ i32, (i32)0x800000FF, 0>::value == -1, "");
+ static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
+ i32, 0x100000FF, 0>::value == -1, "");
+ static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x80808040>,
+ i32, 0xFF, 0>::value == 7, "");
+ static_assert(helper::min_shift<Flagged<i32, i32, 0x40808040>,
+ i32, (i32)0x80007F80, 0>::value == 0, "");
+
+ static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x80808040>,
+ i32, (i32)0x80007F80, (i32)0x80000000>::value == 0, "");
+ static_assert(helper::min_shift<Flagged<i32, i32, (i32)0xC0808040>,
+ i32, (i32)0x80007F80, (i32)0xC0000000>::value == -1, "");
+ // note: cannot create a flagged type with signed flag and shift
+ // static_assert(helper::min_shift<Flagged<i32, i32, (i32)0x60404020, 0, 1>,
+ // i32, (i32)0x40003FC0, (i32)0x40000000>::value == -1, "");
+
+ typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 16 /* shift */> i32_800f_16;
+ static_assert_equals(sizeof(i32_800f_16), sizeof(i32_800f_0), "");
+ // shifted mask overflows!
+ // typedef Flagged<i32, u32, 0x800F /* mask */, 0 /* shared mask */, 17 /* shift */> i32_800f_17;
+ // static_assert(sizeof(i32_800f_17) == sizeof(i32_800f_0), "");
+ typedef Flagged<i32, i32, 0x800F /* mask */, 0 /* shared mask */, 15 /* shift */> i32_800f_15i;
+ static_assert_equals(sizeof(i32_800f_15i), sizeof(i32_800f_0), "");
+ // shifted mask overflows!
+ // typedef Flagged<i32, i32, 0x800F /* mask */, 0 /* shared mask */, 16 /* shift */> i32_800f_16i;
+ // static_assert(sizeof(i32_800f_16i) == sizeof(i32_800f_0), "");
+
+ // canCombine(mask, base, shared, shift, base-shift, base-effective)
+ static_assert(helper::canCombine(0u, 0u, 0u, 0, 0, 0u), "using no mask is valid");
+ static_assert(helper::canCombine(0u, 0u, 0u, 0, 0, 0u), "");
+ static_assert(helper::canCombine(0u, 0u, 0u, 4, 0, 0u), "");
+ static_assert(!helper::canCombine(0u, 0u, 1u, 0, 0, 0u),
+ "shared mask must be the overlap of masks");
+ static_assert(helper::canCombine(1u, 0u, 0u, 0, 0, 0u), "");
+ static_assert(helper::canCombine(1u, 0u, 0u, 4, 0, 0u), "");
+ static_assert(helper::canCombine(3u, 5u, 1u, 0, 0, 5u), "");
+ static_assert(!helper::canCombine(3u, 3u, 3u, 1, 0, 3u), "shift must match when sharing mask");
+ static_assert(helper::canCombine(3u, 3u, 3u, 1, 1, 6u), "");
+ static_assert(!helper::canCombine(3u, 3u, 3u, 1, 2, 12u), "shift must match when sharing mask");
+ static_assert(!helper::canCombine(3u, 7u, 1u, 0, 0, 7u), "");
+ static_assert(!helper::canCombine(1u, 0u, 1u, 0, 0, 0u), "");
+
+ static_assert(!helper::canCombine(0u, 1u, 1u, 0, 0, 1u),
+ "shared mask must be the overlap of masks");
+ static_assert(helper::canCombine(0u, 1u, 0u, 0, 0, 1u), "");
+ static_assert(helper::canCombine(0u, 1u, 0u, 4, 0, 1u), "");
+ static_assert(helper::canCombine(1u, 1u, 0u, 1, 0, 1u), "");
+ static_assert(!helper::canCombine(1u, 1u, 0u, 0, 0, 1u), "");
+ static_assert(helper::canCombine(1u, 1u, 0u, 1, 0, 1u), "");
+ static_assert(helper::canCombine(1u, 1u, 1u, 0, 0, 1u), "");
+ static_assert(!helper::canCombine(1u, 1u, 1u, 1, 0, 1u), "shift must match when sharing mask");
+
+ static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0u, 4, 0, 0x800Fu), "");
+ static_assert(!helper::canCombine(0x800Fu, 0x800Fu, 0u, 1, 0, 0x800Fu), "");
+ static_assert(helper::canCombine(0x800Fu, 0x8002u, 0u, 2, 0, 0x8002u), "");
+ static_assert(helper::canCombine(0x800Fu, 0x8001u, 0u, 1, 0, 0x8001u), "");
+ static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0u, 0, 16, 0x800F0000u), "");
+ static_assert(helper::canCombine(0x800Fu, 0x800Fu, 0x800Fu, 16, 16, 0x800F0000u), "");
+ static_assert(!helper::canCombine(0x1800Fu, 0x800Fu, 0u, 0, 16, 0x800F0000u), "");
+ static_assert(!helper::canCombine(0x1800Fu, 0x800Fu, 0x800Fu, 16, 16, 0x800F0000u), "");
+ static_assert(helper::canCombine(0x800Fu, 0x800F8000u, 0u, 8, 0, 0x800F8000u), "");
+ static_assert(!helper::canCombine(0xFFu, 0x80808080u, 0u, -1, 0, 0x80808080u), "");
+ static_assert(helper::canCombine(0xFFu, 0x80808040u, 0u, 7, 0, 0x80808040u), "");
+ static_assert(helper::canCombine(0xFFu, 0x8000u, 0u, 7, 0, 0x80808040u), "");
+ static_assert(helper::canCombine(0xFFu, 0x101u, 0u, 7, 15, 0x80808040u), "");
+
+ // can combine signed-flagged types only if mask is positive or no shift is required
+ static_assert(!helper::canCombine(0xFF, 0x40808040, 0, 0, 0, 0x40808040), "");
+ static_assert(helper::canCombine(0xFF, 0x40808040, 0, 7, 0, 0x40808040), "");
+ static_assert(!helper::canCombine((i32)0x800000FF, 0x40808040, 0, 0, 0, 0x40808040), "");
+ static_assert(!helper::canCombine((i32)0x800000FF, 0x40808040, 0, 7, 0, 0x40808040), "");
+ static_assert(!helper::canCombine(0x100000FF, 0x40808040, 0, 0, 0, 0x40808040), "");
+ static_assert(!helper::canCombine(0x100000FF, 0x40808040, 0, 7, 0, 0x40808040), "");
+ static_assert(!helper::canCombine(0xFF, (i32)0x80808040, 0, 0, 0, (i32)0x80808040), "");
+ static_assert(helper::canCombine(0xFF, (i32)0x80808040, 0, 7, 0, (i32)0x80808040), "");
+ static_assert(helper::canCombine((i32)0x80007F80, 0x40808040, 0, 0, 0, 0x40808040), "");
+
+ static_assert(helper::canCombine((i32)0x80007F80, (i32)0x80808040, (i32)0x80000000, 0, 0, (i32)0x80808040), "");
+ static_assert(!helper::canCombine((i32)0xC0007F80, (i32)0x80808040, (i32)0xC0000000, 0, 0, (i32)0x80808040), "");
+ static_assert(!helper::canCombine((i32)0x80007F80, (i32)0x80808040, (i32)0x80000000, 1, 0, (i32)0x80808040), "");
+ static_assert(!helper::canCombine((i32)0xC0007F80, (i32)0x80808040, (i32)0xC0000000, 1, 0, (i32)0x80808040), "");
+
+ // can_combine<T, Flag, MASK, [SHARED_MASK], [SHIFT]
+ static_assert(helper::can_combine<i32_0_0, u32, 0u>::value, "");
+ static_assert(helper::can_combine<i32_0_0, u32, 0u, 0u>::value, "");
+ static_assert(helper::can_combine<i32_0_0, u32, 0u, 0u, 4>::value, "");
+ static_assert(!helper::can_combine<i32_0_0, u32, 0u, 1u>::value, "");
+ static_assert(helper::can_combine<i32_0_0, u32, 1u, 0u>::value, "");
+ static_assert(helper::can_combine<i32_0_0, u32, 1u, 0u, 4>::value, "");
+ static_assert(!helper::can_combine<i32_0_0, u32, 1u, 1u>::value, "");
+
+ static_assert(!helper::can_combine<i32_1_0, u32, 0u, 1u>::value, "");
+ static_assert(helper::can_combine<i32_1_0, u32, 0u, 0u>::value, "");
+ static_assert(helper::can_combine<i32_1_0, u32, 0u, 0u, 4>::value, "");
+ static_assert(helper::can_combine<i32_1_0, u32, 1u, 0u>::value, "");
+ static_assert(!helper::can_combine<i32_1_0, u32, 1u, 0u, 0>::value, "");
+ static_assert(helper::can_combine<i32_1_0, u32, 1u, 0u, 1>::value, "");
+ static_assert(helper::can_combine<i32_1_0, u32, 1u, 1u>::value, "");
+ static_assert(helper::can_combine<i32_1_0, u32, 1u, 1u, 0>::value, "");
+ static_assert(!helper::can_combine<i32_1_0, u32, 1u, 1u, 1>::value,
+ "shouldn't be able to use SHIFT with SHARED_MASK");
+
+ static_assert(helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u, 4>::value, "");
+ static_assert(!helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u, 1>::value, "");
+ static_assert(helper::can_combine<i32_800f_0, u32, 0x800Fu, 0u>::value, "");
+ static_assert(helper::can_combine<Flagged<i32, u32, 0x8002u>, u32, 0x800Fu, 0u>::value, "");
+ static_assert(helper::can_combine<Flagged<i32, u32, 0x8001u>, u32, 0x800Fu, 0u>::value, "");
+ static_assert(helper::can_combine<Flagged<i32, u32, 0x800F0000u>, u32, 0x800Fu, 0u>::value, "");
+ static_assert(helper::can_combine<Flagged<i32, u32, 0x800F8000u>, u32, 0x800Fu, 0u>::value, "");
+ static_assert(!helper::can_combine<Flagged<i32, u32, 0x80808080u>, u32, 0xFFu, 0u>::value, "");
+ static_assert(helper::can_combine<Flagged<i32, u32, 0x80808040u>, u32, 0xFFu, 0u>::value, "");
+
+ // can combine signed-flagged types only if mask is positive or no shift is required
+ static_assert(helper::can_combine<Flagged<i32, i32, 0x40808040>, i32, 0xFF, 0>::value, "");
+ static_assert(!helper::can_combine<Flagged<i32, i32, 0x40808040>,
+ i32, (i32)0x800000FF, 0>::value, "");
+ static_assert(!helper::can_combine<Flagged<i32, i32, 0x40808040>,
+ i32, 0x100000FF, 0>::value, "");
+ static_assert(helper::can_combine<Flagged<i32, i32, (i32)0x80808040>, i32, 0xFF, 0>::value, "");
+ static_assert(helper::can_combine<Flagged<i32, i32, 0x40808040>,
+ i32, (i32)0x80007F80, 0>::value, "");
+
+ static_assert(helper::can_combine<Flagged<i32, i32, (i32)0x80808040>,
+ i32, (i32)0x80007F80, (i32)0x80000000>::value, "");
+ static_assert(!helper::can_combine<Flagged<i32, i32, (i32)0xC0808040>,
+ i32, (i32)0x80007F80, (i32)0xC0000000>::value, "");
+
+ static_assert(helper::min_shift<Flagged<i32, FLAG, (FLAG)0x80808040>,
+ FLAG, (FLAG)0x80007F80, (FLAG)0x80000000>::value == 0, "");
+ static_assert(helper::can_combine<Flagged<i32, FLAG, (FLAG)0x80808040>,
+ FLAG, (FLAG)0x80007F80, (FLAG)0x80000000>::value, "");
+
+ // cannot combine non-tagged types
+ static_assert(!helper::can_combine<i32, u32, 0u, 0u>::value, "");
+ static_assert(!helper::can_combine<u32, u32, 0u, 0u>::value, "");
+ static_assert(!helper::can_combine<i32, u32, 0u, 0u>::value, "");
+ static_assert(!helper::can_combine<i32, u32, 0u, 1u>::value, "");
+ static_assert(!helper::can_combine<i32, u32, 1u, 0u>::value, "");
+ static_assert(!helper::can_combine<i32, u32, 1u, 1u>::value, "");
+
+ typedef Flagged<i32_800f_0, u32, 0x800F /* mask */, 0 /* shared mask */> i32_800f_800f;
+ static_assert(i32_800f_800f::sFlagMask == 0x800F, "");
+ static_assert(i32_800f_800f::sFlagShift == 4, "");
+ static_assert(i32_800f_800f::sEffectiveMask == 0x880FF, "");
+ static_assert(!i32_800f_0::sFlagCombined, "");
+ static_assert(!i32_800f_4::sFlagCombined, "");
+
+ static_assert(i32_800f_800f::sFlagCombined, "");
+ static_assert_equals(sizeof(i32_800f_800f), sizeof(i32_800f_0), "");
+
+ typedef Flagged<i32_800f_0, u32, 0x1FFFF /* mask */> i32_800f_1ffff;
+ static_assert(i32_800f_1ffff::sFlagMask == 0x1FFFF, "");
+ static_assert(i32_800f_1ffff::sFlagShift == 0, "");
+ static_assert(i32_800f_1ffff::sEffectiveMask == 0x1FFFF, "");
+ static_assert(!i32_800f_1ffff::sFlagCombined, "");
+
+ // operational tests
+ i32_800f_800f val(0x8000, 0x1234, 56);
+ EXPECT_EQ(val.get().get(), 56);
+ EXPECT_EQ(val.flags(), 0x8000u);
+ EXPECT_EQ(val.get().flags(), 0x1234u & 0x800F);
+ val.setFlags(0x12345);
+ EXPECT_EQ(val.flags(), 0x12345u & 0x800F);
+ EXPECT_EQ(val.get().flags(), 0x1234u & 0x800F);
+ val.get().setFlags(0x54321);
+ EXPECT_EQ(val.flags(), 0x12345u & 0x800F);
+ EXPECT_EQ(val.get().flags(), 0x54321u & 0x800F);
+ EXPECT_EQ(val.get().get(), 56);
+
+ typedef Flagged<i32_800f_4, u32, 0x800F /* mask */, 0 /* shared mask */> i32_800f_800f_B;
+ static_assert(i32_800f_800f_B::sFlagMask == 0x800F, "");
+ static_assert(i32_800f_800f_B::sFlagShift == 0, "");
+ static_assert(i32_800f_800f_B::sEffectiveMask == 0x880FF, "");
+
+ i32_800f_800f_B valB(0x8000, 0x1234, -987);
+ EXPECT_EQ(valB.get().get(), -987);
+ EXPECT_EQ(valB.flags(), 0x8000u);
+ EXPECT_EQ(valB.get().flags(), 0x1234u & 0x800F);
+ valB.setFlags(0x12345);
+ EXPECT_EQ(valB.flags(), 0x12345u & 0x800F);
+ EXPECT_EQ(valB.get().flags(), 0x1234u & 0x800F);
+ valB.get().setFlags(0x5C321);
+ EXPECT_EQ(valB.flags(), 0x12345u & 0x800F);
+ EXPECT_EQ(valB.get().flags(), 0x5C321u & 0x800F);
+ EXPECT_EQ(valB.get().get(), -987);
+
+ typedef Flagged<Flagged<i32, u32, 0xFF>, u32, 0xFF0, 0xF0> i32_ff_ff0;
+ i32_ff_ff0 valC(0xABCD, 0x1234, 101);
+ EXPECT_EQ(valC.get().get(), 101);
+ EXPECT_EQ(valC.flags(), 0xBC0u);
+ EXPECT_EQ(valC.get().flags(), 0xC4u);
+ valC.setFlags(0x12345);
+ EXPECT_EQ(valC.flags(), 0x340u);
+ EXPECT_EQ(valC.get().flags(), 0x44u);
+ valC.get().setFlags(0x54321);
+ EXPECT_EQ(valC.flags(), 0x320u);
+ EXPECT_EQ(valC.get().flags(), 0x21u);
+ EXPECT_EQ(valC.get().get(), 101);
+
+ // when combining flags (with no shift), it should work with signed flags
+ typedef Flagged<Flagged<i32, FLAG, kMask0>, FLAG, kMask1, kMaskCommon> i32_F_ff_ff0;
+ static_assert(i32_F_ff_ff0::sFlagCombined, "flags should be combined");
+
+ i32_F_ff_ff0 valD(kFlag1_A, kFlag0_A, 1023);
+ EXPECT_EQ(valD.get().get(), 1023);
+ EXPECT_EQ(valD.flags(), kFlag1_A);
+ EXPECT_EQ(valD.get().flags(), kFlag0_A);
+ valD.setFlags(kFlag1_B);
+ EXPECT_EQ(valD.flags(), kFlag1_B);
+ EXPECT_EQ(valD.get().flags(), FLAG(0x0BA));
+ valD.get().setFlags(kFlag0_C);
+ EXPECT_EQ(valD.flags(), FLAG(0xBC0));
+ EXPECT_EQ(valD.get().flags(), kFlag0_C);
+ EXPECT_EQ(valD.get().get(), 1023);
+}
+
+} // namespace android
diff --git a/media/libstagefright/foundation/tests/TypeTraits_test.cpp b/media/libstagefright/foundation/tests/TypeTraits_test.cpp
new file mode 100644
index 0000000..9fba435
--- /dev/null
+++ b/media/libstagefright/foundation/tests/TypeTraits_test.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TypeTraits_test"
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/foundation/TypeTraits.h>
+
+namespace android {
+
+class TypeTraitsTest : public ::testing::Test {
+protected:
+ enum A { };
+ enum UA : uint32_t { };
+ enum IA : int32_t { };
+};
+
+// =========== basic sanity tests for type-support templates
+TEST_F(TypeTraitsTest, StaticTests) {
+ static_assert(!std::is_integral<A>::value, "enums should not be integral");
+ static_assert(!std::is_integral<UA>::value, "enums should not be integral");
+ static_assert(!std::is_integral<IA>::value, "enums should not be integral");
+ static_assert(is_integral_or_enum<A>::value, "enums should be integral_or_enum");
+ static_assert(is_integral_or_enum<UA>::value, "enums should be integral_or_enum");
+ static_assert(is_integral_or_enum<IA>::value, "enums should be integral_or_enum");
+ static_assert(is_integral_or_enum<int>::value, "ints should be integral_or_enum");
+ static_assert(is_integral_or_enum<unsigned>::value, "unsigned ints should be integral_or_enum");
+ static_assert(!is_integral_or_enum<float>::value, "floats should not be integral_or_enum");
+
+ static_assert(!std::is_unsigned<UA>::value,
+ "unsigned enums should not be unsigned");
+ static_assert(!std::is_unsigned<IA>::value,
+ "unsigned enums should not be unsigned");
+ static_assert(std::is_unsigned<typename std::underlying_type<UA>::type>::value,
+ "underlying type of unsigned enums should be unsigned");
+ static_assert(!std::is_unsigned<typename std::underlying_type<IA>::type>::value,
+ "underlying type of unsigned enums should be unsigned");
+ static_assert(is_unsigned_integral<UA>::value,
+ "unsigned enums should be unsigned_integral");
+ static_assert(!is_unsigned_integral<IA>::value,
+ "signed enums should not be unsigned_integral");
+ static_assert(is_unsigned_integral<unsigned>::value,
+ "unsigned ints should be unsigned_integral");
+ static_assert(!is_unsigned_integral<int>::value,
+ "ints should not be unsigned_integral");
+ static_assert(!is_unsigned_integral<float>::value,
+ "floats should not be unsigned_integral");
+
+ static_assert(!std::is_signed<UA>::value,
+ "unsigned enums should not be signed");
+ static_assert(!std::is_signed<IA>::value,
+ "unsigned enums should not be signed");
+ static_assert(!std::is_signed<typename std::underlying_type<UA>::type>::value,
+ "underlying type of unsigned enums should be signed");
+ static_assert(std::is_signed<typename std::underlying_type<IA>::type>::value,
+ "underlying type of unsigned enums should be signed");
+ static_assert(!is_signed_integral<UA>::value,
+ "unsigned enums should not be signed_integral");
+ static_assert(is_signed_integral<IA>::value,
+ "signed enums should be signed_integral");
+ static_assert(!is_signed_integral<unsigned>::value,
+ "unsigned ints should not be signed_integral");
+ static_assert(is_signed_integral<int>::value,
+ "ints should be signed_integral");
+ static_assert(!is_signed_integral<float>::value,
+ "floats should not be signed_integral");
+
+ static_assert(std::is_same<uint64_t, typename underlying_integral_type<uint64_t>::type>::value,
+ "underlying integral type of uint64_t should be uint64_t");
+ static_assert(std::is_same<uint32_t, typename underlying_integral_type<UA>::type>::value,
+ "underlying integral type of uint32_t based enums should be uint32_t");
+ static_assert(std::is_same<int64_t, typename underlying_integral_type<int64_t>::type>::value,
+ "underlying integral type of int64_t should be int64_t");
+ static_assert(std::is_same<int32_t, typename underlying_integral_type<IA>::type>::value,
+ "underlying integral type of int32_t based enums should be int32_t");
+ //typedef underlying_integral_type<float>::type no_type;
+ static_assert(std::is_same<void, typename underlying_integral_type<float, void>::type>::value,
+ "underlying integral type of float cannot be specified");
+}
+
+} // namespace android
diff --git a/media/libstagefright/tests/Utils_test.cpp b/media/libstagefright/foundation/tests/Utils_test.cpp
similarity index 98%
rename from media/libstagefright/tests/Utils_test.cpp
rename to media/libstagefright/foundation/tests/Utils_test.cpp
index d736501..0439d5c 100644
--- a/media/libstagefright/tests/Utils_test.cpp
+++ b/media/libstagefright/foundation/tests/Utils_test.cpp
@@ -18,15 +18,11 @@
#define LOG_TAG "Utils_test"
#include <gtest/gtest.h>
-#include <utils/String8.h>
-#include <utils/Errors.h>
-#include <fcntl.h>
-#include <unistd.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AStringUtils.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/Utils.h> // for FOURCC
namespace android {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index e654a01..477280a 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -178,7 +178,7 @@
*shortTermBps = mShortTermEstimate;
}
- int32_t minEstimate = -1, maxEstimate = -1;
+ int64_t minEstimate = -1, maxEstimate = -1;
List<int32_t>::iterator it;
for (it = mPrevEstimates.begin(); it != mPrevEstimates.end(); it++) {
int32_t estimate = *it;
@@ -518,10 +518,10 @@
return err;
}
-status_t LiveSession::seekTo(int64_t timeUs, bool precise) {
+status_t LiveSession::seekTo(int64_t timeUs, MediaPlayerSeekMode mode) {
sp<AMessage> msg = new AMessage(kWhatSeek, this);
msg->setInt64("timeUs", timeUs);
- msg->setInt32("precise", precise);
+ msg->setInt32("mode", mode);
sp<AMessage> response;
status_t err = msg->postAndAwaitResponse(&response);
@@ -1442,11 +1442,11 @@
void LiveSession::onSeek(const sp<AMessage> &msg) {
int64_t timeUs;
- int32_t precise;
+ int32_t mode;
CHECK(msg->findInt64("timeUs", &timeUs));
- CHECK(msg->findInt32("precise", &precise));
- // TODO: add "precise" to changeConfiguration.
- changeConfiguration(timeUs);
+ CHECK(msg->findInt32("mode", &mode));
+ // TODO: add "mode" to changeConfiguration.
+ changeConfiguration(timeUs/* , (MediaPlayerSeekMode)mode */);
}
status_t LiveSession::getDuration(int64_t *durationUs) const {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 4dc529c..a0138be 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -86,7 +86,7 @@
status_t disconnect();
// Blocks until seek is complete.
- status_t seekTo(int64_t timeUs, bool precise);
+ status_t seekTo(int64_t timeUs, MediaPlayerSeekMode mode);
status_t getDuration(int64_t *durationUs) const;
size_t getTrackCount() const;
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
index a93770a..c6963b1 100644
--- a/media/libstagefright/tests/Android.mk
+++ b/media/libstagefright/tests/Android.mk
@@ -38,35 +38,6 @@
include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_MODULE := Utils_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
- Utils_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libmedia \
- libstagefright \
- libstagefright_foundation \
- libstagefright_omx \
-
-LOCAL_C_INCLUDES := \
- frameworks/av/include \
- frameworks/av/media/libstagefright \
- frameworks/av/media/libstagefright/include \
- $(TOP)/frameworks/native/include/media/openmax \
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_NATIVE_TEST)
-
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/services/audiopolicy/engineconfigurable/Android.mk b/services/audiopolicy/engineconfigurable/Android.mk
index 6b18921..08c677e 100644
--- a/services/audiopolicy/engineconfigurable/Android.mk
+++ b/services/audiopolicy/engineconfigurable/Android.mk
@@ -48,6 +48,7 @@
libxml2
LOCAL_SHARED_LIBRARIES := \
+ liblog \
libcutils \
libutils \
liblog \
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.mk b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
index 3cc112f..d031bc3 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.mk
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.mk
@@ -8,7 +8,6 @@
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
- $(TARGET_OUT_HEADERS)/parameter \
$(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/include \
$(TOPDIR)frameworks/av/services/audiopolicy/engineconfigurable/interface \
$(TOPDIR)frameworks/av/services/audiopolicy/utilities/convert \
@@ -17,6 +16,9 @@
LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
+LOCAL_SHARED_LIBRARIES := \
+ libparameter \
+
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
LOCAL_MODULE:= libaudiopolicypfwwrapper
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2f01b02..5ef0216 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1754,7 +1754,7 @@
audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
- mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
+ mInputs.activeInputsCountOnDevices(primaryInputDevices) == 1) {
SoundTrigger::setCaptureState(true);
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 3437e9d..3705e8f 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2962,6 +2962,8 @@
}
}
mRequestQueue.clear();
+
+ Mutex::Autolock al(mTriggerMutex);
mTriggerMap.clear();
if (lastFrameNumber != NULL) {
*lastFrameNumber = mRepeatingLastFrameNumber;
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
index 67976ff..189855c 100644
--- a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-x86.policy
@@ -35,6 +35,7 @@
getgid32: 1
getegid32: 1
getgroups32: 1
+nanosleep: 1
# for attaching to debuggerd on process crash
socketcall: 1
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index 5d01999..e1e1fb1 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -42,7 +42,8 @@
LOCAL_SHARED_LIBRARIES += \
libhwbinder \
- libhidl \
+ libhidlbase \
+ libhidltransport \
libbase \
android.hardware.soundtrigger@2.0 \
android.hardware.audio.common@2.0