am 43b57ec4: Fix error printing if no command string is set.
* commit '43b57ec48ec7652addc11bbc9fef652c2394b7f5':
Fix error printing if no command string is set.
diff --git a/api/current.txt b/api/current.txt
index 92969f6..662ebcd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24082,6 +24082,8 @@
method public int getCurrentItemIndex();
method public int getFromIndex();
method public int getItemCount();
+ method public int getMaxScrollX();
+ method public int getMaxScrollY();
method public android.os.Parcelable getParcelableData();
method public int getRemovedCount();
method public int getScrollX();
@@ -24108,6 +24110,8 @@
method public void setFromIndex(int);
method public void setFullScreen(boolean);
method public void setItemCount(int);
+ method public void setMaxScrollX(int);
+ method public void setMaxScrollY(int);
method public void setParcelableData(android.os.Parcelable);
method public void setPassword(boolean);
method public void setRemovedCount(int);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 528d197..7cb8f62 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -30,7 +30,6 @@
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ALooper.h>
-#include "include/ARTSPController.h"
#include "include/LiveSession.h"
#include "include/NuCachedSource2.h"
#include <media/stagefright/AudioPlayer.h>
@@ -636,7 +635,6 @@
gDisplayHistogram = false;
sp<ALooper> looper;
- sp<ARTSPController> rtspController;
sp<LiveSession> liveSession;
int res;
@@ -948,7 +946,6 @@
sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
if (strncasecmp(filename, "sine:", 5)
- && strncasecmp(filename, "rtsp://", 7)
&& strncasecmp(filename, "httplive://", 11)
&& dataSource == NULL) {
fprintf(stderr, "Unable to create data source.\n");
@@ -984,23 +981,7 @@
} else {
sp<MediaExtractor> extractor;
- if (!strncasecmp("rtsp://", filename, 7)) {
- if (looper == NULL) {
- looper = new ALooper;
- looper->start();
- }
-
- rtspController = new ARTSPController(looper);
- status_t err = rtspController->connect(filename);
- if (err != OK) {
- fprintf(stderr, "could not connect to rtsp server.\n");
- return -1;
- }
-
- extractor = rtspController.get();
-
- syncInfoPresent = false;
- } else if (!strncasecmp("httplive://", filename, 11)) {
+ if (!strncasecmp("httplive://", filename, 11)) {
String8 uri("http://");
uri.append(filename + 11);
@@ -1021,6 +1002,7 @@
syncInfoPresent = false;
} else {
extractor = MediaExtractor::Create(dataSource);
+
if (extractor == NULL) {
fprintf(stderr, "could not create extractor.\n");
return -1;
@@ -1116,13 +1098,6 @@
} else {
playSource(&client, mediaSource);
}
-
- if (rtspController != NULL) {
- rtspController->disconnect();
- rtspController.clear();
-
- sleep(3);
- }
}
if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) {
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index fe0106d..33310df 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -768,61 +768,6 @@
}
/**
- * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
- * @deprecated use {@link CreateNdefMessageCallback} or {@link OnNdefPushCompleteCallback}
- * @hide
- */
- @Deprecated
- public interface NdefPushCallback {
- /**
- * @deprecated use {@link CreateNdefMessageCallback} instead
- */
- @Deprecated
- NdefMessage createMessage();
- /**
- * @deprecated use{@link OnNdefPushCompleteCallback} instead
- */
- @Deprecated
- void onMessagePushed();
- }
-
- /**
- * TODO: Remove this
- * Converts new callbacks to old callbacks.
- */
- static final class LegacyCallbackWrapper implements CreateNdefMessageCallback,
- OnNdefPushCompleteCallback {
- final NdefPushCallback mLegacyCallback;
- LegacyCallbackWrapper(NdefPushCallback legacyCallback) {
- mLegacyCallback = legacyCallback;
- }
- @Override
- public void onNdefPushComplete(NfcEvent event) {
- mLegacyCallback.onMessagePushed();
- }
- @Override
- public NdefMessage createNdefMessage(NfcEvent event) {
- return mLegacyCallback.createMessage();
- }
- }
-
- /**
- * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
- * @deprecated use {@link #setNdefPushMessageCallback} instead
- * @hide
- */
- @Deprecated
- public void enableForegroundNdefPush(Activity activity, final NdefPushCallback callback) {
- if (activity == null || callback == null) {
- throw new NullPointerException();
- }
- enforceResumed(activity);
- LegacyCallbackWrapper callbackWrapper = new LegacyCallbackWrapper(callback);
- mNfcActivityManager.setNdefPushMessageCallback(activity, callbackWrapper);
- mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callbackWrapper);
- }
-
- /**
* Enable NDEF Push feature.
* <p>This API is for the Settings application.
* @hide
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 4d7a9bb..cc2fa85 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -35,7 +35,6 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@@ -902,15 +901,13 @@
return false;
}
+ // Thread policy controls BlockGuard.
int threadPolicyMask = StrictMode.DETECT_DISK_WRITE |
StrictMode.DETECT_DISK_READ |
StrictMode.DETECT_NETWORK;
if (!IS_USER_BUILD) {
threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
- if (IS_ENG_BUILD) {
- threadPolicyMask |= StrictMode.PENALTY_LOG;
- }
}
if (doFlashes) {
threadPolicyMask |= StrictMode.PENALTY_FLASH;
@@ -918,6 +915,8 @@
StrictMode.setThreadPolicyMask(threadPolicyMask);
+ // VM Policy controls CloseGuard, detection of Activity leaks,
+ // and instance counting.
if (IS_USER_BUILD) {
setCloseGuardEnabled(false);
} else {
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index d1dc6e5..0640d7e 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -658,6 +658,24 @@
return _result;
}
+ @Override
+ public int verifyEncryptionPassword(String password) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(password);
+ mRemote.transact(Stub.TRANSACTION_verifyEncryptionPassword, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
public Parcelable[] getVolumeList() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -761,6 +779,8 @@
static final int TRANSACTION_getEncryptionState = IBinder.FIRST_CALL_TRANSACTION + 31;
+ static final int TRANSACTION_verifyEncryptionPassword = IBinder.FIRST_CALL_TRANSACTION + 32;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1286,6 +1306,12 @@
public int changeEncryptionPassword(String password) throws RemoteException;
/**
+ * Verify the encryption password against the stored volume. This method
+ * may only be called by the system process.
+ */
+ public int verifyEncryptionPassword(String password) throws RemoteException;
+
+ /**
* Returns list of all mountable volumes.
*/
public Parcelable[] getVolumeList() throws RemoteException;
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 4b4d308..d7060c1 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -300,8 +300,25 @@
public static final String CALENDAR_COLOR = "calendar_color";
/**
+ * An index for looking up a color from the {@link Colors} table. NULL
+ * or an empty string are reserved for indicating that the calendar does
+ * not use an index for looking up the color. The provider will update
+ * {@link #CALENDAR_COLOR} automatically when a valid index is written
+ * to this column. @see Colors
+ * <P>
+ * Type: TEXT
+ * </P>
+ * TODO UNHIDE
+ *
+ * @hide
+ */
+ public static final String CALENDAR_COLOR_INDEX = "calendar_color_index";
+
+ /**
* The display name of the calendar. Column name.
- * <P>Type: TEXT</P>
+ * <P>
+ * Type: TEXT
+ * </P>
*/
public static final String CALENDAR_DISPLAY_NAME = "calendar_displayName";
@@ -392,6 +409,34 @@
* <P>Type: TEXT</P>
*/
public static final String ALLOWED_REMINDERS = "allowedReminders";
+
+ /**
+ * A comma separated list of availability types supported for this
+ * calendar in the format "#,#,#". Valid types are
+ * {@link Events#AVAILABILITY_BUSY}, {@link Events#AVAILABILITY_FREE},
+ * {@link Events#AVAILABILITY_TENTATIVE}. Setting this field to only
+ * {@link Events#AVAILABILITY_BUSY} should be used to indicate that
+ * changing the availability is not supported.
+ *
+ * TODO UNHIDE, Update Calendars doc
+ *
+ * @hide
+ */
+ public static final String ALLOWED_AVAILABILITY = "allowedAvailability";
+
+ /**
+ * A comma separated list of attendee types supported for this calendar
+ * in the format "#,#,#". Valid types are {@link Attendees#TYPE_NONE},
+ * {@link Attendees#TYPE_OPTIONAL}, {@link Attendees#TYPE_REQUIRED},
+ * {@link Attendees#TYPE_RESOURCE}. Setting this field to only
+ * {@link Attendees#TYPE_NONE} should be used to indicate that changing
+ * the attendee type is not supported.
+ *
+ * TODO UNHIDE, Update Calendars doc
+ *
+ * @hide
+ */
+ public static final String ALLOWED_ATTENDEE_TYPES = "allowedAttendeeTypes";
}
/**
@@ -688,13 +733,22 @@
/**
* The type of attendee. Column name.
- * <P>Type: Integer (one of {@link #TYPE_REQUIRED}, {@link #TYPE_OPTIONAL})</P>
+ * <P>
+ * Type: Integer (one of {@link #TYPE_REQUIRED}, {@link #TYPE_OPTIONAL}
+ * </P>
*/
public static final String ATTENDEE_TYPE = "attendeeType";
public static final int TYPE_NONE = 0;
public static final int TYPE_REQUIRED = 1;
public static final int TYPE_OPTIONAL = 2;
+ /**
+ * This specifies that an attendee is a resource, such as a room, and
+ * not an actual person. TODO UNHIDE and add to ATTENDEE_TYPE comment
+ *
+ * @hide
+ */
+ public static final int TYPE_RESOURCE = 3;
/**
* The attendance status of the attendee. Column name.
@@ -787,13 +841,26 @@
public static final String EVENT_LOCATION = "eventLocation";
/**
- * A secondary color for the individual event. Reserved for future use.
- * Column name.
+ * A secondary color for the individual event. This should only be
+ * updated by the sync adapter for a given account.
* <P>Type: INTEGER</P>
*/
public static final String EVENT_COLOR = "eventColor";
/**
+ * A secondary color index for the individual event. NULL or an empty
+ * string are reserved for indicating that the event does not use an
+ * index for looking up the color. The provider will update
+ * {@link #EVENT_COLOR} automatically when a valid index is written to
+ * this column. @see Colors
+ * <P>Type: TEXT</P>
+ * TODO UNHIDE
+ *
+ * @hide
+ */
+ public static final String EVENT_COLOR_INDEX = "eventColor_index";
+
+ /**
* The event status. Column name.
* <P>Type: INTEGER (one of {@link #STATUS_TENTATIVE}...)</P>
*/
@@ -964,6 +1031,15 @@
* other events.
*/
public static final int AVAILABILITY_FREE = 1;
+ /**
+ * Indicates that the owner's availability may change, but should be
+ * considered busy time that will conflict.
+ *
+ * TODO UNHIDE
+ *
+ * @hide
+ */
+ public static final int AVAILABILITY_TENTATIVE = 2;
/**
* Whether the event has an alarm or not. Column name.
@@ -2224,6 +2300,91 @@
}
}
+ /**
+ * @hide
+ * TODO UNHIDE
+ */
+ protected interface ColorsColumns extends SyncStateContract.Columns {
+
+ /**
+ * The type of color, which describes how it should be used. Valid types
+ * are {@link #TYPE_CALENDAR} and {@link #TYPE_EVENT}. Column name.
+ * <P>
+ * Type: INTEGER (NOT NULL)
+ * </P>
+ */
+ public static final String COLOR_TYPE = "color_type";
+
+ /**
+ * This indicateds a color that can be used for calendars.
+ */
+ public static final int TYPE_CALENDAR = 0;
+ /**
+ * This indicates a color that can be used for events.
+ */
+ public static final int TYPE_EVENT = 1;
+
+ /**
+ * The index used to reference this color. This can be any non-empty
+ * string, but must be unique for a given {@link #ACCOUNT_TYPE} and
+ * {@link #ACCOUNT_NAME} . Column name.
+ * <P>
+ * Type: TEXT
+ * </P>
+ */
+ public static final String COLOR_INDEX = "color_index";
+
+ /**
+ * The version of this color that will work with dark text as an 8-bit
+ * ARGB integer value. Colors should specify alpha as fully opaque (eg
+ * 0xFF993322) as the alpha may be ignored or modified for display.
+ * Column name.
+ * <P>
+ * Type: INTEGER (NOT NULL)
+ * </P>
+ */
+ public static final String COLOR_LIGHT = "color_light";
+
+ /**
+ * The version of this color that will work with light text as an 8-bit
+ * ARGB integer value. Colors should specify alpha as fully opaque (eg
+ * 0xFF993322) as the alpha may be ignored or modified for display.
+ * Column name.
+ * <P>
+ * Type: INTEGER (NOT NULL)
+ * </P>
+ */
+ public static final String COLOR_DARK = "color_dark";
+
+ }
+
+ /**
+ * Fields for accessing colors available for a given account. Colors are
+ * referenced by {@link #COLOR_INDEX} which must be unique for a given
+ * account name/type. These values should only be updated by the sync
+ * adapter.
+ * TODO UNHIDE
+ *
+ * @hide
+ */
+ public static final class Colors implements ColorsColumns {
+ /**
+ * @hide
+ */
+ public static final String TABLE_NAME = "Colors";
+ /**
+ * The Uri for querying color information
+ */
+ @SuppressWarnings("hiding")
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/colors");
+
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Colors() {
+ }
+ }
+
protected interface ExtendedPropertiesColumns {
/**
* The event the extended property belongs to. Column name.
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index fe06d98..a4e0688 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -391,8 +391,6 @@
* Gets the max scroll offset of the source left edge in pixels.
*
* @return The max scroll.
- *
- * @hide
*/
public int getMaxScrollX() {
return mMaxScrollX;
@@ -401,8 +399,6 @@
* Sets the max scroll offset of the source left edge in pixels.
*
* @param maxScrollX The max scroll.
- *
- * @hide
*/
public void setMaxScrollX(int maxScrollX) {
enforceNotSealed();
@@ -413,8 +409,6 @@
* Gets the max scroll offset of the source top edge in pixels.
*
* @return The max scroll.
- *
- * @hide
*/
public int getMaxScrollY() {
return mMaxScrollY;
@@ -424,8 +418,6 @@
* Sets the max scroll offset of the source top edge in pixels.
*
* @param maxScrollY The max scroll.
- *
- * @hide
*/
public void setMaxScrollY(int maxScrollY) {
enforceNotSealed();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8da1820..a851fb4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -4499,6 +4499,9 @@
if (mHeldMotionless == MOTIONLESS_FALSE) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler
.obtainMessage(DRAG_HELD_MOTIONLESS), MOTIONLESS_TIME);
+ mPrivateHandler.sendMessageDelayed(mPrivateHandler
+ .obtainMessage(AWAKEN_SCROLL_BARS),
+ ViewConfiguration.getScrollDefaultDelay());
mHeldMotionless = MOTIONLESS_PENDING;
}
}
@@ -5996,6 +5999,7 @@
mTouchMode = TOUCH_DRAG_START_MODE;
mConfirmMove = true;
mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
+ nativeSetIsScrolling(false);
} else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
@@ -6278,9 +6282,16 @@
}
mLastTouchX = x;
mLastTouchY = y;
- if ((deltaX | deltaY) != 0) {
+
+ if (deltaX * deltaX + deltaY * deltaY > mTouchSlopSquare) {
mHeldMotionless = MOTIONLESS_FALSE;
+ nativeSetIsScrolling(true);
+ } else {
+ mHeldMotionless = MOTIONLESS_TRUE;
+ nativeSetIsScrolling(false);
+ keepScrollBarsVisible = true;
}
+
mLastTouchTime = eventTime;
}
@@ -6296,9 +6307,15 @@
// keep the scrollbar on the screen even there is no scroll
awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(),
false);
+ // Post a message so that we'll keep them alive while we're not scrolling.
+ mPrivateHandler.sendMessageDelayed(mPrivateHandler
+ .obtainMessage(AWAKEN_SCROLL_BARS),
+ ViewConfiguration.getScrollDefaultDelay());
// return false to indicate that we can't pan out of the
// view space
return !done;
+ } else {
+ mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
}
break;
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 510e2d4..1da18aa 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -239,6 +239,7 @@
SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) {
final int start = editable.getSpanStart(spellCheckSpan);
final int end = editable.getSpanEnd(spellCheckSpan);
+ if (start < 0 || end < 0) return; // span was removed in the meantime
// Other suggestion spans may exist on that region, with identical suggestions, filter
// them out to avoid duplicates. First, filter suggestion spans on that exact region.
@@ -249,7 +250,6 @@
final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
if (spanStart != start || spanEnd != end) {
suggestionSpans[i] = null;
- break;
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 041e8a4..a21c924 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9608,15 +9608,6 @@
SpannableStringBuilder text = new SpannableStringBuilder();
TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mContext,
android.R.style.TextAppearance_SuggestionHighlight);
-
- void removeMisspelledFlag() {
- int suggestionSpanFlags = suggestionSpan.getFlags();
- if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
- suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
- suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
- suggestionSpan.setFlags(suggestionSpanFlags);
- }
- }
}
private class SuggestionAdapter extends BaseAdapter {
@@ -9890,14 +9881,16 @@
if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
final int spanUnionStart = editable.getSpanStart(mSuggestionRangeSpan);
int spanUnionEnd = editable.getSpanEnd(mSuggestionRangeSpan);
- // Do not leave two adjacent spaces after deletion, or one at beginning of text
- if (spanUnionEnd < editable.length() &&
- Character.isSpaceChar(editable.charAt(spanUnionEnd)) &&
- (spanUnionStart == 0 ||
- Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
+ if (spanUnionStart >= 0 && spanUnionEnd > spanUnionStart) {
+ // Do not leave two adjacent spaces after deletion, or one at beginning of text
+ if (spanUnionEnd < editable.length() &&
+ Character.isSpaceChar(editable.charAt(spanUnionEnd)) &&
+ (spanUnionStart == 0 ||
+ Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
spanUnionEnd = spanUnionEnd + 1;
+ }
+ editable.replace(spanUnionStart, spanUnionEnd, "");
}
- editable.replace(spanUnionStart, spanUnionEnd, "");
hide();
return;
}
@@ -9932,6 +9925,14 @@
suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
+
+ // Remove potential misspelled flags
+ int suggestionSpanFlags = suggestionSpan.getFlags();
+ if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) {
+ suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
+ suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
+ suggestionSpan.setFlags(suggestionSpanFlags);
+ }
}
final int suggestionStart = suggestionInfo.suggestionStart;
@@ -9940,8 +9941,6 @@
suggestionStart, suggestionEnd).toString();
editable.replace(spanStart, spanEnd, suggestion);
- suggestionInfo.removeMisspelledFlag();
-
// Notify source IME of the suggestion pick. Do this before swaping texts.
if (!TextUtils.isEmpty(
suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
diff --git a/core/java/com/android/internal/view/menu/ExpandedMenuView.java b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
index 723ece4..47058ad 100644
--- a/core/java/com/android/internal/view/menu/ExpandedMenuView.java
+++ b/core/java/com/android/internal/view/menu/ExpandedMenuView.java
@@ -63,11 +63,6 @@
setChildrenDrawingCacheEnabled(false);
}
- @Override
- protected boolean recycleOnMeasure() {
- return false;
- }
-
public boolean invokeItem(MenuItemImpl item) {
return mMenu.performItemAction(item, 0);
}
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index a1e16d4..df579c6 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -34,6 +34,7 @@
* The item view for each item in the ListView-based MenuViews.
*/
public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
+ private static final String TAG = "ListMenuItemView";
private MenuItemImpl mItemData;
private ImageView mIconView;
@@ -121,27 +122,25 @@
}
public void setCheckable(boolean checkable) {
-
if (!checkable && mRadioButton == null && mCheckBox == null) {
return;
}
- if (mRadioButton == null) {
- insertRadioButton();
- }
- if (mCheckBox == null) {
- insertCheckBox();
- }
-
// Depending on whether its exclusive check or not, the checkbox or
// radio button will be the one in use (and the other will be otherCompoundButton)
final CompoundButton compoundButton;
final CompoundButton otherCompoundButton;
if (mItemData.isExclusiveCheckable()) {
+ if (mRadioButton == null) {
+ insertRadioButton();
+ }
compoundButton = mRadioButton;
otherCompoundButton = mCheckBox;
} else {
+ if (mCheckBox == null) {
+ insertCheckBox();
+ }
compoundButton = mCheckBox;
otherCompoundButton = mRadioButton;
}
@@ -155,12 +154,12 @@
}
// Make sure the other compound button isn't visible
- if (otherCompoundButton.getVisibility() != GONE) {
+ if (otherCompoundButton != null && otherCompoundButton.getVisibility() != GONE) {
otherCompoundButton.setVisibility(GONE);
}
} else {
- mCheckBox.setVisibility(GONE);
- mRadioButton.setVisibility(GONE);
+ if (mCheckBox != null) mCheckBox.setVisibility(GONE);
+ if (mRadioButton != null) mRadioButton.setVisibility(GONE);
}
}
diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk
index 564f41c..c964961 100644
--- a/data/keyboards/keyboards.mk
+++ b/data/keyboards/keyboards.mk
@@ -24,6 +24,3 @@
PRODUCT_COPY_FILES += $(foreach file,$(keyconfigs),\
frameworks/base/data/keyboards/$(file):system/usr/idc/$(file))
-
-PRODUCT_PACKAGES := $(keylayouts) $(keycharmaps) $(keyconfigs)
-
diff --git a/docs/html/guide/topics/fundamentals/fragments.jd b/docs/html/guide/topics/fundamentals/fragments.jd
index 8f61945..d34a798 100644
--- a/docs/html/guide/topics/fundamentals/fragments.jd
+++ b/docs/html/guide/topics/fundamentals/fragments.jd
@@ -117,7 +117,7 @@
two
fragments in <em>Activity A</em>, when running on an extra large screen (a tablet, for example).
However, on a normal-sized screen (a phone, for example),
-there's not be enough room for both fragments, so <em>Activity A</em> includes only the fragment for
+there would not be enough room for both fragments, so <em>Activity A</em> includes only the fragment for
the list of articles, and when the user selects an article, it starts <em>Activity B</em>, which
includes the fragment to read the article. Thus, the application supports both design patterns
suggested in figure 1.</p>
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 3e48459..2eb259e 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -31,7 +31,9 @@
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
-extern const char *MEDIA_MIMETYPE_AUDIO_MPEG;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG; // layer III
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
extern const char *MEDIA_MIMETYPE_AUDIO_QCELP;
extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS;
@@ -47,6 +49,7 @@
extern const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA;
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS;
extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS;
extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index e1ee8eb..a42ce21 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -20,12 +20,13 @@
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
+#include <cutils/compiler.h>
namespace android {
// ---------------------------------------------------------------------------
template <typename TYPE>
-class Singleton
+class ANDROID_API Singleton
{
public:
static TYPE& getInstance() {
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index a98e4cd..9bfc94c 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -39,6 +39,7 @@
external/skia/include/utils
LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER
+ LOCAL_CFLAGS += -fvisibility=hidden
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2 libskia libui
LOCAL_MODULE := libhwui
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index cdcbf21..9b0d7c6 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -23,6 +23,8 @@
#include <utils/Singleton.h>
+#include <cutils/compiler.h>
+
#include "Extensions.h"
#include "FontRenderer.h"
#include "GammaFontRenderer.h"
@@ -82,7 +84,7 @@
// Caches
///////////////////////////////////////////////////////////////////////////////
-class Caches: public Singleton<Caches> {
+class ANDROID_API Caches: public Singleton<Caches> {
Caches();
~Caches();
diff --git a/libs/hwui/DisplayListLogBuffer.h b/libs/hwui/DisplayListLogBuffer.h
index bf16f29..5d689bb 100644
--- a/libs/hwui/DisplayListLogBuffer.h
+++ b/libs/hwui/DisplayListLogBuffer.h
@@ -18,6 +18,7 @@
#define ANDROID_HWUI_DISPLAY_LIST_LOG_BUFFER_H
#include <utils/Singleton.h>
+
#include <stdio.h>
namespace android {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 8cd7fea..ab475bf 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -26,6 +26,8 @@
#include <SkTDArray.h>
#include <SkTSearch.h>
+#include <cutils/compiler.h>
+
#include "DisplayListLogBuffer.h"
#include "OpenGLRenderer.h"
#include "utils/Functor.h"
@@ -58,7 +60,7 @@
class DisplayList {
public:
DisplayList(const DisplayListRenderer& recorder);
- ~DisplayList();
+ ANDROID_API ~DisplayList();
// IMPORTANT: Update the intialization of OP_NAMES in the .cpp file
// when modifying this file
@@ -107,13 +109,13 @@
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
- size_t getSize();
+ ANDROID_API size_t getSize();
bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
void output(OpenGLRenderer& renderer, uint32_t level = 0);
- static void outputLogBuffer(int fd);
+ ANDROID_API static void outputLogBuffer(int fd);
void setRenderable(bool renderable) {
mIsRenderable = renderable;
@@ -230,75 +232,76 @@
*/
class DisplayListRenderer: public OpenGLRenderer {
public:
- DisplayListRenderer();
- ~DisplayListRenderer();
+ ANDROID_API DisplayListRenderer();
+ virtual ~DisplayListRenderer();
- DisplayList* getDisplayList(DisplayList* displayList);
+ ANDROID_API DisplayList* getDisplayList(DisplayList* displayList);
- void setViewport(int width, int height);
- void prepareDirty(float left, float top, float right, float bottom, bool opaque);
- void finish();
+ virtual void setViewport(int width, int height);
+ virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
+ virtual void finish();
- bool callDrawGLFunction(Functor *functor, Rect& dirty);
+ virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
- void interrupt();
- void resume();
+ virtual void interrupt();
+ virtual void resume();
- int save(int flags);
- void restore();
- void restoreToCount(int saveCount);
+ virtual int save(int flags);
+ virtual void restore();
+ virtual void restoreToCount(int saveCount);
- int saveLayer(float left, float top, float right, float bottom,
+ virtual int saveLayer(float left, float top, float right, float bottom,
SkPaint* p, int flags);
- int saveLayerAlpha(float left, float top, float right, float bottom,
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom,
int alpha, int flags);
- void translate(float dx, float dy);
- void rotate(float degrees);
- void scale(float sx, float sy);
- void skew(float sx, float sy);
+ virtual void translate(float dx, float dy);
+ virtual void rotate(float degrees);
+ virtual void scale(float sx, float sy);
+ virtual void skew(float sx, float sy);
- void setMatrix(SkMatrix* matrix);
- void concatMatrix(SkMatrix* matrix);
+ virtual void setMatrix(SkMatrix* matrix);
+ virtual void concatMatrix(SkMatrix* matrix);
- bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+ virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
- bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
+ virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
Rect& dirty, uint32_t level = 0);
- void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
- void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
- void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
- void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
+ virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
+ virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
+ virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
+ virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, SkPaint* paint);
- void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
+ virtual void drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
float* vertices, int* colors, SkPaint* paint);
- void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
+ virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
float left, float top, float right, float bottom, SkPaint* paint);
- void drawColor(int color, SkXfermode::Mode mode);
- void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
- void drawRoundRect(float left, float top, float right, float bottom,
+ virtual void drawColor(int color, SkXfermode::Mode mode);
+ virtual void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
+ virtual void drawRoundRect(float left, float top, float right, float bottom,
float rx, float ry, SkPaint* paint);
- void drawCircle(float x, float y, float radius, SkPaint* paint);
- void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
- void drawArc(float left, float top, float right, float bottom,
+ virtual void drawCircle(float x, float y, float radius, SkPaint* paint);
+ virtual void drawOval(float left, float top, float right, float bottom, SkPaint* paint);
+ virtual void drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, bool useCenter, SkPaint* paint);
- void drawPath(SkPath* path, SkPaint* paint);
- void drawLines(float* points, int count, SkPaint* paint);
- void drawPoints(float* points, int count, SkPaint* paint);
- void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
+ virtual void drawPath(SkPath* path, SkPaint* paint);
+ virtual void drawLines(float* points, int count, SkPaint* paint);
+ virtual void drawPoints(float* points, int count, SkPaint* paint);
+ virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
+ SkPaint* paint);
- void resetShader();
- void setupShader(SkiaShader* shader);
+ virtual void resetShader();
+ virtual void setupShader(SkiaShader* shader);
- void resetColorFilter();
- void setupColorFilter(SkiaColorFilter* filter);
+ virtual void resetColorFilter();
+ virtual void setupColorFilter(SkiaColorFilter* filter);
- void resetShadow();
- void setupShadow(float radius, float dx, float dy, int color);
+ virtual void resetShadow();
+ virtual void setupShadow(float radius, float dx, float dy, int color);
- void reset();
+ ANDROID_API void reset();
const SkWriter32& writeStream() const {
return mWriter;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 349b9e3..dfcc5ea 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -31,6 +31,12 @@
// Rendering
///////////////////////////////////////////////////////////////////////////////
+LayerRenderer::LayerRenderer(Layer* layer): mLayer(layer) {
+}
+
+LayerRenderer::~LayerRenderer() {
+}
+
void LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
@@ -264,7 +270,7 @@
layer->setFbo(0);
layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
- layer->texCoords.set(0.0f, 1.0f, 0.0f, 1.0f);
+ layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
layer->region.clear();
layer->setRenderTarget(GL_NONE); // see ::updateTextureLayer()
@@ -400,6 +406,18 @@
renderer.setViewport(bitmap->width(), bitmap->height());
renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
bitmap->width(), bitmap->height(), !layer->isBlend());
+
+ glDisable(GL_SCISSOR_TEST);
+ renderer.translate(0.0f, bitmap->height());
+ renderer.scale(1.0f, -1.0f);
+
+ mat4 texTransform(layer->getTexTransform());
+
+ mat4 invert;
+ invert.translate(0.0f, 1.0f, 0.0f);
+ invert.scale(1.0f, -1.0f, 1.0f);
+ layer->getTexTransform().multiply(invert);
+
if ((error = glGetError()) != GL_NO_ERROR) goto error;
{
@@ -413,6 +431,7 @@
if ((error = glGetError()) != GL_NO_ERROR) goto error;
}
+ layer->getTexTransform().load(texTransform);
status = true;
}
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 2246573..6104301 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HWUI_LAYER_RENDERER_H
#define ANDROID_HWUI_LAYER_RENDERER_H
+#include <cutils/compiler.h>
+
#include "OpenGLRenderer.h"
#include "Layer.h"
@@ -42,27 +44,24 @@
class LayerRenderer: public OpenGLRenderer {
public:
- LayerRenderer(Layer* layer): mLayer(layer) {
- }
+ ANDROID_API LayerRenderer(Layer* layer);
+ virtual ~LayerRenderer();
- ~LayerRenderer() {
- }
+ virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
+ virtual void finish();
- void prepareDirty(float left, float top, float right, float bottom, bool opaque);
- void finish();
+ virtual bool hasLayer();
+ virtual Region* getRegion();
+ virtual GLint getTargetFbo();
- bool hasLayer();
- Region* getRegion();
- GLint getTargetFbo();
-
- static Layer* createTextureLayer(bool isOpaque);
- static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
- static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
- static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
+ ANDROID_API static Layer* createTextureLayer(bool isOpaque);
+ ANDROID_API static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
+ ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
+ ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
bool isOpaque, GLenum renderTarget, float* transform);
- static void destroyLayer(Layer* layer);
- static void destroyLayerDeferred(Layer* layer);
- static bool copyLayer(Layer* layer, SkBitmap* bitmap);
+ ANDROID_API static void destroyLayer(Layer* layer);
+ ANDROID_API static void destroyLayerDeferred(Layer* layer);
+ ANDROID_API static bool copyLayer(Layer* layer, SkBitmap* bitmap);
private:
void generateMesh();
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 56fd37d..22220a9 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -19,6 +19,8 @@
#include <SkMatrix.h>
+#include <cutils/compiler.h>
+
#include "Rect.h"
namespace android {
@@ -28,7 +30,7 @@
// Classes
///////////////////////////////////////////////////////////////////////////////
-class Matrix4 {
+class ANDROID_API Matrix4 {
public:
float data[16];
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 14b22b3..2fc88e1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -31,6 +31,8 @@
#include <utils/RefBase.h>
#include <utils/Vector.h>
+#include <cutils/compiler.h>
+
#include "Debug.h"
#include "Extensions.h"
#include "Matrix.h"
@@ -57,12 +59,12 @@
*/
class OpenGLRenderer {
public:
- OpenGLRenderer();
+ ANDROID_API OpenGLRenderer();
virtual ~OpenGLRenderer();
virtual void setViewport(int width, int height);
- void prepare(bool opaque);
+ ANDROID_API void prepare(bool opaque);
virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque);
virtual void finish();
@@ -72,7 +74,7 @@
virtual bool callDrawGLFunction(Functor *functor, Rect& dirty);
- int getSaveCount() const;
+ ANDROID_API int getSaveCount() const;
virtual int save(int flags);
virtual void restore();
virtual void restoreToCount(int saveCount);
@@ -87,12 +89,12 @@
virtual void scale(float sx, float sy);
virtual void skew(float sx, float sy);
- void getMatrix(SkMatrix* matrix);
+ ANDROID_API void getMatrix(SkMatrix* matrix);
virtual void setMatrix(SkMatrix* matrix);
virtual void concatMatrix(SkMatrix* matrix);
- const Rect& getClipBounds();
- bool quickReject(float left, float top, float right, float bottom);
+ ANDROID_API const Rect& getClipBounds();
+ ANDROID_API bool quickReject(float left, float top, float right, float bottom);
virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 2a38910..8cf466b 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HWUI_RESOURCE_CACHE_H
#define ANDROID_HWUI_RESOURCE_CACHE_H
+#include <cutils/compiler.h>
+
#include <SkBitmap.h>
#include <SkiaColorFilter.h>
#include <SkiaShader.h>
@@ -49,7 +51,7 @@
ResourceType resourceType;
};
-class ResourceCache {
+class ANDROID_API ResourceCache {
KeyedVector<void *, ResourceReference *>* mCache;
public:
ResourceCache();
diff --git a/libs/hwui/SkiaColorFilter.h b/libs/hwui/SkiaColorFilter.h
index 1bf475c..2feb834 100644
--- a/libs/hwui/SkiaColorFilter.h
+++ b/libs/hwui/SkiaColorFilter.h
@@ -20,6 +20,8 @@
#include <GLES2/gl2.h>
#include <SkColorFilter.h>
+#include <cutils/compiler.h>
+
#include "ProgramCache.h"
#include "Extensions.h"
@@ -45,7 +47,7 @@
kBlend,
};
- SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
+ ANDROID_API SkiaColorFilter(SkColorFilter *skFilter, Type type, bool blend);
virtual ~SkiaColorFilter();
virtual void describe(ProgramDescription& description, const Extensions& extensions) = 0;
@@ -79,7 +81,7 @@
* A color filter that multiplies the source color with a matrix and adds a vector.
*/
struct SkiaColorMatrixFilter: public SkiaColorFilter {
- SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
+ ANDROID_API SkiaColorMatrixFilter(SkColorFilter *skFilter, float* matrix, float* vector);
~SkiaColorMatrixFilter();
void describe(ProgramDescription& description, const Extensions& extensions);
@@ -95,7 +97,7 @@
* another fixed value. Ignores the alpha channel of both arguments.
*/
struct SkiaLightingFilter: public SkiaColorFilter {
- SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
+ ANDROID_API SkiaLightingFilter(SkColorFilter *skFilter, int multiply, int add);
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program);
@@ -110,7 +112,7 @@
* and PorterDuff blending mode.
*/
struct SkiaBlendFilter: public SkiaColorFilter {
- SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
+ ANDROID_API SkiaBlendFilter(SkColorFilter *skFilter, int color, SkXfermode::Mode mode);
void describe(ProgramDescription& description, const Extensions& extensions);
void setupProgram(Program* program);
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 89dd131..2de9a93 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -22,6 +22,8 @@
#include <GLES2/gl2.h>
+#include <cutils/compiler.h>
+
#include "Extensions.h"
#include "ProgramCache.h"
#include "TextureCache.h"
@@ -52,8 +54,8 @@
kCompose
};
- SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX, SkShader::TileMode tileY,
- SkMatrix* matrix, bool blend);
+ ANDROID_API SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
+ SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
virtual ~SkiaShader();
virtual SkiaShader* copy() = 0;
@@ -139,7 +141,7 @@
* A shader that draws a bitmap.
*/
struct SkiaBitmapShader: public SkiaShader {
- SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
+ ANDROID_API SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
SkShader::TileMode tileY, SkMatrix* matrix, bool blend);
SkiaShader* copy();
@@ -169,8 +171,8 @@
* A shader that draws a linear gradient.
*/
struct SkiaLinearGradientShader: public SkiaShader {
- SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions, int count,
- SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
+ ANDROID_API SkiaLinearGradientShader(float* bounds, uint32_t* colors, float* positions,
+ int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
~SkiaLinearGradientShader();
SkiaShader* copy();
@@ -193,8 +195,8 @@
* A shader that draws a sweep gradient.
*/
struct SkiaSweepGradientShader: public SkiaShader {
- SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions, int count,
- SkShader* key, SkMatrix* matrix, bool blend);
+ ANDROID_API SkiaSweepGradientShader(float x, float y, uint32_t* colors, float* positions,
+ int count, SkShader* key, SkMatrix* matrix, bool blend);
~SkiaSweepGradientShader();
SkiaShader* copy();
@@ -218,8 +220,9 @@
* A shader that draws a circular gradient.
*/
struct SkiaCircularGradientShader: public SkiaSweepGradientShader {
- SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions,
- int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
+ ANDROID_API SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors,
+ float* positions, int count, SkShader* key,SkShader::TileMode tileMode,
+ SkMatrix* matrix, bool blend);
SkiaShader* copy();
void describe(ProgramDescription& description, const Extensions& extensions);
@@ -233,7 +236,8 @@
* A shader that draws two shaders, composited with an xfermode.
*/
struct SkiaComposeShader: public SkiaShader {
- SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode, SkShader* key);
+ ANDROID_API SkiaComposeShader(SkiaShader* first, SkiaShader* second, SkXfermode::Mode mode,
+ SkShader* key);
~SkiaComposeShader();
SkiaShader* copy();
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 5fd5c35..4ecf8e8 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -226,6 +226,7 @@
RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
uint32_t sig = mtls->sig;
+ outer_foreach_t fn = dc->mForEachLaunch[sig];
while (1) {
uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
uint32_t yStart = mtls->yStart + slice * mtls->mSliceSize;
@@ -239,16 +240,10 @@
//LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut);
for (p.y = yStart; p.y < yEnd; p.y++) {
uint32_t offset = mtls->dimX * p.y;
- uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * offset);
- const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * offset);
-
- for (p.x = mtls->xStart; p.x < mtls->xEnd; p.x++) {
- p.in = xPtrIn;
- p.out = xPtrOut;
- dc->mForEachLaunch[sig](&mtls->script->mHal.info.root, &p);
- xPtrIn += mtls->eStrideIn;
- xPtrOut += mtls->eStrideOut;
- }
+ p.out = mtls->ptrOut + (mtls->eStrideOut * offset);
+ p.in = mtls->ptrIn + (mtls->eStrideIn * offset);
+ fn(&mtls->script->mHal.info.root, &p, mtls->xStart, mtls->xEnd,
+ mtls->eStrideIn, mtls->eStrideOut);
}
}
}
@@ -262,6 +257,7 @@
RsdHal * dc = (RsdHal *)mtls->rsc->mHal.drv;
uint32_t sig = mtls->sig;
+ outer_foreach_t fn = dc->mForEachLaunch[sig];
while (1) {
uint32_t slice = (uint32_t)android_atomic_inc(&mtls->mSliceNum);
uint32_t xStart = mtls->xStart + slice * mtls->mSliceSize;
@@ -271,17 +267,12 @@
return;
}
- //LOGE("usr idx %i, x %i,%i y %i,%i", idx, mtls->xStart, mtls->xEnd, yStart, yEnd);
+ //LOGE("usr slice %i idx %i, x %i,%i", slice, idx, xStart, xEnd);
//LOGE("usr ptr in %p, out %p", mtls->ptrIn, mtls->ptrOut);
- uint8_t *xPtrOut = mtls->ptrOut + (mtls->eStrideOut * xStart);
- const uint8_t *xPtrIn = mtls->ptrIn + (mtls->eStrideIn * xStart);
- for (p.x = xStart; p.x < xEnd; p.x++) {
- p.in = xPtrIn;
- p.out = xPtrOut;
- dc->mForEachLaunch[sig](&mtls->script->mHal.info.root, &p);
- xPtrIn += mtls->eStrideIn;
- xPtrOut += mtls->eStrideOut;
- }
+
+ p.out = mtls->ptrOut + (mtls->eStrideOut * xStart);
+ p.in = mtls->ptrIn + (mtls->eStrideIn * xStart);
+ fn(&mtls->script->mHal.info.root, &p, xStart, xEnd, mtls->eStrideIn, mtls->eStrideOut);
}
}
@@ -392,22 +383,17 @@
uint32_t sig = mtls.sig;
//LOGE("launch 3");
+ outer_foreach_t fn = dc->mForEachLaunch[sig];
for (p.ar[0] = mtls.arrayStart; p.ar[0] < mtls.arrayEnd; p.ar[0]++) {
for (p.z = mtls.zStart; p.z < mtls.zEnd; p.z++) {
for (p.y = mtls.yStart; p.y < mtls.yEnd; p.y++) {
uint32_t offset = mtls.dimX * mtls.dimY * mtls.dimZ * p.ar[0] +
mtls.dimX * mtls.dimY * p.z +
mtls.dimX * p.y;
- uint8_t *xPtrOut = mtls.ptrOut + (mtls.eStrideOut * offset);
- const uint8_t *xPtrIn = mtls.ptrIn + (mtls.eStrideIn * offset);
-
- for (p.x = mtls.xStart; p.x < mtls.xEnd; p.x++) {
- p.in = xPtrIn;
- p.out = xPtrOut;
- dc->mForEachLaunch[sig](&s->mHal.info.root, &p);
- xPtrIn += mtls.eStrideIn;
- xPtrOut += mtls.eStrideOut;
- }
+ p.out = mtls.ptrOut + (mtls.eStrideOut * offset);
+ p.in = mtls.ptrIn + (mtls.eStrideIn * offset);
+ fn(&mtls.script->mHal.info.root, &p, mtls.xStart, mtls.xEnd,
+ mtls.eStrideIn, mtls.eStrideOut);
}
}
}
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index f8107d9..247f4dc 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -292,75 +292,136 @@
}
static void rsdForEach17(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, uint32_t);
(*(fe*)vRoot)(p->in, p->y);
}
static void rsdForEach18(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(void *, uint32_t);
(*(fe*)vRoot)(p->out, p->y);
}
static void rsdForEach19(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, void *, uint32_t);
(*(fe*)vRoot)(p->in, p->out, p->y);
}
static void rsdForEach21(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, const void *, uint32_t);
(*(fe*)vRoot)(p->in, p->usr, p->y);
}
static void rsdForEach22(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(void *, const void *, uint32_t);
(*(fe*)vRoot)(p->out, p->usr, p->y);
}
static void rsdForEach23(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, void *, const void *, uint32_t);
(*(fe*)vRoot)(p->in, p->out, p->usr, p->y);
}
static void rsdForEach25(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->in, p->x, p->y);
+ const uint8_t *pin = (const uint8_t *)p->in;
+ uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pin, x, y);
+ pin += instep;
+ }
}
static void rsdForEach26(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->out, p->x, p->y);
+ uint8_t *pout = (uint8_t *)p->out;
+ uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pout, x, y);
+ pout += outstep;
+ }
}
static void rsdForEach27(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->in, p->out, p->x, p->y);
+ uint8_t *pout = (uint8_t *)p->out;
+ const uint8_t *pin = (const uint8_t *)p->in;
+ uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pin, pout, x, y);
+ pin += instep;
+ pout += outstep;
+ }
}
static void rsdForEach29(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, const void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->in, p->usr, p->x, p->y);
+ const uint8_t *pin = (const uint8_t *)p->in;
+ const void *usr = p->usr;
+ const uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pin, usr, x, y);
+ pin += instep;
+ }
}
static void rsdForEach30(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(void *, const void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->out, p->usr, p->x, p->y);
+ uint8_t *pout = (uint8_t *)p->out;
+ const void *usr = p->usr;
+ const uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pout, usr, x, y);
+ pout += outstep;
+ }
}
static void rsdForEach31(const void *vRoot,
- const android::renderscript::RsForEachStubParamStruct *p) {
+ const android::renderscript::RsForEachStubParamStruct *p,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep) {
typedef void (*fe)(const void *, void *, const void *, uint32_t, uint32_t);
- (*(fe*)vRoot)(p->in, p->out, p->usr, p->x, p->y);
+ uint8_t *pout = (uint8_t *)p->out;
+ const uint8_t *pin = (const uint8_t *)p->in;
+ const void *usr = p->usr;
+ const uint32_t y = p->y;
+ for (uint32_t x = x1; x < x2; x++) {
+ (*(fe*)vRoot)(pin, pout, usr, x, y);
+ pin += instep;
+ pout += outstep;
+ }
}
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 159b72a..ce86d11 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -28,7 +28,9 @@
typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
typedef void (*outer_foreach_t)(const void *,
- const android::renderscript::RsForEachStubParamStruct *);
+ const android::renderscript::RsForEachStubParamStruct *,
+ uint32_t x1, uint32_t x2,
+ uint32_t instep, uint32_t outstep);
typedef struct RsdSymbolTableRec {
const char * mName;
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 8793841..e275aa6 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -71,6 +71,11 @@
private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WEBM;
+ // More video file types
+ public static final int FILE_TYPE_MP2PS = 200;
+ private static final int FIRST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
+ private static final int LAST_VIDEO_FILE_TYPE2 = FILE_TYPE_MP2PS;
+
// Image file types
public static final int FILE_TYPE_JPEG = 31;
public static final int FILE_TYPE_GIF = 32;
@@ -235,6 +240,8 @@
addFileType("PPT", FILE_TYPE_MS_POWERPOINT, "application/mspowerpoint", MtpConstants.FORMAT_MS_POWERPOINT_PRESENTATION);
addFileType("FLAC", FILE_TYPE_FLAC, "audio/flac", MtpConstants.FORMAT_FLAC);
addFileType("ZIP", FILE_TYPE_ZIP, "application/zip");
+ addFileType("MPG", FILE_TYPE_MP2PS, "video/mp2p");
+ addFileType("MPEG", FILE_TYPE_MP2PS, "video/mp2p");
}
public static boolean isAudioFileType(int fileType) {
@@ -246,7 +253,9 @@
public static boolean isVideoFileType(int fileType) {
return (fileType >= FIRST_VIDEO_FILE_TYPE &&
- fileType <= LAST_VIDEO_FILE_TYPE);
+ fileType <= LAST_VIDEO_FILE_TYPE)
+ || (fileType >= FIRST_VIDEO_FILE_TYPE2 &&
+ fileType <= LAST_VIDEO_FILE_TYPE2);
}
public static boolean isImageFileType(int fileType) {
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index ec7d8a0..a3e2517 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -32,8 +32,8 @@
libdl
LOCAL_STATIC_LIBRARIES := \
- libstagefright_rtsp \
libstagefright_nuplayer \
+ libstagefright_rtsp \
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b5eef94..24e1bfb 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -584,6 +584,10 @@
}
}
+ if (!strncasecmp("rtsp://", url, 7)) {
+ return NU_PLAYER;
+ }
+
// use MidiFile for MIDI extensions
int lenURL = strlen(url);
for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index e761509..33e2f93 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -8,6 +8,7 @@
NuPlayerDriver.cpp \
NuPlayerRenderer.cpp \
NuPlayerStreamListener.cpp \
+ RTSPSource.cpp \
StreamingSource.cpp \
LOCAL_C_INCLUDES := \
@@ -15,6 +16,7 @@
$(TOP)/frameworks/base/media/libstagefright/include \
$(TOP)/frameworks/base/media/libstagefright/mpeg2ts \
$(TOP)/frameworks/base/media/libstagefright/httplive \
+ $(TOP)/frameworks/base/media/libstagefright/rtsp \
LOCAL_MODULE:= libstagefright_nuplayer
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 6b40528..4c710b4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -25,6 +25,7 @@
#include "NuPlayerDriver.h"
#include "NuPlayerRenderer.h"
#include "NuPlayerSource.h"
+#include "RTSPSource.h"
#include "StreamingSource.h"
#include "ATSParser.h"
@@ -87,7 +88,14 @@
const char *url, const KeyedVector<String8, String8> *headers) {
sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
- msg->setObject("source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
+ if (!strncasecmp(url, "rtsp://", 7)) {
+ msg->setObject(
+ "source", new RTSPSource(url, headers, mUIDValid, mUID));
+ } else {
+ msg->setObject(
+ "source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
+ }
+
msg->post();
}
@@ -568,8 +576,15 @@
CHECK(mAudioDecoder == NULL);
CHECK(mVideoDecoder == NULL);
+ ++mScanSourcesGeneration;
+ mScanSourcesPending = false;
+
mRenderer.clear();
- mSource.clear();
+
+ if (mSource != NULL) {
+ mSource->stop();
+ mSource.clear();
+ }
if (mDriver != NULL) {
sp<NuPlayerDriver> driver = mDriver.promote();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index a5382b4..f90759d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -68,6 +68,7 @@
struct Renderer;
struct Source;
struct StreamingSource;
+ struct RTSPSource;
enum {
kWhatSetDataSource = '=DaS',
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 07e347e..bf19040 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -219,7 +219,9 @@
bool NuPlayer::Renderer::onDrainAudioQueue() {
uint32_t numFramesPlayed;
- CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
+ if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
+ return false;
+ }
ssize_t numFramesAvailableToWrite =
mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 8a7eece..531b29f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -28,6 +28,7 @@
Source() {}
virtual void start() = 0;
+ virtual void stop() {}
// Returns OK iff more data was available,
// an error or ERROR_END_OF_STREAM if not.
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
new file mode 100644
index 0000000..e72adc4
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2010 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 "RTSPSource"
+#include <utils/Log.h>
+
+#include "RTSPSource.h"
+
+#include "AnotherPacketSource.h"
+#include "MyHandler.h"
+
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+NuPlayer::RTSPSource::RTSPSource(
+ const char *url,
+ const KeyedVector<String8, String8> *headers,
+ bool uidValid,
+ uid_t uid)
+ : mURL(url),
+ mUIDValid(uidValid),
+ mUID(uid),
+ mFlags(0),
+ mState(DISCONNECTED),
+ mFinalResult(OK),
+ mDisconnectReplyID(0) {
+ if (headers) {
+ mExtraHeaders = *headers;
+
+ ssize_t index =
+ mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log"));
+
+ if (index >= 0) {
+ mFlags |= kFlagIncognito;
+
+ mExtraHeaders.removeItemsAt(index);
+ }
+ }
+}
+
+NuPlayer::RTSPSource::~RTSPSource() {
+ if (mLooper != NULL) {
+ mLooper->stop();
+ }
+}
+
+void NuPlayer::RTSPSource::start() {
+ if (mLooper == NULL) {
+ mLooper = new ALooper;
+ mLooper->setName("rtsp");
+ mLooper->start();
+
+ mReflector = new AHandlerReflector<RTSPSource>(this);
+ mLooper->registerHandler(mReflector);
+ }
+
+ CHECK(mHandler == NULL);
+
+ sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
+
+ mHandler = new MyHandler(mURL.c_str(), notify, mUIDValid, mUID);
+ mLooper->registerHandler(mHandler);
+
+ CHECK_EQ(mState, (int)DISCONNECTED);
+ mState = CONNECTING;
+
+ mHandler->connect();
+}
+
+void NuPlayer::RTSPSource::stop() {
+ sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
+
+ sp<AMessage> dummy;
+ msg->postAndAwaitResponse(&dummy);
+}
+
+status_t NuPlayer::RTSPSource::feedMoreTSData() {
+ return mFinalResult;
+}
+
+sp<MetaData> NuPlayer::RTSPSource::getFormat(bool audio) {
+ sp<AnotherPacketSource> source = getSource(audio);
+
+ if (source == NULL) {
+ return NULL;
+ }
+
+ return source->getFormat();
+}
+
+status_t NuPlayer::RTSPSource::dequeueAccessUnit(
+ bool audio, sp<ABuffer> *accessUnit) {
+ sp<AnotherPacketSource> source = getSource(audio);
+
+ if (source == NULL) {
+ return -EWOULDBLOCK;
+ }
+
+ status_t finalResult;
+ if (!source->hasBufferAvailable(&finalResult)) {
+ return finalResult == OK ? -EWOULDBLOCK : finalResult;
+ }
+
+ return source->dequeueAccessUnit(accessUnit);
+}
+
+sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
+ return audio ? mAudioTrack : mVideoTrack;
+}
+
+status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
+ *durationUs = 0ll;
+
+ int64_t audioDurationUs;
+ if (mAudioTrack != NULL
+ && mAudioTrack->getFormat()->findInt64(
+ kKeyDuration, &audioDurationUs)
+ && audioDurationUs > *durationUs) {
+ *durationUs = audioDurationUs;
+ }
+
+ int64_t videoDurationUs;
+ if (mVideoTrack != NULL
+ && mVideoTrack->getFormat()->findInt64(
+ kKeyDuration, &videoDurationUs)
+ && videoDurationUs > *durationUs) {
+ *durationUs = videoDurationUs;
+ }
+
+ return OK;
+}
+
+status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
+ if (mState != CONNECTED) {
+ return UNKNOWN_ERROR;
+ }
+
+ mState = SEEKING;
+ mHandler->seek(seekTimeUs);
+
+ return OK;
+}
+
+bool NuPlayer::RTSPSource::isSeekable() {
+ return true;
+}
+
+void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
+ if (msg->what() == kWhatDisconnect) {
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ mDisconnectReplyID = replyID;
+ finishDisconnectIfPossible();
+ return;
+ }
+
+ CHECK_EQ(msg->what(), (int)kWhatNotify);
+
+ int32_t what;
+ CHECK(msg->findInt32("what", &what));
+
+ switch (what) {
+ case MyHandler::kWhatConnected:
+ onConnected();
+ break;
+
+ case MyHandler::kWhatDisconnected:
+ onDisconnected(msg);
+ break;
+
+ case MyHandler::kWhatSeekDone:
+ {
+ mState = CONNECTED;
+ break;
+ }
+
+ case MyHandler::kWhatAccessUnit:
+ {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK_LT(trackIndex, mTracks.size());
+
+ sp<RefBase> obj;
+ CHECK(msg->findObject("accessUnit", &obj));
+
+ sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
+
+ int32_t damaged;
+ if (accessUnit->meta()->findInt32("damaged", &damaged)
+ && damaged) {
+ LOGI("dropping damaged access unit.");
+ break;
+ }
+
+ const TrackInfo &info = mTracks.editItemAt(trackIndex);
+ sp<AnotherPacketSource> source = info.mSource;
+ if (source != NULL) {
+#if 1
+ uint32_t rtpTime;
+ CHECK(accessUnit->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+
+ int64_t nptUs =
+ ((double)rtpTime - (double)info.mRTPTime)
+ / info.mTimeScale
+ * 1000000ll
+ + info.mNormalPlaytimeUs;
+
+ accessUnit->meta()->setInt64("timeUs", nptUs);
+#endif
+
+ source->queueAccessUnit(accessUnit);
+ }
+ break;
+ }
+
+ case MyHandler::kWhatEOS:
+ {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK_LT(trackIndex, mTracks.size());
+
+ int32_t finalResult;
+ CHECK(msg->findInt32("finalResult", &finalResult));
+ CHECK_NE(finalResult, (status_t)OK);
+
+ TrackInfo *info = &mTracks.editItemAt(trackIndex);
+ sp<AnotherPacketSource> source = info->mSource;
+ if (source != NULL) {
+ source->signalEOS(finalResult);
+ }
+
+ break;
+ }
+
+ case MyHandler::kWhatSeekDiscontinuity:
+ {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK_LT(trackIndex, mTracks.size());
+
+ TrackInfo *info = &mTracks.editItemAt(trackIndex);
+ sp<AnotherPacketSource> source = info->mSource;
+ if (source != NULL) {
+ source->queueDiscontinuity(ATSParser::DISCONTINUITY_SEEK, NULL);
+ }
+
+ break;
+ }
+
+ case MyHandler::kWhatNormalPlayTimeMapping:
+ {
+ size_t trackIndex;
+ CHECK(msg->findSize("trackIndex", &trackIndex));
+ CHECK_LT(trackIndex, mTracks.size());
+
+ uint32_t rtpTime;
+ CHECK(msg->findInt32("rtpTime", (int32_t *)&rtpTime));
+
+ int64_t nptUs;
+ CHECK(msg->findInt64("nptUs", &nptUs));
+
+ TrackInfo *info = &mTracks.editItemAt(trackIndex);
+ info->mRTPTime = rtpTime;
+ info->mNormalPlaytimeUs = nptUs;
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
+void NuPlayer::RTSPSource::onConnected() {
+ CHECK(mAudioTrack == NULL);
+ CHECK(mVideoTrack == NULL);
+
+ size_t numTracks = mHandler->countTracks();
+ for (size_t i = 0; i < numTracks; ++i) {
+ int32_t timeScale;
+ sp<MetaData> format = mHandler->getTrackFormat(i, &timeScale);
+
+ const char *mime;
+ CHECK(format->findCString(kKeyMIMEType, &mime));
+
+ bool isAudio = !strncasecmp(mime, "audio/", 6);
+ bool isVideo = !strncasecmp(mime, "video/", 6);
+
+ TrackInfo info;
+ info.mTimeScale = timeScale;
+ info.mRTPTime = 0;
+ info.mNormalPlaytimeUs = 0ll;
+
+ if ((isAudio && mAudioTrack == NULL)
+ || (isVideo && mVideoTrack == NULL)) {
+ sp<AnotherPacketSource> source = new AnotherPacketSource(format);
+
+ if (isAudio) {
+ mAudioTrack = source;
+ } else {
+ mVideoTrack = source;
+ }
+
+ info.mSource = source;
+ }
+
+ mTracks.push(info);
+ }
+
+ mState = CONNECTED;
+}
+
+void NuPlayer::RTSPSource::onDisconnected(const sp<AMessage> &msg) {
+ status_t err;
+ CHECK(msg->findInt32("result", &err));
+ CHECK_NE(err, (status_t)OK);
+
+ mLooper->unregisterHandler(mHandler->id());
+ mHandler.clear();
+
+ mState = DISCONNECTED;
+ mFinalResult = err;
+
+ if (mDisconnectReplyID != 0) {
+ finishDisconnectIfPossible();
+ }
+}
+
+void NuPlayer::RTSPSource::finishDisconnectIfPossible() {
+ if (mState != DISCONNECTED) {
+ mHandler->disconnect();
+ return;
+ }
+
+ (new AMessage)->postReply(mDisconnectReplyID);
+ mDisconnectReplyID = 0;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
new file mode 100644
index 0000000..66eab72
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2010 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 RTSP_SOURCE_H_
+
+#define RTSP_SOURCE_H_
+
+#include "NuPlayerSource.h"
+
+#include <media/stagefright/foundation/AHandlerReflector.h>
+
+namespace android {
+
+struct ALooper;
+struct AnotherPacketSource;
+struct MyHandler;
+
+struct NuPlayer::RTSPSource : public NuPlayer::Source {
+ RTSPSource(
+ const char *url,
+ const KeyedVector<String8, String8> *headers,
+ bool uidValid = false,
+ uid_t uid = 0);
+
+ virtual void start();
+ virtual void stop();
+
+ virtual status_t feedMoreTSData();
+
+ virtual sp<MetaData> getFormat(bool audio);
+ virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+
+ virtual status_t getDuration(int64_t *durationUs);
+ virtual status_t seekTo(int64_t seekTimeUs);
+ virtual bool isSeekable();
+
+ void onMessageReceived(const sp<AMessage> &msg);
+
+protected:
+ virtual ~RTSPSource();
+
+private:
+ enum {
+ kWhatNotify = 'noti',
+ kWhatDisconnect = 'disc',
+ };
+
+ enum State {
+ DISCONNECTED,
+ CONNECTING,
+ CONNECTED,
+ SEEKING,
+ };
+
+ enum Flags {
+ // Don't log any URLs.
+ kFlagIncognito = 1,
+ };
+
+ struct TrackInfo {
+ sp<AnotherPacketSource> mSource;
+
+ int32_t mTimeScale;
+ uint32_t mRTPTime;
+ int64_t mNormalPlaytimeUs;
+ };
+
+ AString mURL;
+ KeyedVector<String8, String8> mExtraHeaders;
+ bool mUIDValid;
+ uid_t mUID;
+ uint32_t mFlags;
+ State mState;
+ status_t mFinalResult;
+ uint32_t mDisconnectReplyID;
+
+ sp<ALooper> mLooper;
+ sp<AHandlerReflector<RTSPSource> > mReflector;
+ sp<MyHandler> mHandler;
+
+ Vector<TrackInfo> mTracks;
+ sp<AnotherPacketSource> mAudioTrack;
+ sp<AnotherPacketSource> mVideoTrack;
+
+ sp<AnotherPacketSource> getSource(bool audio);
+
+ void onConnected();
+ void onDisconnected(const sp<AMessage> &msg);
+ void finishDisconnectIfPossible();
+
+ DISALLOW_EVIL_CONSTRUCTORS(RTSPSource);
+};
+
+} // namespace android
+
+#endif // RTSP_SOURCE_H_
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9cb18de..d947760 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -681,6 +681,10 @@
static const MimeToRole kMimeToRole[] = {
{ MEDIA_MIMETYPE_AUDIO_MPEG,
"audio_decoder.mp3", "audio_encoder.mp3" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
+ "audio_decoder.mp1", "audio_encoder.mp1" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+ "audio_decoder.mp2", "audio_encoder.mp2" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB,
"audio_decoder.amrnb", "audio_encoder.amrnb" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB,
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 0b1a2af..0aeb515 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -58,7 +58,6 @@
$(TOP)/frameworks/base/include/media/stagefright/openmax \
$(TOP)/external/flac/include \
$(TOP)/external/tremolo \
- $(TOP)/frameworks/base/media/libstagefright/rtsp \
$(TOP)/external/openssl/include \
LOCAL_SHARED_LIBRARIES := \
@@ -88,7 +87,6 @@
libvpx \
libstagefright_mpeg2ts \
libstagefright_httplive \
- libstagefright_rtsp \
libstagefright_id3 \
libFLAC \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 1165af5..1c7e58d 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -22,7 +22,6 @@
#include <dlfcn.h>
-#include "include/ARTSPController.h"
#include "include/AwesomePlayer.h"
#include "include/DRMExtractor.h"
#include "include/SoftwareRenderer.h"
@@ -53,7 +52,6 @@
#include <gui/SurfaceTextureClient.h>
#include <surfaceflinger/ISurfaceComposer.h>
-#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <cutils/properties.h>
@@ -65,7 +63,6 @@
static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
-static int64_t kHighWaterMarkRTSPUs = 4000000ll; // 4secs
static const size_t kLowWaterMarkBytes = 40000;
static const size_t kHighWaterMarkBytes = 200000;
@@ -485,9 +482,6 @@
if (mConnectingDataSource != NULL) {
LOGI("interrupting the connection process");
mConnectingDataSource->disconnect();
- } else if (mConnectingRTSPController != NULL) {
- LOGI("interrupting the connection process");
- mConnectingRTSPController->disconnect();
}
if (mFlags & PREPARING_CONNECTED) {
@@ -534,11 +528,6 @@
mVideoRenderer.clear();
- if (mRTSPController != NULL) {
- mRTSPController->disconnect();
- mRTSPController.clear();
- }
-
if (mVideoSource != NULL) {
shutdownVideoDecoder_l();
}
@@ -612,10 +601,7 @@
bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
int64_t bitrate;
- if (mRTSPController != NULL) {
- *durationUs = mRTSPController->getQueueDurationUs(eos);
- return true;
- } else if (mCachedSource != NULL && getBitrate(&bitrate)) {
+ if (mCachedSource != NULL && getBitrate(&bitrate)) {
status_t finalStatus;
size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
*durationUs = cachedDataRemaining * 8000000ll / bitrate;
@@ -751,9 +737,6 @@
LOGV("cachedDurationUs = %.2f secs, eos=%d",
cachedDurationUs / 1E6, eos);
- int64_t highWaterMarkUs =
- (mRTSPController != NULL) ? kHighWaterMarkRTSPUs : kHighWaterMarkUs;
-
if ((mFlags & PLAYING) && !eos
&& (cachedDurationUs < kLowWaterMarkUs)) {
LOGI("cache is running low (%.2f secs) , pausing.",
@@ -763,7 +746,7 @@
ensureCacheIsFetching_l();
sendCacheStats();
notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDurationUs > highWaterMarkUs) {
+ } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
if (mFlags & CACHE_UNDERRUN) {
LOGI("cache has filled up (%.2f secs), resuming.",
cachedDurationUs / 1E6);
@@ -1081,7 +1064,8 @@
if (USE_SURFACE_ALLOC
&& !strncmp(component, "OMX.", 4)
- && strncmp(component, "OMX.google.", 11)) {
+ && strncmp(component, "OMX.google.", 11)
+ && strcmp(component, "OMX.Nvidia.mpeg2v.decode")) {
// Hardware decoders avoid the CPU color conversion by decoding
// directly to ANativeBuffers, so we must use a renderer that
// just pushes those buffers to the ANativeWindow.
@@ -1263,10 +1247,7 @@
}
status_t AwesomePlayer::getPosition(int64_t *positionUs) {
- if (mRTSPController != NULL) {
- *positionUs = mRTSPController->getNormalPlayTimeUs();
- }
- else if (mSeeking != NO_SEEK) {
+ if (mSeeking != NO_SEEK) {
*positionUs = mSeekTimeUs;
} else if (mVideoSource != NULL
&& (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) {
@@ -1316,25 +1297,7 @@
}
}
-// static
-void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
- static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
-}
-
-void AwesomePlayer::onRTSPSeekDone() {
- if (!mSeekNotificationSent) {
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
- }
-}
-
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
- if (mRTSPController != NULL) {
- mSeekNotificationSent = false;
- mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
- return OK;
- }
-
if (mFlags & CACHE_UNDERRUN) {
modifyFlags(CACHE_UNDERRUN, CLEAR);
play_l();
@@ -1770,7 +1733,6 @@
int64_t latenessUs = nowUs - timeUs;
if (latenessUs > 500000ll
- && mRTSPController == NULL
&& mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(
&realTimeUs, &mediaTimeUs)) {
@@ -2085,34 +2047,6 @@
return UNKNOWN_ERROR;
}
}
- } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
- if (mLooper == NULL) {
- mLooper = new ALooper;
- mLooper->setName("rtsp");
- mLooper->start();
- }
- mRTSPController = new ARTSPController(mLooper);
- mConnectingRTSPController = mRTSPController;
-
- if (mUIDValid) {
- mConnectingRTSPController->setUID(mUID);
- }
-
- mLock.unlock();
- status_t err = mRTSPController->connect(mUri.string());
- mLock.lock();
-
- mConnectingRTSPController.clear();
-
- LOGI("ARTSPController::connect returned %d", err);
-
- if (err != OK) {
- mRTSPController.clear();
- return err;
- }
-
- sp<MediaExtractor> extractor = mRTSPController.get();
- return setDataSource_l(extractor);
} else {
dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
}
@@ -2224,7 +2158,7 @@
modifyFlags(PREPARING_CONNECTED, SET);
- if (isStreamingHTTP() || mRTSPController != NULL) {
+ if (isStreamingHTTP()) {
postBufferingEvent_l();
} else {
finishAsyncPrepare_l();
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index c16b3b5..70523c1 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -20,6 +20,7 @@
#include "include/MPEG4Extractor.h"
#include "include/WAVExtractor.h"
#include "include/OggExtractor.h"
+#include "include/MPEG2PSExtractor.h"
#include "include/MPEG2TSExtractor.h"
#include "include/NuCachedSource2.h"
#include "include/HTTPBase.h"
@@ -113,6 +114,7 @@
RegisterSniffer(SniffMP3);
RegisterSniffer(SniffAAC);
RegisterSniffer(SniffAVI);
+ RegisterSniffer(SniffMPEG2PS);
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 92e84c2..34e9cd7 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -25,11 +25,11 @@
#include "include/VBRISeeker.h"
#include "include/XINGSeeker.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -289,9 +289,24 @@
GetMPEGAudioFrameSize(
header, &frame_size, &sample_rate, &num_channels, &bitrate);
+ unsigned layer = 4 - ((header >> 17) & 3);
+
mMeta = new MetaData;
- mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ switch (layer) {
+ case 1:
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+ break;
+ case 2:
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+ break;
+ case 3:
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ break;
+ default:
+ TRESPASS();
+ }
+
mMeta->setInt32(kKeySampleRate, sample_rate);
mMeta->setInt32(kKeyBitRate, bitrate * 1000);
mMeta->setInt32(kKeyChannelCount, num_channels);
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 01f1fba..444e823 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -30,6 +30,8 @@
const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
+const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I = "audio/mpeg-L1";
+const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II = "audio/mpeg-L2";
const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp";
const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";
@@ -45,6 +47,7 @@
const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA = "video/x-matroska";
const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG2PS = "video/mp2p";
const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index a8023df..2221268 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -24,6 +24,7 @@
#include "include/MPEG4Extractor.h"
#include "include/WAVExtractor.h"
#include "include/OggExtractor.h"
+#include "include/MPEG2PSExtractor.h"
#include "include/MPEG2TSExtractor.h"
#include "include/DRMExtractor.h"
#include "include/WVMExtractor.h"
@@ -115,6 +116,8 @@
ret = new WVMExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
ret = new AACExtractor(source);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
+ ret = new MPEG2PSExtractor(source);
}
if (ret != NULL) {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7c34257..86bd267 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -102,6 +102,7 @@
{ MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
{ MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, "OMX.Nvidia.mp2.decoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.decoder" },
@@ -1462,7 +1463,9 @@
mOutputPortSettingsChangedPending(false),
mLeftOverBuffer(NULL),
mPaused(false),
- mNativeWindow(!strncmp(componentName, "OMX.google.", 11)
+ mNativeWindow(
+ (!strncmp(componentName, "OMX.google.", 11)
+ || !strcmp(componentName, "OMX.Nvidia.mpeg2v.decode"))
? NULL : nativeWindow) {
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
@@ -1483,6 +1486,12 @@
static const MimeToRole kMimeToRole[] = {
{ MEDIA_MIMETYPE_AUDIO_MPEG,
"audio_decoder.mp3", "audio_encoder.mp3" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
+ "audio_decoder.mp1", "audio_encoder.mp1" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
+ "audio_decoder.mp2", "audio_encoder.mp2" },
+ { MEDIA_MIMETYPE_AUDIO_MPEG,
+ "audio_decoder.mp3", "audio_encoder.mp3" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB,
"audio_decoder.amrnb", "audio_encoder.amrnb" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB,
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 571e8be27..bb6e4cd 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -38,7 +38,7 @@
".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
- ".avi",
+ ".avi", ".mpeg", ".mpg"
};
static const size_t kNumValidExtensions =
sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
deleted file mode 100644
index 2bd5be6..0000000
--- a/media/libstagefright/include/ARTSPController.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2010 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 A_RTSP_CONTROLLER_H_
-
-#define A_RTSP_CONTROLLER_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/MediaExtractor.h>
-
-namespace android {
-
-struct ALooper;
-struct MyHandler;
-
-struct ARTSPController : public MediaExtractor {
- ARTSPController(const sp<ALooper> &looper);
-
- void setUID(uid_t uid);
-
- status_t connect(const char *url);
- void disconnect();
-
- void seekAsync(int64_t timeUs, void (*seekDoneCb)(void *), void *cookie);
-
- virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
-
- virtual sp<MetaData> getTrackMetaData(
- size_t index, uint32_t flags);
-
- int64_t getNormalPlayTimeUs();
- int64_t getQueueDurationUs(bool *eos);
-
- void onMessageReceived(const sp<AMessage> &msg);
-
- virtual uint32_t flags() const {
- // Seeking 10secs forward or backward is a very expensive operation
- // for rtsp, so let's not enable that.
- // The user can always use the seek bar.
-
- return CAN_PAUSE | CAN_SEEK;
- }
-
-protected:
- virtual ~ARTSPController();
-
-private:
- enum {
- kWhatConnectDone = 'cdon',
- kWhatDisconnectDone = 'ddon',
- kWhatSeekDone = 'sdon',
- };
-
- enum State {
- DISCONNECTED,
- CONNECTED,
- CONNECTING,
- };
-
- Mutex mLock;
- Condition mCondition;
-
- State mState;
- status_t mConnectionResult;
-
- sp<ALooper> mLooper;
- sp<MyHandler> mHandler;
- sp<AHandlerReflector<ARTSPController> > mReflector;
-
- bool mUIDValid;
- uid_t mUID;
-
- void (*mSeekDoneCb)(void *);
- void *mSeekDoneCookie;
- int64_t mLastSeekCompletedTimeUs;
-
- DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
-};
-
-} // namespace android
-
-#endif // A_RTSP_CONTROLLER_H_
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 8e73121..7d6bcad 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -38,9 +38,6 @@
struct NuCachedSource2;
struct ISurfaceTexture;
-struct ALooper;
-struct ARTSPController;
-
class DrmManagerClinet;
class DecryptHandle;
@@ -233,10 +230,6 @@
sp<HTTPBase> mConnectingDataSource;
sp<NuCachedSource2> mCachedSource;
- sp<ALooper> mLooper;
- sp<ARTSPController> mRTSPController;
- sp<ARTSPController> mConnectingRTSPController;
-
DrmManagerClient *mDrmManagerClient;
sp<DecryptHandle> mDecryptHandle;
@@ -287,9 +280,6 @@
static bool ContinuePreparation(void *cookie);
- static void OnRTSPSeekDoneWrapper(void *cookie);
- void onRTSPSeekDone();
-
bool getBitrate(int64_t *bitrate);
void finishSeekIfNecessary(int64_t videoTimeUs);
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/libstagefright/include/MPEG2PSExtractor.h
new file mode 100644
index 0000000..fb76564
--- /dev/null
+++ b/media/libstagefright/include/MPEG2PSExtractor.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MPEG2_PS_EXTRACTOR_H_
+
+#define MPEG2_PS_EXTRACTOR_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+struct ABuffer;
+struct AMessage;
+struct Track;
+struct String8;
+
+struct MPEG2PSExtractor : public MediaExtractor {
+ MPEG2PSExtractor(const sp<DataSource> &source);
+
+ virtual size_t countTracks();
+ virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+ virtual sp<MetaData> getMetaData();
+
+ virtual uint32_t flags() const;
+
+protected:
+ virtual ~MPEG2PSExtractor();
+
+private:
+ struct Track;
+ struct WrappedTrack;
+
+ mutable Mutex mLock;
+ sp<DataSource> mDataSource;
+
+ off64_t mOffset;
+ status_t mFinalResult;
+ sp<ABuffer> mBuffer;
+ KeyedVector<unsigned, sp<Track> > mTracks;
+ bool mScanning;
+
+ bool mProgramStreamMapValid;
+ KeyedVector<unsigned, unsigned> mStreamTypeByESID;
+
+ status_t feedMore();
+
+ status_t dequeueChunk();
+ ssize_t dequeuePack();
+ ssize_t dequeueSystemHeader();
+ ssize_t dequeuePES();
+
+ DISALLOW_EVIL_CONSTRUCTORS(MPEG2PSExtractor);
+};
+
+bool SniffMPEG2PS(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *);
+
+} // namespace android
+
+#endif // MPEG2_PS_EXTRACTOR_H_
+
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 388cb54..878e534 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -64,12 +64,9 @@
bool PTSTimeDeltaEstablished();
-protected:
- virtual ~ATSParser();
-
-private:
enum {
// From ISO/IEC 13818-1: 2000 (E), Table 2-29
+ STREAMTYPE_RESERVED = 0x00,
STREAMTYPE_MPEG1_VIDEO = 0x01,
STREAMTYPE_MPEG2_VIDEO = 0x02,
STREAMTYPE_MPEG1_AUDIO = 0x03,
@@ -79,6 +76,10 @@
STREAMTYPE_H264 = 0x1b,
};
+protected:
+ virtual ~ATSParser();
+
+private:
struct Program;
struct Stream;
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 4a30416..578c669 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -6,6 +6,7 @@
AnotherPacketSource.cpp \
ATSParser.cpp \
ESQueue.cpp \
+ MPEG2PSExtractor.cpp \
MPEG2TSExtractor.cpp \
LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index a56da36..b9a4826 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -585,6 +585,8 @@
return NULL;
}
+ unsigned layer = 4 - ((header >> 17) & 3);
+
sp<ABuffer> accessUnit = new ABuffer(frameSize);
memcpy(accessUnit->data(), data, frameSize);
@@ -601,7 +603,24 @@
if (mFormat == NULL) {
mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+
+ switch (layer) {
+ case 1:
+ mFormat->setCString(
+ kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
+ break;
+ case 2:
+ mFormat->setCString(
+ kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+ break;
+ case 3:
+ mFormat->setCString(
+ kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ break;
+ default:
+ TRESPASS();
+ }
+
mFormat->setInt32(kKeySampleRate, samplingRate);
mFormat->setInt32(kKeyChannelCount, numChannels);
}
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
new file mode 100644
index 0000000..f55be6e
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MPEG2PSExtractor"
+#include <utils/Log.h>
+
+#include "include/MPEG2PSExtractor.h"
+
+#include "AnotherPacketSource.h"
+#include "ESQueue.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/foundation/hexdump.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <utils/String8.h>
+
+namespace android {
+
+struct MPEG2PSExtractor::Track : public MediaSource {
+ Track(MPEG2PSExtractor *extractor,
+ unsigned stream_id, unsigned stream_type);
+
+ virtual status_t start(MetaData *params);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+ virtual ~Track();
+
+private:
+ friend struct MPEG2PSExtractor;
+
+ MPEG2PSExtractor *mExtractor;
+
+ unsigned mStreamID;
+ unsigned mStreamType;
+ ElementaryStreamQueue *mQueue;
+ sp<AnotherPacketSource> mSource;
+
+ status_t appendPESData(
+ unsigned PTS_DTS_flags,
+ uint64_t PTS, uint64_t DTS,
+ const uint8_t *data, size_t size);
+
+ DISALLOW_EVIL_CONSTRUCTORS(Track);
+};
+
+struct MPEG2PSExtractor::WrappedTrack : public MediaSource {
+ WrappedTrack(const sp<MPEG2PSExtractor> &extractor, const sp<Track> &track);
+
+ virtual status_t start(MetaData *params);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+ virtual ~WrappedTrack();
+
+private:
+ sp<MPEG2PSExtractor> mExtractor;
+ sp<MPEG2PSExtractor::Track> mTrack;
+
+ DISALLOW_EVIL_CONSTRUCTORS(WrappedTrack);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::MPEG2PSExtractor(const sp<DataSource> &source)
+ : mDataSource(source),
+ mOffset(0),
+ mFinalResult(OK),
+ mBuffer(new ABuffer(0)),
+ mScanning(true),
+ mProgramStreamMapValid(false) {
+ for (size_t i = 0; i < 500; ++i) {
+ if (feedMore() != OK) {
+ break;
+ }
+ }
+
+ // Remove all tracks that were unable to determine their format.
+ for (size_t i = mTracks.size(); i-- > 0;) {
+ if (mTracks.valueAt(i)->getFormat() == NULL) {
+ mTracks.removeItemsAt(i);
+ }
+ }
+
+ mScanning = false;
+}
+
+MPEG2PSExtractor::~MPEG2PSExtractor() {
+}
+
+size_t MPEG2PSExtractor::countTracks() {
+ return mTracks.size();
+}
+
+sp<MediaSource> MPEG2PSExtractor::getTrack(size_t index) {
+ if (index >= mTracks.size()) {
+ return NULL;
+ }
+
+ return new WrappedTrack(this, mTracks.valueAt(index));
+}
+
+sp<MetaData> MPEG2PSExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+ if (index >= mTracks.size()) {
+ return NULL;
+ }
+
+ return mTracks.valueAt(index)->getFormat();
+}
+
+sp<MetaData> MPEG2PSExtractor::getMetaData() {
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
+
+ return meta;
+}
+
+uint32_t MPEG2PSExtractor::flags() const {
+ return CAN_PAUSE;
+}
+
+status_t MPEG2PSExtractor::feedMore() {
+ Mutex::Autolock autoLock(mLock);
+
+ // How much data we're reading at a time
+ static const size_t kChunkSize = 8192;
+
+ for (;;) {
+ status_t err = dequeueChunk();
+
+ if (err == -EAGAIN && mFinalResult == OK) {
+ memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
+ mBuffer->setRange(0, mBuffer->size());
+
+ if (mBuffer->size() + kChunkSize > mBuffer->capacity()) {
+ size_t newCapacity = mBuffer->capacity() + kChunkSize;
+ sp<ABuffer> newBuffer = new ABuffer(newCapacity);
+ memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
+ newBuffer->setRange(0, mBuffer->size());
+ mBuffer = newBuffer;
+ }
+
+ ssize_t n = mDataSource->readAt(
+ mOffset, mBuffer->data() + mBuffer->size(), kChunkSize);
+
+ if (n < (ssize_t)kChunkSize) {
+ mFinalResult = (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
+ return mFinalResult;
+ }
+
+ mBuffer->setRange(mBuffer->offset(), mBuffer->size() + n);
+ mOffset += n;
+ } else if (err != OK) {
+ mFinalResult = err;
+ return err;
+ } else {
+ return OK;
+ }
+ }
+}
+
+status_t MPEG2PSExtractor::dequeueChunk() {
+ if (mBuffer->size() < 4) {
+ return -EAGAIN;
+ }
+
+ if (memcmp("\x00\x00\x01", mBuffer->data(), 3)) {
+ return ERROR_MALFORMED;
+ }
+
+ unsigned chunkType = mBuffer->data()[3];
+
+ ssize_t res;
+
+ switch (chunkType) {
+ case 0xba:
+ {
+ res = dequeuePack();
+ break;
+ }
+
+ case 0xbb:
+ {
+ res = dequeueSystemHeader();
+ break;
+ }
+
+ default:
+ {
+ res = dequeuePES();
+ break;
+ }
+ }
+
+ if (res > 0) {
+ if (mBuffer->size() < (size_t)res) {
+ return -EAGAIN;
+ }
+
+ mBuffer->setRange(mBuffer->offset() + res, mBuffer->size() - res);
+ res = OK;
+ }
+
+ return res;
+}
+
+ssize_t MPEG2PSExtractor::dequeuePack() {
+ // 32 + 2 + 3 + 1 + 15 + 1 + 15+ 1 + 9 + 1 + 22 + 1 + 1 | +5
+
+ if (mBuffer->size() < 14) {
+ return -EAGAIN;
+ }
+
+ unsigned pack_stuffing_length = mBuffer->data()[13] & 7;
+
+ return pack_stuffing_length + 14;
+}
+
+ssize_t MPEG2PSExtractor::dequeueSystemHeader() {
+ if (mBuffer->size() < 6) {
+ return -EAGAIN;
+ }
+
+ unsigned header_length = U16_AT(mBuffer->data() + 4);
+
+ return header_length + 6;
+}
+
+ssize_t MPEG2PSExtractor::dequeuePES() {
+ if (mBuffer->size() < 6) {
+ return -EAGAIN;
+ }
+
+ unsigned PES_packet_length = U16_AT(mBuffer->data() + 4);
+ CHECK_NE(PES_packet_length, 0u);
+
+ size_t n = PES_packet_length + 6;
+
+ if (mBuffer->size() < n) {
+ return -EAGAIN;
+ }
+
+ ABitReader br(mBuffer->data(), n);
+
+ unsigned packet_startcode_prefix = br.getBits(24);
+
+ LOGV("packet_startcode_prefix = 0x%08x", packet_startcode_prefix);
+
+ if (packet_startcode_prefix != 1) {
+ LOGV("Supposedly payload_unit_start=1 unit does not start "
+ "with startcode.");
+
+ return ERROR_MALFORMED;
+ }
+
+ CHECK_EQ(packet_startcode_prefix, 0x000001u);
+
+ unsigned stream_id = br.getBits(8);
+ LOGV("stream_id = 0x%02x", stream_id);
+
+ /* unsigned PES_packet_length = */br.getBits(16);
+
+ if (stream_id == 0xbc) {
+ // program_stream_map
+
+ if (!mScanning) {
+ return n;
+ }
+
+ mStreamTypeByESID.clear();
+
+ /* unsigned current_next_indicator = */br.getBits(1);
+ /* unsigned reserved = */br.getBits(2);
+ /* unsigned program_stream_map_version = */br.getBits(5);
+ /* unsigned reserved = */br.getBits(7);
+ /* unsigned marker_bit = */br.getBits(1);
+ unsigned program_stream_info_length = br.getBits(16);
+
+ size_t offset = 0;
+ while (offset < program_stream_info_length) {
+ if (offset + 2 > program_stream_info_length) {
+ return ERROR_MALFORMED;
+ }
+
+ unsigned descriptor_tag = br.getBits(8);
+ unsigned descriptor_length = br.getBits(8);
+
+ LOGI("found descriptor tag 0x%02x of length %u",
+ descriptor_tag, descriptor_length);
+
+ if (offset + 2 + descriptor_length > program_stream_info_length) {
+ return ERROR_MALFORMED;
+ }
+
+ br.skipBits(8 * descriptor_length);
+
+ offset += 2 + descriptor_length;
+ }
+
+ unsigned elementary_stream_map_length = br.getBits(16);
+
+ offset = 0;
+ while (offset < elementary_stream_map_length) {
+ if (offset + 4 > elementary_stream_map_length) {
+ return ERROR_MALFORMED;
+ }
+
+ unsigned stream_type = br.getBits(8);
+ unsigned elementary_stream_id = br.getBits(8);
+
+ LOGI("elementary stream id 0x%02x has stream type 0x%02x",
+ elementary_stream_id, stream_type);
+
+ mStreamTypeByESID.add(elementary_stream_id, stream_type);
+
+ unsigned elementary_stream_info_length = br.getBits(16);
+
+ if (offset + 4 + elementary_stream_info_length
+ > elementary_stream_map_length) {
+ return ERROR_MALFORMED;
+ }
+
+ offset += 4 + elementary_stream_info_length;
+ }
+
+ /* unsigned CRC32 = */br.getBits(32);
+
+ mProgramStreamMapValid = true;
+ } else if (stream_id != 0xbe // padding_stream
+ && stream_id != 0xbf // private_stream_2
+ && stream_id != 0xf0 // ECM
+ && stream_id != 0xf1 // EMM
+ && stream_id != 0xff // program_stream_directory
+ && stream_id != 0xf2 // DSMCC
+ && stream_id != 0xf8) { // H.222.1 type E
+ CHECK_EQ(br.getBits(2), 2u);
+
+ /* unsigned PES_scrambling_control = */br.getBits(2);
+ /* unsigned PES_priority = */br.getBits(1);
+ /* unsigned data_alignment_indicator = */br.getBits(1);
+ /* unsigned copyright = */br.getBits(1);
+ /* unsigned original_or_copy = */br.getBits(1);
+
+ unsigned PTS_DTS_flags = br.getBits(2);
+ LOGV("PTS_DTS_flags = %u", PTS_DTS_flags);
+
+ unsigned ESCR_flag = br.getBits(1);
+ LOGV("ESCR_flag = %u", ESCR_flag);
+
+ unsigned ES_rate_flag = br.getBits(1);
+ LOGV("ES_rate_flag = %u", ES_rate_flag);
+
+ unsigned DSM_trick_mode_flag = br.getBits(1);
+ LOGV("DSM_trick_mode_flag = %u", DSM_trick_mode_flag);
+
+ unsigned additional_copy_info_flag = br.getBits(1);
+ LOGV("additional_copy_info_flag = %u", additional_copy_info_flag);
+
+ /* unsigned PES_CRC_flag = */br.getBits(1);
+ /* PES_extension_flag = */br.getBits(1);
+
+ unsigned PES_header_data_length = br.getBits(8);
+ LOGV("PES_header_data_length = %u", PES_header_data_length);
+
+ unsigned optional_bytes_remaining = PES_header_data_length;
+
+ uint64_t PTS = 0, DTS = 0;
+
+ if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
+ CHECK_GE(optional_bytes_remaining, 5u);
+
+ CHECK_EQ(br.getBits(4), PTS_DTS_flags);
+
+ PTS = ((uint64_t)br.getBits(3)) << 30;
+ CHECK_EQ(br.getBits(1), 1u);
+ PTS |= ((uint64_t)br.getBits(15)) << 15;
+ CHECK_EQ(br.getBits(1), 1u);
+ PTS |= br.getBits(15);
+ CHECK_EQ(br.getBits(1), 1u);
+
+ LOGV("PTS = %llu", PTS);
+ // LOGI("PTS = %.2f secs", PTS / 90000.0f);
+
+ optional_bytes_remaining -= 5;
+
+ if (PTS_DTS_flags == 3) {
+ CHECK_GE(optional_bytes_remaining, 5u);
+
+ CHECK_EQ(br.getBits(4), 1u);
+
+ DTS = ((uint64_t)br.getBits(3)) << 30;
+ CHECK_EQ(br.getBits(1), 1u);
+ DTS |= ((uint64_t)br.getBits(15)) << 15;
+ CHECK_EQ(br.getBits(1), 1u);
+ DTS |= br.getBits(15);
+ CHECK_EQ(br.getBits(1), 1u);
+
+ LOGV("DTS = %llu", DTS);
+
+ optional_bytes_remaining -= 5;
+ }
+ }
+
+ if (ESCR_flag) {
+ CHECK_GE(optional_bytes_remaining, 6u);
+
+ br.getBits(2);
+
+ uint64_t ESCR = ((uint64_t)br.getBits(3)) << 30;
+ CHECK_EQ(br.getBits(1), 1u);
+ ESCR |= ((uint64_t)br.getBits(15)) << 15;
+ CHECK_EQ(br.getBits(1), 1u);
+ ESCR |= br.getBits(15);
+ CHECK_EQ(br.getBits(1), 1u);
+
+ LOGV("ESCR = %llu", ESCR);
+ /* unsigned ESCR_extension = */br.getBits(9);
+
+ CHECK_EQ(br.getBits(1), 1u);
+
+ optional_bytes_remaining -= 6;
+ }
+
+ if (ES_rate_flag) {
+ CHECK_GE(optional_bytes_remaining, 3u);
+
+ CHECK_EQ(br.getBits(1), 1u);
+ /* unsigned ES_rate = */br.getBits(22);
+ CHECK_EQ(br.getBits(1), 1u);
+
+ optional_bytes_remaining -= 3;
+ }
+
+ br.skipBits(optional_bytes_remaining * 8);
+
+ // ES data follows.
+
+ CHECK_GE(PES_packet_length, PES_header_data_length + 3);
+
+ unsigned dataLength =
+ PES_packet_length - 3 - PES_header_data_length;
+
+ if (br.numBitsLeft() < dataLength * 8) {
+ LOGE("PES packet does not carry enough data to contain "
+ "payload. (numBitsLeft = %d, required = %d)",
+ br.numBitsLeft(), dataLength * 8);
+
+ return ERROR_MALFORMED;
+ }
+
+ CHECK_GE(br.numBitsLeft(), dataLength * 8);
+
+ ssize_t index = mTracks.indexOfKey(stream_id);
+ if (index < 0 && mScanning) {
+ unsigned streamType;
+
+ ssize_t streamTypeIndex;
+ if (mProgramStreamMapValid
+ && (streamTypeIndex =
+ mStreamTypeByESID.indexOfKey(stream_id)) >= 0) {
+ streamType = mStreamTypeByESID.valueAt(streamTypeIndex);
+ } else if ((stream_id & ~0x1f) == 0xc0) {
+ // ISO/IEC 13818-3 or ISO/IEC 11172-3 or ISO/IEC 13818-7
+ // or ISO/IEC 14496-3 audio
+ streamType = ATSParser::STREAMTYPE_MPEG2_AUDIO;
+ } else if ((stream_id & ~0x0f) == 0xe0) {
+ // ISO/IEC 13818-2 or ISO/IEC 11172-2 or ISO/IEC 14496-2 video
+ streamType = ATSParser::STREAMTYPE_MPEG2_VIDEO;
+ } else {
+ streamType = ATSParser::STREAMTYPE_RESERVED;
+ }
+
+ index = mTracks.add(
+ stream_id, new Track(this, stream_id, streamType));
+ }
+
+ status_t err = OK;
+
+ if (index >= 0) {
+ err =
+ mTracks.editValueAt(index)->appendPESData(
+ PTS_DTS_flags, PTS, DTS, br.data(), dataLength);
+ }
+
+ br.skipBits(dataLength * 8);
+
+ if (err != OK) {
+ return err;
+ }
+ } else if (stream_id == 0xbe) { // padding_stream
+ CHECK_NE(PES_packet_length, 0u);
+ br.skipBits(PES_packet_length * 8);
+ } else {
+ CHECK_NE(PES_packet_length, 0u);
+ br.skipBits(PES_packet_length * 8);
+ }
+
+ return n;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::Track::Track(
+ MPEG2PSExtractor *extractor, unsigned stream_id, unsigned stream_type)
+ : mExtractor(extractor),
+ mStreamID(stream_id),
+ mStreamType(stream_type),
+ mQueue(NULL) {
+ bool supported = true;
+ ElementaryStreamQueue::Mode mode;
+
+ switch (mStreamType) {
+ case ATSParser::STREAMTYPE_H264:
+ mode = ElementaryStreamQueue::H264;
+ break;
+ case ATSParser::STREAMTYPE_MPEG2_AUDIO_ATDS:
+ mode = ElementaryStreamQueue::AAC;
+ break;
+ case ATSParser::STREAMTYPE_MPEG1_AUDIO:
+ case ATSParser::STREAMTYPE_MPEG2_AUDIO:
+ mode = ElementaryStreamQueue::MPEG_AUDIO;
+ break;
+
+ case ATSParser::STREAMTYPE_MPEG1_VIDEO:
+ case ATSParser::STREAMTYPE_MPEG2_VIDEO:
+ mode = ElementaryStreamQueue::MPEG_VIDEO;
+ break;
+
+ case ATSParser::STREAMTYPE_MPEG4_VIDEO:
+ mode = ElementaryStreamQueue::MPEG4_VIDEO;
+ break;
+
+ default:
+ supported = false;
+ break;
+ }
+
+ if (supported) {
+ mQueue = new ElementaryStreamQueue(mode);
+ } else {
+ LOGI("unsupported stream ID 0x%02x", stream_id);
+ }
+}
+
+MPEG2PSExtractor::Track::~Track() {
+ delete mQueue;
+ mQueue = NULL;
+}
+
+status_t MPEG2PSExtractor::Track::start(MetaData *params) {
+ if (mSource == NULL) {
+ return NO_INIT;
+ }
+
+ return mSource->start(params);
+}
+
+status_t MPEG2PSExtractor::Track::stop() {
+ if (mSource == NULL) {
+ return NO_INIT;
+ }
+
+ return mSource->stop();
+}
+
+sp<MetaData> MPEG2PSExtractor::Track::getFormat() {
+ if (mSource == NULL) {
+ return NULL;
+ }
+
+ return mSource->getFormat();
+}
+
+status_t MPEG2PSExtractor::Track::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ if (mSource == NULL) {
+ return NO_INIT;
+ }
+
+ status_t finalResult;
+ while (!mSource->hasBufferAvailable(&finalResult)) {
+ if (finalResult != OK) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ status_t err = mExtractor->feedMore();
+
+ if (err != OK) {
+ mSource->signalEOS(err);
+ }
+ }
+
+ return mSource->read(buffer, options);
+}
+
+status_t MPEG2PSExtractor::Track::appendPESData(
+ unsigned PTS_DTS_flags,
+ uint64_t PTS, uint64_t DTS,
+ const uint8_t *data, size_t size) {
+ if (mQueue == NULL) {
+ return OK;
+ }
+
+ int64_t timeUs;
+ if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) {
+ timeUs = (PTS * 100) / 9;
+ } else {
+ timeUs = 0;
+ }
+
+ status_t err = mQueue->appendData(data, size, timeUs);
+
+ if (err != OK) {
+ return err;
+ }
+
+ sp<ABuffer> accessUnit;
+ while ((accessUnit = mQueue->dequeueAccessUnit()) != NULL) {
+ if (mSource == NULL) {
+ sp<MetaData> meta = mQueue->getFormat();
+
+ if (meta != NULL) {
+ LOGV("Stream ID 0x%02x now has data.", mStreamID);
+
+ mSource = new AnotherPacketSource(meta);
+ mSource->queueAccessUnit(accessUnit);
+ }
+ } else if (mQueue->getFormat() != NULL) {
+ mSource->queueAccessUnit(accessUnit);
+ }
+ }
+
+ return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+MPEG2PSExtractor::WrappedTrack::WrappedTrack(
+ const sp<MPEG2PSExtractor> &extractor, const sp<Track> &track)
+ : mExtractor(extractor),
+ mTrack(track) {
+}
+
+MPEG2PSExtractor::WrappedTrack::~WrappedTrack() {
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::start(MetaData *params) {
+ return mTrack->start(params);
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::stop() {
+ return mTrack->stop();
+}
+
+sp<MetaData> MPEG2PSExtractor::WrappedTrack::getFormat() {
+ return mTrack->getFormat();
+}
+
+status_t MPEG2PSExtractor::WrappedTrack::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ return mTrack->read(buffer, options);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SniffMPEG2PS(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence,
+ sp<AMessage> *) {
+ uint8_t header[5];
+ if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return false;
+ }
+
+ if (memcmp("\x00\x00\x01\xba", header, 4) || (header[4] >> 6) != 1) {
+ return false;
+ }
+
+ *confidence = 0.25f; // Slightly larger than .mp3 extractor's confidence
+
+ mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2PS);
+
+ return true;
+}
+
+} // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 4ecb92f..3f4cdb5 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -34,8 +34,8 @@
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <utils/Vector.h>
@@ -402,43 +402,15 @@
return csd;
}
-static bool GetClockRate(const AString &desc, uint32_t *clockRate) {
- ssize_t slashPos = desc.find("/");
- if (slashPos < 0) {
- return false;
- }
-
- const char *s = desc.c_str() + slashPos + 1;
-
- char *end;
- unsigned long x = strtoul(s, &end, 10);
-
- if (end == s || (*end != '\0' && *end != '/')) {
- return false;
- }
-
- *clockRate = x;
-
- return true;
-}
-
APacketSource::APacketSource(
const sp<ASessionDescription> &sessionDesc, size_t index)
: mInitCheck(NO_INIT),
- mFormat(new MetaData),
- mEOSResult(OK),
- mIsAVC(false),
- mScanForIDR(true),
- mRTPTimeBase(0),
- mNormalPlayTimeBaseUs(0),
- mLastNormalPlayTimeUs(0) {
+ mFormat(new MetaData) {
unsigned long PT;
AString desc;
AString params;
sessionDesc->getFormatType(index, &PT, &desc, ¶ms);
- CHECK(GetClockRate(desc, &mClockRate));
-
int64_t durationUs;
if (sessionDesc->getDurationUs(&durationUs)) {
mFormat->setInt64(kKeyDuration, durationUs);
@@ -448,8 +420,6 @@
mInitCheck = OK;
if (!strncmp(desc.c_str(), "H264/", 5)) {
- mIsAVC = true;
-
mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
int32_t width, height;
@@ -602,137 +572,8 @@
return mInitCheck;
}
-status_t APacketSource::start(MetaData *params) {
- return OK;
-}
-
-status_t APacketSource::stop() {
- return OK;
-}
-
sp<MetaData> APacketSource::getFormat() {
return mFormat;
}
-status_t APacketSource::read(
- MediaBuffer **out, const ReadOptions *) {
- *out = NULL;
-
- Mutex::Autolock autoLock(mLock);
- while (mEOSResult == OK && mBuffers.empty()) {
- mCondition.wait(mLock);
- }
-
- if (!mBuffers.empty()) {
- const sp<ABuffer> buffer = *mBuffers.begin();
-
- updateNormalPlayTime_l(buffer);
-
- int64_t timeUs;
- CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
-
- MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
- mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
-
- *out = mediaBuffer;
-
- mBuffers.erase(mBuffers.begin());
- return OK;
- }
-
- return mEOSResult;
-}
-
-void APacketSource::updateNormalPlayTime_l(const sp<ABuffer> &buffer) {
- uint32_t rtpTime;
- CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-
- mLastNormalPlayTimeUs =
- (((double)rtpTime - (double)mRTPTimeBase) / mClockRate)
- * 1000000ll
- + mNormalPlayTimeBaseUs;
-}
-
-void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
- int32_t damaged;
- if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
- LOGV("discarding damaged AU");
- return;
- }
-
- if (mScanForIDR && mIsAVC) {
- // This pretty piece of code ensures that the first access unit
- // fed to the decoder after stream-start or seek is guaranteed to
- // be an IDR frame. This is to workaround limitations of a certain
- // hardware h.264 decoder that requires this to be the case.
-
- if (!IsIDR(buffer)) {
- LOGV("skipping AU while scanning for next IDR frame.");
- return;
- }
-
- mScanForIDR = false;
- }
-
- Mutex::Autolock autoLock(mLock);
- mBuffers.push_back(buffer);
- mCondition.signal();
-}
-
-void APacketSource::signalEOS(status_t result) {
- CHECK(result != OK);
-
- Mutex::Autolock autoLock(mLock);
- mEOSResult = result;
- mCondition.signal();
-}
-
-void APacketSource::flushQueue() {
- Mutex::Autolock autoLock(mLock);
- mBuffers.clear();
-
- mScanForIDR = true;
-}
-
-int64_t APacketSource::getNormalPlayTimeUs() {
- Mutex::Autolock autoLock(mLock);
- return mLastNormalPlayTimeUs;
-}
-
-void APacketSource::setNormalPlayTimeMapping(
- uint32_t rtpTime, int64_t normalPlayTimeUs) {
- Mutex::Autolock autoLock(mLock);
-
- mRTPTimeBase = rtpTime;
- mNormalPlayTimeBaseUs = normalPlayTimeUs;
-}
-
-int64_t APacketSource::getQueueDurationUs(bool *eos) {
- Mutex::Autolock autoLock(mLock);
-
- *eos = (mEOSResult != OK);
-
- if (mBuffers.size() < 2) {
- return 0;
- }
-
- const sp<ABuffer> first = *mBuffers.begin();
- const sp<ABuffer> last = *--mBuffers.end();
-
- int64_t firstTimeUs;
- CHECK(first->meta()->findInt64("timeUs", &firstTimeUs));
-
- int64_t lastTimeUs;
- CHECK(last->meta()->findInt64("timeUs", &lastTimeUs));
-
- if (lastTimeUs < firstTimeUs) {
- LOGE("Huh? Time moving backwards? %lld > %lld",
- firstTimeUs, lastTimeUs);
-
- return 0;
- }
-
- return lastTimeUs - firstTimeUs;
-}
-
} // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h
index 7a77fc6..530e537 100644
--- a/media/libstagefright/rtsp/APacketSource.h
+++ b/media/libstagefright/rtsp/APacketSource.h
@@ -19,63 +19,27 @@
#define A_PACKET_SOURCE_H_
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/threads.h>
-#include <utils/List.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/RefBase.h>
namespace android {
-struct ABuffer;
struct ASessionDescription;
-struct APacketSource : public MediaSource {
+struct APacketSource : public RefBase {
APacketSource(const sp<ASessionDescription> &sessionDesc, size_t index);
status_t initCheck() const;
- virtual status_t start(MetaData *params = NULL);
- virtual status_t stop();
virtual sp<MetaData> getFormat();
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
-
- void queueAccessUnit(const sp<ABuffer> &buffer);
- void signalEOS(status_t result);
-
- void flushQueue();
-
- int64_t getNormalPlayTimeUs();
-
- void setNormalPlayTimeMapping(
- uint32_t rtpTime, int64_t normalPlayTimeUs);
-
- int64_t getQueueDurationUs(bool *eos);
-
protected:
virtual ~APacketSource();
private:
status_t mInitCheck;
- Mutex mLock;
- Condition mCondition;
-
sp<MetaData> mFormat;
- List<sp<ABuffer> > mBuffers;
- status_t mEOSResult;
-
- bool mIsAVC;
- bool mScanForIDR;
-
- uint32_t mClockRate;
-
- uint32_t mRTPTimeBase;
- int64_t mNormalPlayTimeBaseUs;
-
- int64_t mLastNormalPlayTimeUs;
-
- void updateNormalPlayTime_l(const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(APacketSource);
};
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
deleted file mode 100644
index 2ebae7e..0000000
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ARTSPController.h"
-
-#include "MyHandler.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-ARTSPController::ARTSPController(const sp<ALooper> &looper)
- : mState(DISCONNECTED),
- mLooper(looper),
- mUIDValid(false),
- mSeekDoneCb(NULL),
- mSeekDoneCookie(NULL),
- mLastSeekCompletedTimeUs(-1) {
- mReflector = new AHandlerReflector<ARTSPController>(this);
- looper->registerHandler(mReflector);
-}
-
-ARTSPController::~ARTSPController() {
- CHECK_EQ((int)mState, (int)DISCONNECTED);
- mLooper->unregisterHandler(mReflector->id());
-}
-
-void ARTSPController::setUID(uid_t uid) {
- mUIDValid = true;
- mUID = uid;
-}
-
-status_t ARTSPController::connect(const char *url) {
- Mutex::Autolock autoLock(mLock);
-
- if (mState != DISCONNECTED) {
- return ERROR_ALREADY_CONNECTED;
- }
-
- sp<AMessage> msg = new AMessage(kWhatConnectDone, mReflector->id());
-
- mHandler = new MyHandler(url, mLooper, mUIDValid, mUID);
-
- mState = CONNECTING;
-
- mHandler->connect(msg);
-
- while (mState == CONNECTING) {
- mCondition.wait(mLock);
- }
-
- if (mState != CONNECTED) {
- mHandler.clear();
- }
-
- return mConnectionResult;
-}
-
-void ARTSPController::disconnect() {
- Mutex::Autolock autoLock(mLock);
-
- if (mState == CONNECTING) {
- mState = DISCONNECTED;
- mConnectionResult = ERROR_IO;
- mCondition.broadcast();
-
- mHandler.clear();
- return;
- } else if (mState != CONNECTED) {
- return;
- }
-
- sp<AMessage> msg = new AMessage(kWhatDisconnectDone, mReflector->id());
- mHandler->disconnect(msg);
-
- while (mState == CONNECTED) {
- mCondition.wait(mLock);
- }
-
- mHandler.clear();
-}
-
-void ARTSPController::seekAsync(
- int64_t timeUs,
- void (*seekDoneCb)(void *), void *cookie) {
- Mutex::Autolock autoLock(mLock);
-
- CHECK(seekDoneCb != NULL);
- CHECK(mSeekDoneCb == NULL);
-
- // Ignore seek requests that are too soon after the previous one has
- // completed, we don't want to swamp the server.
-
- bool tooEarly =
- mLastSeekCompletedTimeUs >= 0
- && ALooper::GetNowUs() < mLastSeekCompletedTimeUs + 500000ll;
-
- if (mState != CONNECTED || tooEarly) {
- (*seekDoneCb)(cookie);
- return;
- }
-
- mSeekDoneCb = seekDoneCb;
- mSeekDoneCookie = cookie;
-
- sp<AMessage> msg = new AMessage(kWhatSeekDone, mReflector->id());
- mHandler->seek(timeUs, msg);
-}
-
-size_t ARTSPController::countTracks() {
- if (mHandler == NULL) {
- return 0;
- }
-
- return mHandler->countTracks();
-}
-
-sp<MediaSource> ARTSPController::getTrack(size_t index) {
- CHECK(mHandler != NULL);
-
- return mHandler->getPacketSource(index);
-}
-
-sp<MetaData> ARTSPController::getTrackMetaData(
- size_t index, uint32_t flags) {
- CHECK(mHandler != NULL);
-
- return mHandler->getPacketSource(index)->getFormat();
-}
-
-void ARTSPController::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatConnectDone:
- {
- Mutex::Autolock autoLock(mLock);
-
- CHECK(msg->findInt32("result", &mConnectionResult));
- mState = (mConnectionResult == OK) ? CONNECTED : DISCONNECTED;
-
- mCondition.signal();
- break;
- }
-
- case kWhatDisconnectDone:
- {
- Mutex::Autolock autoLock(mLock);
- mState = DISCONNECTED;
- mCondition.signal();
- break;
- }
-
- case kWhatSeekDone:
- {
- LOGI("seek done");
-
- mLastSeekCompletedTimeUs = ALooper::GetNowUs();
-
- void (*seekDoneCb)(void *) = mSeekDoneCb;
- mSeekDoneCb = NULL;
-
- (*seekDoneCb)(mSeekDoneCookie);
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-int64_t ARTSPController::getNormalPlayTimeUs() {
- CHECK(mHandler != NULL);
- return mHandler->getNormalPlayTimeUs();
-}
-
-int64_t ARTSPController::getQueueDurationUs(bool *eos) {
- *eos = true;
-
- int64_t minQueuedDurationUs = 0;
- for (size_t i = 0; i < mHandler->countTracks(); ++i) {
- sp<APacketSource> source = mHandler->getPacketSource(i);
-
- bool newEOS;
- int64_t queuedDurationUs = source->getQueueDurationUs(&newEOS);
-
- if (!newEOS) {
- *eos = false;
- }
-
- if (i == 0 || queuedDurationUs < minQueuedDurationUs) {
- minQueuedDurationUs = queuedDurationUs;
- }
- }
-
- return minQueuedDurationUs;
-}
-
-} // namespace android
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index 8530ff3..8230347 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -15,7 +15,6 @@
ARTPSource.cpp \
ARTPWriter.cpp \
ARTSPConnection.cpp \
- ARTSPController.cpp \
ASessionDescription.cpp \
LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 8128813..af7dd23 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -94,12 +94,24 @@
}
struct MyHandler : public AHandler {
+ enum {
+ kWhatConnected = 'conn',
+ kWhatDisconnected = 'disc',
+ kWhatSeekDone = 'sdon',
+
+ kWhatAccessUnit = 'accU',
+ kWhatEOS = 'eos!',
+ kWhatSeekDiscontinuity = 'seeD',
+ kWhatNormalPlayTimeMapping = 'nptM',
+ };
+
MyHandler(
- const char *url, const sp<ALooper> &looper,
+ const char *url,
+ const sp<AMessage> ¬ify,
bool uidValid = false, uid_t uid = 0)
- : mUIDValid(uidValid),
+ : mNotify(notify),
+ mUIDValid(uidValid),
mUID(uid),
- mLooper(looper),
mNetLooper(new ALooper),
mConn(new ARTSPConnection(mUIDValid, mUID)),
mRTPConn(new ARTPConnection),
@@ -145,12 +157,9 @@
mSessionHost = host;
}
- void connect(const sp<AMessage> &doneMsg) {
- mDoneMsg = doneMsg;
-
- mLooper->registerHandler(this);
- mLooper->registerHandler(mConn);
- (1 ? mNetLooper : mLooper)->registerHandler(mRTPConn);
+ void connect() {
+ looper()->registerHandler(mConn);
+ (1 ? mNetLooper : looper())->registerHandler(mRTPConn);
sp<AMessage> notify = new AMessage('biny', id());
mConn->observeBinaryData(notify);
@@ -159,33 +168,16 @@
mConn->connect(mOriginalSessionURL.c_str(), reply);
}
- void disconnect(const sp<AMessage> &doneMsg) {
- mDoneMsg = doneMsg;
-
+ void disconnect() {
(new AMessage('abor', id()))->post();
}
- void seek(int64_t timeUs, const sp<AMessage> &doneMsg) {
+ void seek(int64_t timeUs) {
sp<AMessage> msg = new AMessage('seek', id());
msg->setInt64("time", timeUs);
- msg->setMessage("doneMsg", doneMsg);
msg->post();
}
- int64_t getNormalPlayTimeUs() {
- int64_t maxTimeUs = 0;
- for (size_t i = 0; i < mTracks.size(); ++i) {
- int64_t timeUs = mTracks.editItemAt(i).mPacketSource
- ->getNormalPlayTimeUs();
-
- if (i == 0 || timeUs > maxTimeUs) {
- maxTimeUs = timeUs;
- }
- }
-
- return maxTimeUs;
- }
-
static void addRR(const sp<ABuffer> &buf) {
uint8_t *ptr = buf->data() + buf->size();
ptr[0] = 0x80 | 0;
@@ -619,7 +611,9 @@
for (size_t i = 0; i < mTracks.size(); ++i) {
TrackInfo *info = &mTracks.editItemAt(i);
- info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
+ if (!mFirstAccessUnit) {
+ postQueueEOS(i, ERROR_END_OF_STREAM);
+ }
if (!info->mUsingInterleavedTCP) {
mRTPConn->removeStream(info->mRTPSocket, info->mRTCPSocket);
@@ -690,11 +684,10 @@
case 'quit':
{
- if (mDoneMsg != NULL) {
- mDoneMsg->setInt32("result", UNKNOWN_ERROR);
- mDoneMsg->post();
- mDoneMsg = NULL;
- }
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatDisconnected);
+ msg->setInt32("result", UNKNOWN_ERROR);
+ msg->post();
break;
}
@@ -795,17 +788,12 @@
case 'seek':
{
- sp<AMessage> doneMsg;
- CHECK(msg->findMessage("doneMsg", &doneMsg));
-
- if (mSeekPending) {
- doneMsg->post();
- break;
- }
-
if (!mSeekable) {
LOGW("This is a live stream, ignoring seek request.");
- doneMsg->post();
+
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatSeekDone);
+ msg->post();
break;
}
@@ -831,7 +819,6 @@
sp<AMessage> reply = new AMessage('see1', id());
reply->setInt64("time", timeUs);
- reply->setMessage("doneMsg", doneMsg);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -842,7 +829,8 @@
for (size_t i = 0; i < mTracks.size(); ++i) {
TrackInfo *info = &mTracks.editItemAt(i);
- info->mPacketSource->flushQueue();
+ postQueueSeekDiscontinuity(i);
+
info->mRTPAnchor = 0;
info->mNTPAnchorUs = -1;
}
@@ -866,11 +854,7 @@
request.append("\r\n");
- sp<AMessage> doneMsg;
- CHECK(msg->findMessage("doneMsg", &doneMsg));
-
sp<AMessage> reply = new AMessage('see2', id());
- reply->setMessage("doneMsg", doneMsg);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -915,10 +899,9 @@
mSeekPending = false;
- sp<AMessage> doneMsg;
- CHECK(msg->findMessage("doneMsg", &doneMsg));
-
- doneMsg->post();
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatSeekDone);
+ msg->post();
break;
}
@@ -1056,8 +1039,14 @@
LOGV("track #%d: rtpTime=%u <=> npt=%.2f", n, rtpTime, npt1);
- info->mPacketSource->setNormalPlayTimeMapping(
- rtpTime, (int64_t)(npt1 * 1E6));
+ info->mNormalPlayTimeRTP = rtpTime;
+ info->mNormalPlayTimeUs = (int64_t)(npt1 * 1E6);
+
+ if (!mFirstAccessUnit) {
+ postNormalPlayTimeMapping(
+ trackIndex,
+ info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+ }
++n;
}
@@ -1065,11 +1054,15 @@
mSeekable = true;
}
- sp<APacketSource> getPacketSource(size_t index) {
+ sp<MetaData> getTrackFormat(size_t index, int32_t *timeScale) {
CHECK_GE(index, 0u);
CHECK_LT(index, mTracks.size());
- return mTracks.editItemAt(index).mPacketSource;
+ const TrackInfo &info = mTracks.itemAt(index);
+
+ *timeScale = info.mTimeScale;
+
+ return info.mPacketSource->getFormat();
}
size_t countTracks() const {
@@ -1089,6 +1082,9 @@
int64_t mNTPAnchorUs;
int32_t mTimeScale;
+ uint32_t mNormalPlayTimeRTP;
+ int64_t mNormalPlayTimeUs;
+
sp<APacketSource> mPacketSource;
// Stores packets temporarily while no notion of time
@@ -1096,9 +1092,9 @@
List<sp<ABuffer> > mPackets;
};
+ sp<AMessage> mNotify;
bool mUIDValid;
uid_t mUID;
- sp<ALooper> mLooper;
sp<ALooper> mNetLooper;
sp<ARTSPConnection> mConn;
sp<ARTPConnection> mRTPConn;
@@ -1127,8 +1123,6 @@
Vector<TrackInfo> mTracks;
- sp<AMessage> mDoneMsg;
-
void setupTrack(size_t index) {
sp<APacketSource> source =
new APacketSource(mSessionDesc, index);
@@ -1158,6 +1152,8 @@
info->mNewSegment = true;
info->mRTPAnchor = 0;
info->mNTPAnchorUs = -1;
+ info->mNormalPlayTimeRTP = 0;
+ info->mNormalPlayTimeUs = 0ll;
unsigned long PT;
AString formatDesc;
@@ -1283,9 +1279,17 @@
LOGV("onAccessUnitComplete track %d", trackIndex);
if (mFirstAccessUnit) {
- mDoneMsg->setInt32("result", OK);
- mDoneMsg->post();
- mDoneMsg = NULL;
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatConnected);
+ msg->post();
+
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ TrackInfo *info = &mTracks.editItemAt(i);
+
+ postNormalPlayTimeMapping(
+ i,
+ info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
+ }
mFirstAccessUnit = false;
}
@@ -1303,12 +1307,12 @@
track->mPackets.erase(track->mPackets.begin());
if (addMediaTimestamp(trackIndex, track, accessUnit)) {
- track->mPacketSource->queueAccessUnit(accessUnit);
+ postQueueAccessUnit(trackIndex, accessUnit);
}
}
if (addMediaTimestamp(trackIndex, track, accessUnit)) {
- track->mPacketSource->queueAccessUnit(accessUnit);
+ postQueueAccessUnit(trackIndex, accessUnit);
}
}
@@ -1344,6 +1348,39 @@
return true;
}
+ void postQueueAccessUnit(
+ size_t trackIndex, const sp<ABuffer> &accessUnit) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatAccessUnit);
+ msg->setSize("trackIndex", trackIndex);
+ msg->setObject("accessUnit", accessUnit);
+ msg->post();
+ }
+
+ void postQueueEOS(size_t trackIndex, status_t finalResult) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatEOS);
+ msg->setSize("trackIndex", trackIndex);
+ msg->setInt32("finalResult", finalResult);
+ msg->post();
+ }
+
+ void postQueueSeekDiscontinuity(size_t trackIndex) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatSeekDiscontinuity);
+ msg->setSize("trackIndex", trackIndex);
+ msg->post();
+ }
+
+ void postNormalPlayTimeMapping(
+ size_t trackIndex, uint32_t rtpTime, int64_t nptUs) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatNormalPlayTimeMapping);
+ msg->setSize("trackIndex", trackIndex);
+ msg->setInt32("rtpTime", rtpTime);
+ msg->setInt64("nptUs", nptUs);
+ msg->post();
+ }
DISALLOW_EVIL_CONSTRUCTORS(MyHandler);
};
diff --git a/packages/BackupRestoreConfirmation/res/values/strings.xml b/packages/BackupRestoreConfirmation/res/values/strings.xml
index e91c6e2..5c90fd0 100644
--- a/packages/BackupRestoreConfirmation/res/values/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values/strings.xml
@@ -35,8 +35,12 @@
<!-- Text for message to user that they must enter their predefined backup password in order to perform this operation. -->
<string name="current_password_text">Please enter your current backup password below:</string>
+ <!-- Text for message to user that they must enter their device encryption password in order to perform this restore operation. -->
+ <string name="device_encryption_restore_text">Please enter your device encryption password below.</string>
+ <!-- Text for message to user that they must enter their device encryption password in order to perform this backup operation. -->
+ <string name="device_encryption_backup_text">Please enter your device encryption password below. This will also be used to encrypt the backup archive.</string>
- <!-- Text for message to user that they can must enter an encryption password to use for the full backup operation. -->
+ <!-- Text for message to user that they must enter an encryption password to use for the full backup operation. -->
<string name="backup_enc_password_text">Please enter a password to use for encrypting the full backup data. If this is left blank, your current backup password will be used:</string>
<!-- Text for message to user that they may optionally supply an encryption password to use for a full backup operation. -->
<string name="backup_enc_password_optional">If you wish to encrypt the full backup data, enter a password below:</string>
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index fbdf3cc..7f1d059 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -27,6 +27,8 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.storage.IMountService;
+import android.util.Log;
import android.util.Slog;
import android.view.View;
import android.widget.Button;
@@ -60,8 +62,10 @@
Handler mHandler;
IBackupManager mBackupManager;
+ IMountService mMountService;
FullObserver mObserver;
int mToken;
+ boolean mIsEncrypted;
boolean mDidAcknowledge;
TextView mStatusView;
@@ -152,6 +156,7 @@
}
mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
+ mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
mHandler = new ObserverHandler(getApplicationContext());
final Object oldObserver = getLastNonConfigurationInstance();
@@ -174,8 +179,23 @@
mEncPassword = (TextView) findViewById(R.id.enc_password);
TextView curPwDesc = (TextView) findViewById(R.id.password_desc);
- // We vary the password prompt depending on whether one is predefined
- if (!haveBackupPassword()) {
+ // We vary the password prompt depending on whether one is predefined, and whether
+ // the device is encrypted.
+ mIsEncrypted = deviceIsEncrypted();
+ if (mIsEncrypted) {
+ Log.d(TAG, "Device is encrypted: requiring encryption pw");
+ TextView pwPrompt = (TextView) findViewById(R.id.password_desc);
+ // this password is mandatory; we hide the other options during backup
+ if (layoutId == R.layout.confirm_backup) {
+ pwPrompt.setText(R.string.device_encryption_backup_text);
+ TextView tv = (TextView) findViewById(R.id.enc_password);
+ tv.setVisibility(View.GONE);
+ tv = (TextView) findViewById(R.id.enc_password_desc);
+ tv.setVisibility(View.GONE);
+ } else {
+ pwPrompt.setText(R.string.device_encryption_restore_text);
+ }
+ } else if (!haveBackupPassword()) {
curPwDesc.setVisibility(View.GONE);
mCurPassword.setVisibility(View.GONE);
if (layoutId == R.layout.confirm_backup) {
@@ -226,10 +246,12 @@
mDidAcknowledge = true;
try {
+ CharSequence encPassword = (mIsEncrypted)
+ ? mCurPassword.getText() : mEncPassword.getText();
mBackupManager.acknowledgeFullBackupOrRestore(mToken,
allow,
String.valueOf(mCurPassword.getText()),
- String.valueOf(mEncPassword.getText()),
+ String.valueOf(encPassword),
mObserver);
} catch (RemoteException e) {
// TODO: bail gracefully if we can't contact the backup manager
@@ -237,6 +259,16 @@
}
}
+ boolean deviceIsEncrypted() {
+ try {
+ return (mMountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE);
+ } catch (Exception e) {
+ // If we can't talk to the mount service we have a serious problem; fail
+ // "secure" i.e. assuming that the device is encrypted.
+ return true;
+ }
+ }
+
boolean haveBackupPassword() {
try {
return mBackupManager.hasBackupPassword();
diff --git a/packages/SystemUI/res/drawable/notification_row_bg.xml b/packages/SystemUI/res/drawable/notification_row_bg.xml
index dc626d1..1bb2172 100644
--- a/packages/SystemUI/res/drawable/notification_row_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_row_bg.xml
@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
- <item android:state_pressed="true" android:drawable="@android:color/holo_blue_light" />
+ <item android:state_pressed="true" android:drawable="@drawable/notification_item_background_color_pressed" />
<item android:state_pressed="false" android:drawable="@drawable/notification_item_background_color" />
</selector>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 3220e62..abbc89a 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -41,7 +41,7 @@
android:layout_width="match_parent"
android:layout_height="@dimen/notification_divider_height"
android:layout_alignParentBottom="true"
- android:background="@drawable/notification_item_background_color"
+ android:background="@drawable/status_bar_notification_row_background_color"
/>
</RelativeLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 5ba1908..c88d651 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -19,6 +19,7 @@
<resources>
<drawable name="notification_number_text_color">#ffffffff</drawable>
<drawable name="notification_item_background_color">#ff111111</drawable>
+ <drawable name="notification_item_background_color_pressed">#ff257390</drawable>
<drawable name="ticker_background_color">#ff1d1d1d</drawable>
<drawable name="status_bar_background">#ff000000</drawable>
<drawable name="status_bar_recents_background">#b3000000</drawable>
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index f9f5458..4ef8837 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -62,14 +62,15 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.WorkSource;
+import android.os.storage.IMountService;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.util.StringBuilderPrinter;
import com.android.internal.backup.BackupConstants;
@@ -187,6 +188,7 @@
private IActivityManager mActivityManager;
private PowerManager mPowerManager;
private AlarmManager mAlarmManager;
+ private IMountService mMountService;
IBackupManager mBackupManagerBinder;
boolean mEnabled; // access to this is synchronized on 'this'
@@ -660,6 +662,7 @@
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
mBackupManagerBinder = asInterface(asBinder());
@@ -1037,6 +1040,40 @@
// Backup password management
boolean passwordMatchesSaved(String candidatePw, int rounds) {
+ // First, on an encrypted device we require matching the device pw
+ final boolean isEncrypted;
+ try {
+ isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+ if (isEncrypted) {
+ if (DEBUG) {
+ Slog.i(TAG, "Device encrypted; verifying against device data pw");
+ }
+ // 0 means the password validated
+ // -2 means device not encrypted
+ // Any other result is either password failure or an error condition,
+ // so we refuse the match
+ final int result = mMountService.verifyEncryptionPassword(candidatePw);
+ if (result == 0) {
+ if (MORE_DEBUG) Slog.d(TAG, "Pw verifies");
+ return true;
+ } else if (result != -2) {
+ if (MORE_DEBUG) Slog.d(TAG, "Pw mismatch");
+ return false;
+ } else {
+ // ...else the device is supposedly not encrypted. HOWEVER, the
+ // query about the encryption state said that the device *is*
+ // encrypted, so ... we may have a problem. Log it and refuse
+ // the backup.
+ Slog.e(TAG, "verified encryption state mismatch against query; no match allowed");
+ return false;
+ }
+ }
+ } catch (Exception e) {
+ // Something went wrong talking to the mount service. This is very bad;
+ // assume that we fail password validation.
+ return false;
+ }
+
if (mPasswordHash == null) {
// no current password case -- require that 'currentPw' be null or empty
if (candidatePw == null || "".equals(candidatePw)) {
@@ -1114,7 +1151,15 @@
public boolean hasBackupPassword() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"hasBackupPassword");
- return (mPasswordHash != null && mPasswordHash.length() > 0);
+
+ try {
+ return (mMountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE)
+ || (mPasswordHash != null && mPasswordHash.length() > 0);
+ } catch (Exception e) {
+ // If we can't talk to the mount service we have a serious problem; fail
+ // "secure" i.e. assuming that we require a password
+ return true;
+ }
}
// Maintain persistent state around whether need to do an initialize operation.
@@ -5007,7 +5052,17 @@
params.observer = observer;
params.curPassword = curPassword;
- params.encryptPassword = encPpassword;
+
+ boolean isEncrypted;
+ try {
+ isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+ if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
+ } catch (RemoteException e) {
+ // couldn't contact the mount service; fail "safe" and assume encryption
+ Slog.e(TAG, "Unable to contact mount service!");
+ isEncrypted = true;
+ }
+ params.encryptPassword = (isEncrypted) ? curPassword : encPpassword;
if (DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
mWakelock.acquire();
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 582f0ed..5425813 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1897,6 +1897,53 @@
}
}
+ /**
+ * Validate a user-supplied password string with cryptfs
+ */
+ @Override
+ public int verifyEncryptionPassword(String password) throws RemoteException {
+ // Only the system process is permitted to validate passwords
+ if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+ throw new SecurityException("no permission to access the crypt keeper");
+ }
+
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
+ "no permission to access the crypt keeper");
+
+ if (TextUtils.isEmpty(password)) {
+ throw new IllegalArgumentException("password cannot be empty");
+ }
+
+ waitForReady();
+
+ if (DEBUG_EVENTS) {
+ Slog.i(TAG, "validating encryption password...");
+ }
+
+ try {
+ ArrayList<String> response = mConnector.doCommand("cryptfs verifypw " + password);
+ String[] tokens = response.get(0).split(" ");
+
+ if (tokens == null || tokens.length != 2) {
+ String msg = "Unexpected result from cryptfs verifypw: {";
+ if (tokens == null) msg += "null";
+ else for (int i = 0; i < tokens.length; i++) {
+ if (i != 0) msg += ',';
+ msg += tokens[i];
+ }
+ msg += '}';
+ Slog.e(TAG, msg);
+ return -1;
+ }
+
+ Slog.i(TAG, "cryptfs verifypw => " + tokens[1]);
+ return Integer.parseInt(tokens[1]);
+ } catch (NativeDaemonConnectorException e) {
+ // Encryption failed
+ return e.getCode();
+ }
+ }
+
public Parcelable[] getVolumeList() {
synchronized(mVolumes) {
int size = mVolumes.size();
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index b05705e..bcb1aa2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -238,6 +238,11 @@
* Notify our observers of an interface removal.
*/
private void notifyInterfaceRemoved(String iface) {
+ // netd already clears out quota and alerts for removed ifaces; update
+ // our sanity-checking state.
+ mActiveAlertIfaces.remove(iface);
+ mActiveQuotaIfaces.remove(iface);
+
for (INetworkManagementEventObserver obs : mObservers) {
try {
obs.interfaceRemoved(iface);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
index 3232eedc..414ae0d 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GLTextureViewActivity.java
@@ -22,9 +22,11 @@
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.opengl.GLUtils;
import android.os.Bundle;
+import android.os.Environment;
import android.util.Log;
import android.view.Gravity;
import android.view.TextureView;
@@ -39,6 +41,7 @@
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
import java.io.BufferedOutputStream;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -65,7 +68,8 @@
Bitmap b = mTextureView.getBitmap(800, 800);
BufferedOutputStream out = null;
try {
- out = new BufferedOutputStream(new FileOutputStream("/sdcard/out.png"));
+ File dump = new File(Environment.getExternalStorageDirectory(), "out.png");
+ out = new BufferedOutputStream(new FileOutputStream(dump));
b.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (FileNotFoundException e) {
e.printStackTrace();
@@ -168,10 +172,10 @@
private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
private final float[] mTriangleVerticesData = {
// X, Y, Z, U, V
- -1.0f, -1.0f, 0, 0.f, 0.f,
- 1.0f, -1.0f, 0, 1.f, 0.f,
- -1.0f, 1.0f, 0, 0.f, 1.f,
- 1.0f, 1.0f, 0, 1.f, 1.f,
+ -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
};
@Override
@@ -212,8 +216,6 @@
while (!mFinished) {
checkCurrent();
- Log.d(LOG_TAG, "Rendering frame");
-
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
checkGlError();
@@ -237,7 +239,7 @@
checkEglError();
try {
- Thread.sleep(20);
+ Thread.sleep(2000);
} catch (InterruptedException e) {
// Ignore
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index fcb57d9..0f4c668 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -17,16 +17,23 @@
package com.android.test.hwui;
import android.app.Activity;
+import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
+import android.os.Environment;
import android.view.Gravity;
+import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.IOException;
@SuppressWarnings({"UnusedDeclaration"})
@@ -44,6 +51,26 @@
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
+ mTextureView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Bitmap b = mTextureView.getBitmap(800, 800);
+ BufferedOutputStream out = null;
+ try {
+ File dump = new File(Environment.getExternalStorageDirectory(), "out.png");
+ out = new BufferedOutputStream(new FileOutputStream(dump));
+ b.compress(Bitmap.CompressFormat.PNG, 100, out);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } finally {
+ if (out != null) try {
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ });
Button button = new Button(this);
button.setText("Remove/Add");
@@ -73,6 +100,8 @@
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();
+ mCamera.setDisplayOrientation(getCameraOrientation());
+
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
previewSize.width, previewSize.height, Gravity.CENTER));
@@ -86,6 +115,34 @@
mCamera.startPreview();
}
+ private int getCameraOrientation() {
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
+ Camera.getCameraInfo(i, info);
+ if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) break;
+ }
+
+ int rotation = getWindowManager().getDefaultDisplay().getRotation();
+ int degrees = 0;
+
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ degrees = 0;
+ break;
+ case Surface.ROTATION_90:
+ degrees = 90;
+ break;
+ case Surface.ROTATION_180:
+ degrees = 180;
+ break;
+ case Surface.ROTATION_270:
+ degrees = 270;
+ break;
+ }
+
+ return (info.orientation - degrees + 360) % 360;
+ }
+
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, the Camera does all the work for us
diff --git a/tests/RenderScriptTests/ComputePerf/Android.mk b/tests/RenderScriptTests/ComputePerf/Android.mk
new file mode 100644
index 0000000..1d67d29
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsComputePerf
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml b/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml
new file mode 100644
index 0000000..a9193b5
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.rs.computeperf">
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-sdk android:minSdkVersion="14" />
+ <application android:label="Compute Perf">
+ <activity android:name="ComputePerf">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/ComputePerf/res/layout/main.xml b/tests/RenderScriptTests/ComputePerf/res/layout/main.xml
new file mode 100644
index 0000000..61cd24d
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/res/layout/main.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/displayin"
+ android:layout_width="320dip"
+ android:layout_height="266dip" />
+
+ <ImageView
+ android:id="@+id/displayout"
+ android:layout_width="320dip"
+ android:layout_height="266dip" />
+
+</LinearLayout>
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java
new file mode 100644
index 0000000..d0e089b
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/ComputePerf.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.computeperf;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.renderscript.RenderScript;
+import android.renderscript.Allocation;
+import android.widget.ImageView;
+
+public class ComputePerf extends Activity {
+
+ private LaunchTest mLT;
+ private RenderScript mRS;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ mRS = RenderScript.create(this);
+ mLT = new LaunchTest(mRS, getResources());
+ mLT.run();
+ mLT.run();
+ }
+
+}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java
new file mode 100644
index 0000000..0c29ce1
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/LaunchTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.computeperf;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class LaunchTest implements Runnable {
+ private RenderScript mRS;
+ private Allocation mAllocationX;
+ private Allocation mAllocationXY;
+ private ScriptC_launchtestxlw mScript_xlw;
+ private ScriptC_launchtestxyw mScript_xyw;
+
+ LaunchTest(RenderScript rs, Resources res) {
+ mRS = rs;
+ mScript_xlw = new ScriptC_launchtestxlw(mRS, res, R.raw.launchtestxlw);
+ mScript_xyw = new ScriptC_launchtestxyw(mRS, res, R.raw.launchtestxyw);
+ final int dim = mScript_xlw.get_dim();
+
+ mAllocationX = Allocation.createSized(rs, Element.U8(rs), dim);
+ Type.Builder tb = new Type.Builder(rs, Element.U8(rs));
+ tb.setX(dim);
+ tb.setY(dim);
+ mAllocationXY = Allocation.createTyped(rs, tb.create());
+ mScript_xlw.bind_buf(mAllocationXY);
+ }
+
+ public void run() {
+ long t = java.lang.System.currentTimeMillis();
+ mScript_xlw.forEach_root(mAllocationX);
+ mRS.finish();
+ t = java.lang.System.currentTimeMillis() - t;
+ android.util.Log.v("ComputePerf", "xlw launch test ms " + t);
+
+ t = java.lang.System.currentTimeMillis();
+ mScript_xyw.forEach_root(mAllocationXY);
+ mRS.finish();
+ t = java.lang.System.currentTimeMillis() - t;
+ android.util.Log.v("ComputePerf", "xyw launch test ms " + t);
+ }
+
+}
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs
new file mode 100644
index 0000000..47ae8ca
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxlw.rs
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.computeperf)
+
+const int dim = 2048;
+uint8_t *buf;
+
+void root(uchar *v_out, uint32_t x) {
+ uint8_t *p = buf;
+ p += x * 2048;
+ for (int i=0; i<2048; i++) {
+ p[i] = 1;
+ }
+}
+
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs
new file mode 100644
index 0000000..7f7aa95
--- /dev/null
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/launchtestxyw.rs
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.computeperf)
+
+void root(uchar *v_out, uint32_t x, uint32_t y) {
+ *v_out = 0;
+}
+
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
index b77ccb4..42b1cf1 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs
@@ -105,8 +105,8 @@
rsgMeshComputeBoundingBox(info->mMesh,
&minX, &minY, &minZ,
&maxX, &maxY, &maxZ);
- info->bBoxMin = (minX, minY, minZ);
- info->bBoxMax = (maxX, maxY, maxZ);
+ info->bBoxMin = (float3){minX, minY, minZ};
+ info->bBoxMax = (float3){maxX, maxY, maxZ};
gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
}
gLookAt = gLookAt / (float)size;
diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
index d44fd2b..05ef3ac 100644
--- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
+++ b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs
@@ -104,8 +104,8 @@
rsgMeshComputeBoundingBox(info->mMesh,
&minX, &minY, &minZ,
&maxX, &maxY, &maxZ);
- info->bBoxMin = (minX, minY, minZ);
- info->bBoxMax = (maxX, maxY, maxZ);
+ info->bBoxMin = (float3){minX, minY, minZ};
+ info->bBoxMax = (float3){maxX, maxY, maxZ};
gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f;
}
gLookAt = gLookAt / (float)size;