Merge "Import revised translations."
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e269c31..ad8c971 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -83,15 +83,61 @@
*/
private long mSeekTime = -1;
+ // TODO: We access the following ThreadLocal variables often, some of them on every update.
+ // If ThreadLocal access is significantly expensive, we may want to put all of these
+ // fields into a structure sot hat we just access ThreadLocal once to get the reference
+ // to that structure, then access the structure directly for each field.
+
// The static sAnimationHandler processes the internal timing loop on which all animations
// are based
- private static AnimationHandler sAnimationHandler;
+ private static ThreadLocal<AnimationHandler> sAnimationHandler =
+ new ThreadLocal<AnimationHandler>();
- // The static list of all active animations
- private static final ArrayList<ValueAnimator> sAnimations = new ArrayList<ValueAnimator>();
+ // The per-thread list of all active animations
+ private static final ThreadLocal<ArrayList<ValueAnimator>> sAnimations =
+ new ThreadLocal<ArrayList<ValueAnimator>>() {
+ @Override
+ protected ArrayList<ValueAnimator> initialValue() {
+ return new ArrayList<ValueAnimator>();
+ }
+ };
- // The set of animations to be started on the next animation frame
- private static final ArrayList<ValueAnimator> sPendingAnimations = new ArrayList<ValueAnimator>();
+ // The per-thread set of animations to be started on the next animation frame
+ private static final ThreadLocal<ArrayList<ValueAnimator>> sPendingAnimations =
+ new ThreadLocal<ArrayList<ValueAnimator>>() {
+ @Override
+ protected ArrayList<ValueAnimator> initialValue() {
+ return new ArrayList<ValueAnimator>();
+ }
+ };
+
+ /**
+ * Internal per-thread collections used to avoid set collisions as animations start and end
+ * while being processed.
+ */
+ private static final ThreadLocal<ArrayList<ValueAnimator>> sDelayedAnims =
+ new ThreadLocal<ArrayList<ValueAnimator>>() {
+ @Override
+ protected ArrayList<ValueAnimator> initialValue() {
+ return new ArrayList<ValueAnimator>();
+ }
+ };
+
+ private static final ThreadLocal<ArrayList<ValueAnimator>> sEndingAnims =
+ new ThreadLocal<ArrayList<ValueAnimator>>() {
+ @Override
+ protected ArrayList<ValueAnimator> initialValue() {
+ return new ArrayList<ValueAnimator>();
+ }
+ };
+
+ private static final ThreadLocal<ArrayList<ValueAnimator>> sReadyAnims =
+ new ThreadLocal<ArrayList<ValueAnimator>>() {
+ @Override
+ protected ArrayList<ValueAnimator> initialValue() {
+ return new ArrayList<ValueAnimator>();
+ }
+ };
// The time interpolator to be used if none is set on the animation
private static final TimeInterpolator sDefaultInterpolator =
@@ -136,14 +182,6 @@
private int mPlayingState = STOPPED;
/**
- * Internal collections used to avoid set collisions as animations start and end while being
- * processed.
- */
- private static final ArrayList<ValueAnimator> sEndingAnims = new ArrayList<ValueAnimator>();
- private static final ArrayList<ValueAnimator> sDelayedAnims = new ArrayList<ValueAnimator>();
- private static final ArrayList<ValueAnimator> sReadyAnims = new ArrayList<ValueAnimator>();
-
- /**
* Flag that denotes whether the animation is set up and ready to go. Used to
* set up animation that has not yet been started.
*/
@@ -609,11 +647,14 @@
@Override
public void handleMessage(Message msg) {
boolean callAgain = true;
+ ArrayList<ValueAnimator> animations = sAnimations.get();
+ ArrayList<ValueAnimator> delayedAnims = sDelayedAnims.get();
switch (msg.what) {
// TODO: should we avoid sending frame message when starting if we
// were already running?
case ANIMATION_START:
- if (sAnimations.size() > 0 || sDelayedAnims.size() > 0) {
+ ArrayList<ValueAnimator> pendingAnimations = sPendingAnimations.get();
+ if (animations.size() > 0 || delayedAnims.size() > 0) {
callAgain = false;
}
// pendingAnims holds any animations that have requested to be started
@@ -621,10 +662,10 @@
// cause more to be added to the pending list (for example, if one animation
// starting triggers another starting). So we loop until sPendingAnimations
// is empty.
- while (sPendingAnimations.size() > 0) {
+ while (pendingAnimations.size() > 0) {
ArrayList<ValueAnimator> pendingCopy =
- (ArrayList<ValueAnimator>) sPendingAnimations.clone();
- sPendingAnimations.clear();
+ (ArrayList<ValueAnimator>) pendingAnimations.clone();
+ pendingAnimations.clear();
int count = pendingCopy.size();
for (int i = 0; i < count; ++i) {
ValueAnimator anim = pendingCopy.get(i);
@@ -633,7 +674,7 @@
anim.mPlayingState == CANCELED) {
anim.startAnimation();
} else {
- sDelayedAnims.add(anim);
+ delayedAnims.add(anim);
}
}
}
@@ -642,45 +683,47 @@
// currentTime holds the common time for all animations processed
// during this frame
long currentTime = AnimationUtils.currentAnimationTimeMillis();
+ ArrayList<ValueAnimator> readyAnims = sReadyAnims.get();
+ ArrayList<ValueAnimator> endingAnims = sEndingAnims.get();
// First, process animations currently sitting on the delayed queue, adding
// them to the active animations if they are ready
- int numDelayedAnims = sDelayedAnims.size();
+ int numDelayedAnims = delayedAnims.size();
for (int i = 0; i < numDelayedAnims; ++i) {
- ValueAnimator anim = sDelayedAnims.get(i);
+ ValueAnimator anim = delayedAnims.get(i);
if (anim.delayedAnimationFrame(currentTime)) {
- sReadyAnims.add(anim);
+ readyAnims.add(anim);
}
}
- int numReadyAnims = sReadyAnims.size();
+ int numReadyAnims = readyAnims.size();
if (numReadyAnims > 0) {
for (int i = 0; i < numReadyAnims; ++i) {
- ValueAnimator anim = sReadyAnims.get(i);
+ ValueAnimator anim = readyAnims.get(i);
anim.startAnimation();
- sDelayedAnims.remove(anim);
+ delayedAnims.remove(anim);
}
- sReadyAnims.clear();
+ readyAnims.clear();
}
// Now process all active animations. The return value from animationFrame()
// tells the handler whether it should now be ended
- int numAnims = sAnimations.size();
+ int numAnims = animations.size();
for (int i = 0; i < numAnims; ++i) {
- ValueAnimator anim = sAnimations.get(i);
+ ValueAnimator anim = animations.get(i);
if (anim.animationFrame(currentTime)) {
- sEndingAnims.add(anim);
+ endingAnims.add(anim);
}
}
- if (sEndingAnims.size() > 0) {
- for (int i = 0; i < sEndingAnims.size(); ++i) {
- sEndingAnims.get(i).endAnimation();
+ if (endingAnims.size() > 0) {
+ for (int i = 0; i < endingAnims.size(); ++i) {
+ endingAnims.get(i).endAnimation();
}
- sEndingAnims.clear();
+ endingAnims.clear();
}
// If there are still active or delayed animations, call the handler again
// after the frameDelay
- if (callAgain && (!sAnimations.isEmpty() || !sDelayedAnims.isEmpty())) {
+ if (callAgain && (!animations.isEmpty() || !delayedAnims.isEmpty())) {
sendEmptyMessageDelayed(ANIMATION_FRAME, Math.max(0, sFrameDelay -
(AnimationUtils.currentAnimationTimeMillis() - currentTime)));
}
@@ -935,13 +978,13 @@
mCurrentIteration = 0;
mPlayingState = STOPPED;
mStartedDelay = false;
- sPendingAnimations.add(this);
- if (sAnimationHandler == null) {
- sAnimationHandler = new AnimationHandler();
+ sPendingAnimations.get().add(this);
+ AnimationHandler animationHandler = sAnimationHandler.get();
+ if (animationHandler == null) {
+ animationHandler = new AnimationHandler();
+ sAnimationHandler.set(animationHandler);
}
- // TODO: does this put too many messages on the queue if the handler
- // is already running?
- sAnimationHandler.sendEmptyMessage(ANIMATION_START);
+ animationHandler.sendEmptyMessage(ANIMATION_START);
}
@Override
@@ -965,14 +1008,16 @@
@Override
public void end() {
- if (!sAnimations.contains(this) && !sPendingAnimations.contains(this)) {
+ if (!sAnimations.get().contains(this) && !sPendingAnimations.get().contains(this)) {
// Special case if the animation has not yet started; get it ready for ending
mStartedDelay = false;
- sPendingAnimations.add(this);
- if (sAnimationHandler == null) {
- sAnimationHandler = new AnimationHandler();
+ sPendingAnimations.get().add(this);
+ AnimationHandler animationHandler = sAnimationHandler.get();
+ if (animationHandler == null) {
+ animationHandler = new AnimationHandler();
+ sAnimationHandler.set(animationHandler);
}
- sAnimationHandler.sendEmptyMessage(ANIMATION_START);
+ animationHandler.sendEmptyMessage(ANIMATION_START);
}
// Just set the ENDED flag - this causes the animation to end the next time a frame
// is processed.
@@ -1009,7 +1054,7 @@
* called on the UI thread.
*/
private void endAnimation() {
- sAnimations.remove(this);
+ sAnimations.get().remove(this);
mPlayingState = STOPPED;
if (mListeners != null) {
ArrayList<AnimatorListener> tmpListeners =
@@ -1026,7 +1071,7 @@
*/
private void startAnimation() {
initAnimation();
- sAnimations.add(this);
+ sAnimations.get().add(this);
if (mStartDelay > 0 && mListeners != null) {
// Listeners were already notified in start() if startDelay is 0; this is
// just for delayed animations
@@ -1225,6 +1270,6 @@
* @hide
*/
public static int getCurrentAnimationsCount() {
- return sAnimations.size();
+ return sAnimations.get().size();
}
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 378a8bd..33f88d8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1228,7 +1228,6 @@
*/
protected void onPause() {
mCalled = true;
- QueuedWork.waitToFinish();
}
/**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2abe822..c5badaf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2347,6 +2347,9 @@
r.activity.mConfigChangeFlags |= configChanges;
Bundle state = performPauseActivity(token, finished, true);
+ // Make sure any pending writes are now committed.
+ QueuedWork.waitToFinish();
+
// Tell the activity manager we have paused.
try {
ActivityManagerNative.getDefault().activityPaused(token, state);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6897537..257dbf0 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6903,14 +6903,14 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
- if (action == MotionEvent.ACTION_DOWN) {
- if (mInsertionPointCursorController != null) {
- mInsertionPointCursorController.onTouchEvent(event);
- }
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.onTouchEvent(event);
- }
+ if (mInsertionPointCursorController != null) {
+ mInsertionPointCursorController.onTouchEvent(event);
+ }
+ if (mSelectionModifierCursorController != null) {
+ mSelectionModifierCursorController.onTouchEvent(event);
+ }
+ if (action == MotionEvent.ACTION_DOWN) {
// Reset this state; it will be re-set if super.onTouchEvent
// causes focus to move to the view.
mTouchFocusSelected = false;
@@ -6931,13 +6931,6 @@
if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
&& mText instanceof Spannable && mLayout != null) {
- if (mInsertionPointCursorController != null) {
- mInsertionPointCursorController.onTouchEvent(event);
- }
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.onTouchEvent(event);
- }
-
boolean handled = false;
// Save previous selection, in case this event is used to show the IME.
@@ -6946,7 +6939,7 @@
final int oldScrollX = mScrollX;
final int oldScrollY = mScrollY;
-
+
if (mMovement != null) {
handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
}
@@ -7981,7 +7974,7 @@
}
mDrawable = mSelectHandleLeft;
handleWidth = mDrawable.getIntrinsicWidth();
- mHotspotX = handleWidth / 4 * 3;
+ mHotspotX = (handleWidth * 3) / 4;
break;
}
@@ -8264,6 +8257,11 @@
// Whether selection anchors are active
private boolean mIsShowing;
+ // Double tap detection
+ private long mPreviousTapUpTime = 0;
+ private int mPreviousTapPositionX;
+ private int mPreviousTapPositionY;
+
private static final int DELAY_BEFORE_FADE_OUT = 4100;
private final Runnable mHider = new Runnable() {
@@ -8369,6 +8367,26 @@
// Remember finger down position, to be able to start selection from there
mMinTouchOffset = mMaxTouchOffset = getOffset(x, y);
+ // Double tap detection
+ long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
+ if (duration <= ViewConfiguration.getDoubleTapTimeout()) {
+ final int deltaX = x - mPreviousTapPositionX;
+ final int deltaY = y - mPreviousTapPositionY;
+ final int distanceSquared = deltaX * deltaX + deltaY * deltaY;
+ final int doubleTapSlop =
+ ViewConfiguration.get(getContext()).getScaledDoubleTapSlop();
+ final int slopSquared = doubleTapSlop * doubleTapSlop;
+ if (distanceSquared < slopSquared) {
+ startSelectionActionMode();
+ // Hacky: onTapUpEvent will open a context menu with cut/copy
+ // Prevent this by hiding handles which will be revived instead.
+ hide();
+ }
+ }
+
+ mPreviousTapPositionX = x;
+ mPreviousTapPositionY = y;
+
break;
case MotionEvent.ACTION_POINTER_DOWN:
@@ -8380,6 +8398,10 @@
updateMinAndMaxOffsets(event);
}
break;
+
+ case MotionEvent.ACTION_UP:
+ mPreviousTapUpTime = SystemClock.uptimeMillis();
+ break;
}
}
return false;
diff --git a/core/res/res/anim/wallpaper_intra_close_enter.xml b/core/res/res/anim/wallpaper_intra_close_enter.xml
index 5c4f5c9..73bf9a3 100644
--- a/core/res/res/anim/wallpaper_intra_close_enter.xml
+++ b/core/res/res/anim/wallpaper_intra_close_enter.xml
@@ -20,12 +20,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
- <scale android:fromXScale="2.0" android:toXScale="1.0"
- android:fromYScale="2.0" android:toYScale="1.0"
- android:pivotX="100%p" android:pivotY="50%p"
- android:duration="@android:integer/config_mediumAnimTime" />
- <translate android:fromXDelta="-150%p" android:toXDelta="0%p"
- android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="0.5" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/wallpaper_intra_close_exit.xml b/core/res/res/anim/wallpaper_intra_close_exit.xml
index acaf773..d43660e 100644
--- a/core/res/res/anim/wallpaper_intra_close_exit.xml
+++ b/core/res/res/anim/wallpaper_intra_close_exit.xml
@@ -18,13 +18,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@anim/accelerate_interpolator">
- <scale android:fromXScale="1.0" android:toXScale=".5"
- android:fromYScale="1.0" android:toYScale=".5"
- android:pivotX="100%p" android:pivotY="50%p"
- android:duration="@android:integer/config_mediumAnimTime" />
- <translate android:fromXDelta="0%p" android:toXDelta="100%p"
- android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:interpolator="@anim/decelerate_interpolator">
+ <alpha android:fromAlpha="0.5" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/wallpaper_intra_open_enter.xml b/core/res/res/anim/wallpaper_intra_open_enter.xml
index 81c9991..c85ca4c 100644
--- a/core/res/res/anim/wallpaper_intra_open_enter.xml
+++ b/core/res/res/anim/wallpaper_intra_open_enter.xml
@@ -19,12 +19,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <scale android:fromXScale=".5" android:toXScale="1.0"
- android:fromYScale=".5" android:toYScale="1.0"
- android:pivotX="100%p" android:pivotY="50%p"
- android:duration="@android:integer/config_mediumAnimTime" />
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="0.5" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/wallpaper_intra_open_exit.xml b/core/res/res/anim/wallpaper_intra_open_exit.xml
index 28c4287..eaeac22 100644
--- a/core/res/res/anim/wallpaper_intra_open_exit.xml
+++ b/core/res/res/anim/wallpaper_intra_open_exit.xml
@@ -18,14 +18,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@anim/accelerate_interpolator"
+ android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
- <scale android:fromXScale="1.0" android:toXScale="2.0"
- android:fromYScale="1.0" android:toYScale="2.0"
- android:pivotX="100%p" android:pivotY="50%p"
- android:duration="@android:integer/config_mediumAnimTime" />
- <translate android:fromXDelta="0" android:toXDelta="-150%p"
- android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.5" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index b0d2c64..bbde516 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -18,18 +18,381 @@
#include "ARTPSource.h"
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include <ctype.h>
namespace android {
-AMPEG4AudioAssembler::AMPEG4AudioAssembler(const sp<AMessage> ¬ify)
+static bool GetAttribute(const char *s, const char *key, AString *value) {
+ value->clear();
+
+ size_t keyLen = strlen(key);
+
+ for (;;) {
+ while (isspace(*s)) {
+ ++s;
+ }
+
+ const char *colonPos = strchr(s, ';');
+
+ size_t len =
+ (colonPos == NULL) ? strlen(s) : colonPos - s;
+
+ if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
+ value->setTo(&s[keyLen + 1], len - keyLen - 1);
+ return true;
+ }
+
+ if (colonPos == NULL) {
+ return false;
+ }
+
+ s = colonPos + 1;
+ }
+}
+
+static sp<ABuffer> decodeHex(const AString &s) {
+ if ((s.size() % 2) != 0) {
+ return NULL;
+ }
+
+ size_t outLen = s.size() / 2;
+ sp<ABuffer> buffer = new ABuffer(outLen);
+ uint8_t *out = buffer->data();
+
+ uint8_t accum = 0;
+ for (size_t i = 0; i < s.size(); ++i) {
+ char c = s.c_str()[i];
+ unsigned value;
+ if (c >= '0' && c <= '9') {
+ value = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ value = c - 'a' + 10;
+ } else if (c >= 'A' && c <= 'F') {
+ value = c - 'A' + 10;
+ } else {
+ return NULL;
+ }
+
+ accum = (accum << 4) | value;
+
+ if (i & 1) {
+ *out++ = accum;
+
+ accum = 0;
+ }
+ }
+
+ return buffer;
+}
+
+static status_t parseAudioObjectType(
+ ABitReader *bits, unsigned *audioObjectType) {
+ *audioObjectType = bits->getBits(5);
+ if ((*audioObjectType) == 31) {
+ *audioObjectType = 32 + bits->getBits(6);
+ }
+
+ return OK;
+}
+
+static status_t parseGASpecificConfig(
+ ABitReader *bits,
+ unsigned audioObjectType, unsigned channelConfiguration) {
+ unsigned frameLengthFlag = bits->getBits(1);
+ unsigned dependsOnCoreCoder = bits->getBits(1);
+ if (dependsOnCoreCoder) {
+ /* unsigned coreCoderDelay = */bits->getBits(1);
+ }
+ unsigned extensionFlag = bits->getBits(1);
+
+ if (!channelConfiguration) {
+ // program_config_element
+ return ERROR_UNSUPPORTED; // XXX to be implemented
+ }
+
+ if (audioObjectType == 6 || audioObjectType == 20) {
+ /* unsigned layerNr = */bits->getBits(3);
+ }
+
+ if (extensionFlag) {
+ if (audioObjectType == 22) {
+ /* unsigned numOfSubFrame = */bits->getBits(5);
+ /* unsigned layerLength = */bits->getBits(11);
+ } else if (audioObjectType == 17 || audioObjectType == 19
+ || audioObjectType == 20 || audioObjectType == 23) {
+ /* unsigned aacSectionDataResilienceFlag = */bits->getBits(1);
+ /* unsigned aacScalefactorDataResilienceFlag = */bits->getBits(1);
+ /* unsigned aacSpectralDataResilienceFlag = */bits->getBits(1);
+ }
+
+ unsigned extensionFlag3 = bits->getBits(1);
+ CHECK_EQ(extensionFlag3, 0u); // TBD in version 3
+ }
+
+ return OK;
+}
+
+static status_t parseAudioSpecificConfig(ABitReader *bits) {
+ unsigned audioObjectType;
+ CHECK_EQ(parseAudioObjectType(bits, &audioObjectType), (status_t)OK);
+
+ unsigned samplingFreqIndex = bits->getBits(4);
+ if (samplingFreqIndex == 0x0f) {
+ /* unsigned samplingFrequency = */bits->getBits(24);
+ }
+
+ unsigned channelConfiguration = bits->getBits(4);
+
+ unsigned extensionAudioObjectType = 0;
+ unsigned sbrPresent = 0;
+
+ if (audioObjectType == 5) {
+ extensionAudioObjectType = audioObjectType;
+ sbrPresent = 1;
+ unsigned extensionSamplingFreqIndex = bits->getBits(4);
+ if (extensionSamplingFreqIndex == 0x0f) {
+ /* unsigned extensionSamplingFrequency = */bits->getBits(24);
+ }
+ CHECK_EQ(parseAudioObjectType(bits, &audioObjectType), (status_t)OK);
+ }
+
+ CHECK((audioObjectType >= 1 && audioObjectType <= 4)
+ || (audioObjectType >= 6 && audioObjectType <= 7)
+ || audioObjectType == 17
+ || (audioObjectType >= 19 && audioObjectType <= 23));
+
+ CHECK_EQ(parseGASpecificConfig(
+ bits, audioObjectType, channelConfiguration), (status_t)OK);
+
+ if (audioObjectType == 17
+ || (audioObjectType >= 19 && audioObjectType <= 27)) {
+ unsigned epConfig = bits->getBits(2);
+ if (epConfig == 2 || epConfig == 3) {
+ // ErrorProtectionSpecificConfig
+ return ERROR_UNSUPPORTED; // XXX to be implemented
+
+ if (epConfig == 3) {
+ unsigned directMapping = bits->getBits(1);
+ CHECK_EQ(directMapping, 1u);
+ }
+ }
+ }
+
+#if 0
+ // This is not supported here as the upper layers did not explicitly
+ // signal the length of AudioSpecificConfig.
+
+ if (extensionAudioObjectType != 5 && bits->numBitsLeft() >= 16) {
+ unsigned syncExtensionType = bits->getBits(11);
+ if (syncExtensionType == 0x2b7) {
+ CHECK_EQ(parseAudioObjectType(bits, &extensionAudioObjectType),
+ (status_t)OK);
+
+ sbrPresent = bits->getBits(1);
+
+ if (sbrPresent == 1) {
+ unsigned extensionSamplingFreqIndex = bits->getBits(4);
+ if (extensionSamplingFreqIndex == 0x0f) {
+ /* unsigned extensionSamplingFrequency = */bits->getBits(24);
+ }
+ }
+ }
+ }
+#endif
+
+ return OK;
+}
+
+static status_t parseStreamMuxConfig(
+ ABitReader *bits,
+ unsigned *numSubFrames,
+ unsigned *frameLengthType,
+ bool *otherDataPresent,
+ unsigned *otherDataLenBits) {
+ unsigned audioMuxVersion = bits->getBits(1);
+
+ unsigned audioMuxVersionA = 0;
+ if (audioMuxVersion == 1) {
+ audioMuxVersionA = bits->getBits(1);
+ }
+
+ CHECK_EQ(audioMuxVersionA, 0u); // otherwise future spec
+
+ if (audioMuxVersion != 0) {
+ return ERROR_UNSUPPORTED; // XXX to be implemented;
+ }
+ CHECK_EQ(audioMuxVersion, 0u); // XXX to be implemented
+
+ unsigned allStreamsSameTimeFraming = bits->getBits(1);
+ CHECK_EQ(allStreamsSameTimeFraming, 1u); // There's only one stream.
+
+ *numSubFrames = bits->getBits(6);
+ unsigned numProgram = bits->getBits(4);
+ CHECK_EQ(numProgram, 0u); // disabled in RTP LATM
+
+ unsigned numLayer = bits->getBits(3);
+ CHECK_EQ(numLayer, 0u); // disabled in RTP LATM
+
+ if (audioMuxVersion == 0) {
+ // AudioSpecificConfig
+ CHECK_EQ(parseAudioSpecificConfig(bits), (status_t)OK);
+ } else {
+ TRESPASS(); // XXX to be implemented
+ }
+
+ *frameLengthType = bits->getBits(3);
+ switch (*frameLengthType) {
+ case 0:
+ {
+ /* unsigned bufferFullness = */bits->getBits(8);
+
+ // The "coreFrameOffset" does not apply since there's only
+ // a single layer.
+ break;
+ }
+
+ case 1:
+ {
+ /* unsigned frameLength = */bits->getBits(9);
+ break;
+ }
+
+ case 3:
+ case 4:
+ case 5:
+ {
+ /* unsigned CELPframeLengthTableIndex = */bits->getBits(6);
+ break;
+ }
+
+ case 6:
+ case 7:
+ {
+ /* unsigned HVXCframeLengthTableIndex = */bits->getBits(1);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ *otherDataPresent = bits->getBits(1);
+ *otherDataLenBits = 0;
+ if (*otherDataPresent) {
+ if (audioMuxVersion == 1) {
+ TRESPASS(); // XXX to be implemented
+ } else {
+ *otherDataLenBits = 0;
+
+ unsigned otherDataLenEsc;
+ do {
+ (*otherDataLenBits) <<= 8;
+ otherDataLenEsc = bits->getBits(1);
+ unsigned otherDataLenTmp = bits->getBits(8);
+ (*otherDataLenBits) += otherDataLenTmp;
+ } while (otherDataLenEsc);
+ }
+ }
+
+ unsigned crcCheckPresent = bits->getBits(1);
+ if (crcCheckPresent) {
+ /* unsigned crcCheckSum = */bits->getBits(8);
+ }
+
+ return OK;
+}
+
+sp<ABuffer> AMPEG4AudioAssembler::removeLATMFraming(const sp<ABuffer> &buffer) {
+ CHECK(!mMuxConfigPresent); // XXX to be implemented
+
+ sp<ABuffer> out = new ABuffer(buffer->size());
+ out->setRange(0, 0);
+
+ size_t offset = 0;
+ uint8_t *ptr = buffer->data();
+
+ for (size_t i = 0; i <= mNumSubFrames; ++i) {
+ // parse PayloadLengthInfo
+
+ unsigned payloadLength = 0;
+
+ switch (mFrameLengthType) {
+ case 0:
+ {
+ unsigned muxSlotLengthBytes = 0;
+ unsigned tmp;
+ do {
+ CHECK_LT(offset, buffer->size());
+ tmp = ptr[offset++];
+ muxSlotLengthBytes += tmp;
+ } while (tmp == 0xff);
+
+ payloadLength = muxSlotLengthBytes;
+ break;
+ }
+
+ default:
+ TRESPASS(); // XXX to be implemented
+ break;
+ }
+
+ CHECK_LE(offset + payloadLength, buffer->size());
+
+ memcpy(out->data() + out->size(), &ptr[offset], payloadLength);
+ out->setRange(0, out->size() + payloadLength);
+
+ offset += payloadLength;
+
+ if (mOtherDataPresent) {
+ // We want to stay byte-aligned.
+
+ CHECK((mOtherDataLenBits % 8) == 0);
+ CHECK_LE(offset + (mOtherDataLenBits / 8), buffer->size());
+ offset += mOtherDataLenBits / 8;
+ }
+ }
+
+ CHECK_EQ(offset, buffer->size());
+
+ return out;
+}
+
+AMPEG4AudioAssembler::AMPEG4AudioAssembler(
+ const sp<AMessage> ¬ify, const AString ¶ms)
: mNotifyMsg(notify),
+ mMuxConfigPresent(false),
mAccessUnitRTPTime(0),
mNextExpectedSeqNoValid(false),
mNextExpectedSeqNo(0),
mAccessUnitDamaged(false) {
+ AString val;
+ if (!GetAttribute(params.c_str(), "cpresent", &val)) {
+ mMuxConfigPresent = true;
+ } else if (val == "0") {
+ mMuxConfigPresent = false;
+ } else {
+ CHECK(val == "1");
+ mMuxConfigPresent = true;
+ }
+
+ CHECK(GetAttribute(params.c_str(), "config", &val));
+
+ sp<ABuffer> config = decodeHex(val);
+ CHECK(config != NULL);
+
+ ABitReader bits(config->data(), config->size());
+ status_t err = parseStreamMuxConfig(
+ &bits, &mNumSubFrames, &mFrameLengthType,
+ &mOtherDataPresent, &mOtherDataLenBits);
+
+ CHECK_EQ(err, (status_t)NO_ERROR);
}
AMPEG4AudioAssembler::~AMPEG4AudioAssembler() {
@@ -108,13 +471,7 @@
while (it != mPackets.end()) {
const sp<ABuffer> &unit = *it;
- size_t n = 0;
- while (unit->data()[n] == 0xff) {
- ++n;
- }
- ++n;
-
- totalSize += unit->size() - n;
+ totalSize += unit->size();
++it;
}
@@ -124,20 +481,13 @@
while (it != mPackets.end()) {
const sp<ABuffer> &unit = *it;
- size_t n = 0;
- while (unit->data()[n] == 0xff) {
- ++n;
- }
- ++n;
-
memcpy((uint8_t *)accessUnit->data() + offset,
- unit->data() + n, unit->size() - n);
-
- offset += unit->size() - n;
+ unit->data(), unit->size());
++it;
}
+ accessUnit = removeLATMFraming(accessUnit);
CopyTimes(accessUnit, *mPackets.begin());
#if 0
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.h b/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
index bf9f204..9cef94c 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
@@ -27,9 +27,11 @@
namespace android {
struct AMessage;
+struct AString;
struct AMPEG4AudioAssembler : public ARTPAssembler {
- AMPEG4AudioAssembler(const sp<AMessage> ¬ify);
+ AMPEG4AudioAssembler(
+ const sp<AMessage> ¬ify, const AString ¶ms);
protected:
virtual ~AMPEG4AudioAssembler();
@@ -40,6 +42,13 @@
private:
sp<AMessage> mNotifyMsg;
+
+ bool mMuxConfigPresent;
+ unsigned mNumSubFrames;
+ unsigned mFrameLengthType;
+ bool mOtherDataPresent;
+ unsigned mOtherDataLenBits;
+
uint32_t mAccessUnitRTPTime;
bool mNextExpectedSeqNoValid;
uint32_t mNextExpectedSeqNo;
@@ -49,6 +58,8 @@
AssemblyStatus addPacket(const sp<ARTPSource> &source);
void submitAccessUnit();
+ sp<ABuffer> removeLATMFraming(const sp<ABuffer> &buffer);
+
DISALLOW_EVIL_CONSTRUCTORS(AMPEG4AudioAssembler);
};
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 2518264..5aae4e7 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -57,7 +57,7 @@
mAssembler = new AAVCAssembler(notify);
mIssueFIRRequests = true;
} else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) {
- mAssembler = new AMPEG4AudioAssembler(notify);
+ mAssembler = new AMPEG4AudioAssembler(notify, params);
} else if (!strncmp(desc.c_str(), "H263-1998/", 10)
|| !strncmp(desc.c_str(), "H263-2000/", 10)) {
mAssembler = new AH263Assembler(notify);
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 880aa85..547fbab 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -53,7 +53,6 @@
mFormats.push(AString("[root]"));
AString desc((const char *)data, size);
- LOGI("%s", desc.c_str());
size_t i = 0;
for (;;) {
@@ -76,6 +75,8 @@
return false;
}
+ LOGI("%s", line.c_str());
+
switch (line.c_str()[0]) {
case 'v':
{
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index e44c485..7c496e7 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -546,7 +546,9 @@
if (!dirtyRegion.isEmpty()) {
dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
if (previousBuffer) {
- const Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
+ // This was const Region copyBack, but that causes an
+ // internal compile error on simulator builds
+ /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
if (!copyBack.isEmpty()) {
void* prevBits;
if (lock(previousBuffer,