diff options
78 files changed, 2468 insertions, 976 deletions
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 @@ package android.view.accessibility { 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 @@ package android.view.accessibility { 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 @@ int main(int argc, char **argv) { gDisplayHistogram = false; sp<ALooper> looper; - sp<ARTSPController> rtspController; sp<LiveSession> liveSession; int res; @@ -948,7 +946,6 @@ int main(int argc, char **argv) { 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 @@ int main(int argc, char **argv) { } 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 @@ int main(int argc, char **argv) { syncInfoPresent = false; } else { extractor = MediaExtractor::Create(dataSource); + if (extractor == NULL) { fprintf(stderr, "could not create extractor.\n"); return -1; @@ -1116,13 +1098,6 @@ int main(int argc, char **argv) { } else { playSource(&client, mediaSource); } - - if (rtspController != NULL) { - rtspController->disconnect(); - rtspController.clear(); - - sleep(3); - } } if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) { diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 3290b9d..3aa159e 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -24,6 +24,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ResolveInfo; import android.database.Cursor; +import android.graphics.Rect; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -498,8 +499,24 @@ public class SearchManager ComponentName launchActivity, Bundle appSearchData, boolean globalSearch) { + startSearch(initialQuery, selectInitialQuery, launchActivity, + appSearchData, globalSearch, null); + } + + /** + * As {@link #startSearch(String, boolean, ComponentName, Bundle, boolean)} but including + * source bounds for the global search intent. + * + * @hide + */ + public void startSearch(String initialQuery, + boolean selectInitialQuery, + ComponentName launchActivity, + Bundle appSearchData, + boolean globalSearch, + Rect sourceBounds) { if (globalSearch) { - startGlobalSearch(initialQuery, selectInitialQuery, appSearchData); + startGlobalSearch(initialQuery, selectInitialQuery, appSearchData, sourceBounds); return; } @@ -520,7 +537,7 @@ public class SearchManager * Starts the global search activity. */ /* package */ void startGlobalSearch(String initialQuery, boolean selectInitialQuery, - Bundle appSearchData) { + Bundle appSearchData, Rect sourceBounds) { ComponentName globalSearchActivity = getGlobalSearchActivity(); if (globalSearchActivity == null) { Log.w(TAG, "No global search activity found."); @@ -546,6 +563,7 @@ public class SearchManager if (selectInitialQuery) { intent.putExtra(EXTRA_SELECT_QUERY, selectInitialQuery); } + intent.setSourceBounds(sourceBounds); try { if (DBG) Log.d(TAG, "Starting global search: " + intent.toUri(0)); mContext.startActivity(intent); 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 @@ public final class NfcAdapter { } /** - * 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 dalvik.system.VMDebug; 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 @@ public final class StrictMode { 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 @@ public final class StrictMode { 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 @@ public interface IMountService extends IInterface { 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 @@ public interface IMountService extends IInterface { 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 interface IMountService extends IInterface { 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 final class CalendarContract { 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 @@ public final class CalendarContract { * <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 @@ public final class CalendarContract { /** * 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 final class CalendarContract { 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 @@ public final class CalendarContract { * 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 @@ public final class CalendarContract { } } + /** + * @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 @@ public class AccessibilityRecord { * 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 @@ public class AccessibilityRecord { * 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 @@ public class AccessibilityRecord { * 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 @@ public class AccessibilityRecord { * 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 1c22a0b..ae1b66c 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -4501,6 +4501,9 @@ public class WebView extends AbsoluteLayout 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; } } @@ -5998,6 +6001,7 @@ public class WebView extends AbsoluteLayout 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()) { @@ -6280,9 +6284,16 @@ public class WebView extends AbsoluteLayout } 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; } @@ -6298,9 +6309,15 @@ public class WebView extends AbsoluteLayout // 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 @@ public class SpellChecker implements SpellCheckerSessionListener { 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 @@ public class SpellChecker implements SpellCheckerSessionListener { 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..2908a8a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -357,6 +357,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private SpellChecker mSpellChecker; + private boolean mShowSoftInputOnFocus = true; + // The alignment to pass to Layout, or null if not resolved. private Layout.Alignment mLayoutAlignment; @@ -605,6 +607,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mLinksClickable = a.getBoolean(attr, true); break; +// TODO uncomment when this attribute is made public in the next release +// also add TextView_showSoftInputOnFocus to the list of attributes above +// case com.android.internal.R.styleable.TextView_showSoftInputOnFocus: +// setShowSoftInputOnFocus(a.getBoolean(attr, true)); +// break; + case com.android.internal.R.styleable.TextView_drawableLeft: drawableLeft = a.getDrawable(attr); break; @@ -2368,6 +2376,29 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Sets whether the soft input method will be made visible when this + * TextView gets focused. The default is true. + * + * @attr ref android.R.styleable#TextView_showSoftInputOnFocus + * @hide + */ + @android.view.RemotableViewMethod + public final void setShowSoftInputOnFocus(boolean show) { + mShowSoftInputOnFocus = show; + } + + /** + * Returns whether the soft input method will be made visible when this + * TextView gets focused. The default is true. + * + * @attr ref android.R.styleable#TextView_showSoftInputOnFocus + * @hide + */ + public final boolean getShowSoftInputOnFocus() { + return mShowSoftInputOnFocus; + } + + /** * Returns the list of URLSpans attached to the text * (by {@link Linkify} or otherwise) if any. You can call * {@link URLSpan#getURL} on them to find where they link to @@ -5465,7 +5496,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && mLayout != null && onCheckIsTextEditor()) { InputMethodManager imm = InputMethodManager.peekInstance(); viewClicked(imm); - if (imm != null) { + if (imm != null && mShowSoftInputOnFocus) { imm.showSoftInput(this, 0); } } @@ -8303,7 +8334,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Show the IME, except when selecting in read-only text. final InputMethodManager imm = InputMethodManager.peekInstance(); viewClicked(imm); - if (!mTextIsSelectable) { + if (!mTextIsSelectable && mShowSoftInputOnFocus) { handled |= imm != null && imm.showSoftInput(this, 0); } @@ -9608,15 +9639,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 +9912,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 +9956,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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 +9972,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener 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())) { @@ -10117,7 +10147,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final boolean selectionStarted = mSelectionActionMode != null || extractedTextModeWillBeStartedFullScreen; - if (selectionStarted && !mTextIsSelectable && imm != null) { + if (selectionStarted && !mTextIsSelectable && imm != null && mShowSoftInputOnFocus) { // Show the IME to be able to replace text, except when selecting non editable text. imm.showSoftInput(this, 0, null); } 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 @@ public final class ExpandedMenuView extends ListView implements ItemInvoker, Men 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 @@ import android.widget.TextView; * 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 class ListMenuItemView extends LinearLayout implements MenuView.ItemView } 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 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView } // 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,$(keycharmaps),\ 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 @@ launch separate activities that use different fragments.</p> 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_VIDEO_RAW; 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_OGG; 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 @@ ifeq ($(USE_OPENGL_RENDERER),true) 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 @@ struct CacheLogger { // 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 DisplayListRenderer; 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 @@ public: 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 @@ private: */ 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 @@ namespace uirenderer { // 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* LayerRenderer::createTextureLayer(bool isOpaque) { 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 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { 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 @@ bool LayerRenderer::copyLayer(Layer* layer, SkBitmap* bitmap) { 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 @@ namespace uirenderer { class LayerRenderer: public OpenGLRenderer { public: - LayerRenderer(Layer* layer): mLayer(layer) { - } - - ~LayerRenderer() { - } + ANDROID_API LayerRenderer(Layer* layer); + virtual ~LayerRenderer(); - void prepareDirty(float left, float top, float right, float bottom, bool opaque); - void finish(); + virtual void prepareDirty(float left, float top, float right, float bottom, bool opaque); + virtual void finish(); - bool hasLayer(); - Region* getRegion(); - GLint getTargetFbo(); + virtual bool hasLayer(); + virtual Region* getRegion(); + virtual 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 @@ namespace uirenderer { // 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 DisplayList; */ 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ struct SkiaColorFilter { 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 @@ private: * 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 @@ private: * 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 @@ private: * 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 @@ struct SkiaShader { 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 @@ private: * 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 @@ private: * 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 @@ private: * 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 @@ protected: * 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 @@ private: * 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 @@ static void wc_xy(void *usr, uint32_t idx) { 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 @@ static void wc_xy(void *usr, uint32_t idx) { //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 @@ static void wc_x(void *usr, uint32_t idx) { 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 @@ static void wc_x(void *usr, uint32_t idx) { 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 @@ void rsdScriptInvokeForEach(const Context *rsc, 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 @@ void Shutdown(Context *rsc) { } 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 (* InvokeFunc_t)(void); 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 @@ public class MediaFile { 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 @@ public class MediaFile { 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 class MediaFile { 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 @@ LOCAL_SHARED_LIBRARIES := \ 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 @@ player_type getPlayerType(const char* url) } } + 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 @@ LOCAL_SRC_FILES:= \ NuPlayerDriver.cpp \ NuPlayerRenderer.cpp \ NuPlayerStreamListener.cpp \ + RTSPSource.cpp \ StreamingSource.cpp \ LOCAL_C_INCLUDES := \ @@ -15,6 +16,7 @@ LOCAL_C_INCLUDES := \ $(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 @@ void NuPlayer::setDataSource( 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 @@ void NuPlayer::finishReset() { 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 @@ private: 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 @@ void NuPlayer::Renderer::signalAudioSinkChanged() { 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 @@ struct NuPlayer::Source : public RefBase { 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 @@ void ACodec::setComponentRole( 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 @@ LOCAL_C_INCLUDES:= \ $(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 @@ LOCAL_STATIC_LIBRARIES := \ 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 @@ namespace android { 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 @@ void AwesomePlayer::reset_l() { 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 @@ void AwesomePlayer::reset_l() { mVideoRenderer.clear(); - if (mRTSPController != NULL) { - mRTSPController->disconnect(); - mRTSPController.clear(); - } - if (mVideoSource != NULL) { shutdownVideoDecoder_l(); } @@ -612,10 +601,7 @@ bool AwesomePlayer::getBitrate(int64_t *bitrate) { 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 @@ void AwesomePlayer::onBufferingUpdate() { 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 @@ void AwesomePlayer::onBufferingUpdate() { 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 @@ void AwesomePlayer::initRenderer_l() { 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::getDuration(int64_t *durationUs) { } 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 @@ status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) { } } -// 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 @@ void AwesomePlayer::onVideoEvent() { int64_t latenessUs = nowUs - timeUs; if (latenessUs > 500000ll - && mRTSPController == NULL && mAudioPlayer != NULL && mAudioPlayer->getMediaTimeMapping( &realTimeUs, &mediaTimeUs)) { @@ -2085,34 +2047,6 @@ status_t AwesomePlayer::finishSetDataSource_l() { 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 @@ void AwesomePlayer::onPrepareAsyncEvent() { 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 @@ void DataSource::RegisterDefaultSniffers() { 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 @@ MP3Extractor::MP3Extractor( 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_VIDEO_RAW = "video/raw"; 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_OGG = "application/ogg"; 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 @@ sp<MediaExtractor> MediaExtractor::Create( 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 @@ static const CodecInfo kDecoderInfo[] = { { 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 @@ OMXCodec::OMXCodec( 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 @@ void OMXCodec::setComponentRole( 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 571e8be..bb6e4cd 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -38,7 +38,7 @@ static bool FileHasAcceptableExtension(const char *extension) { ".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 MediaSource; struct NuCachedSource2; struct ISurfaceTexture; -struct ALooper; -struct ARTSPController; - class DrmManagerClinet; class DecryptHandle; @@ -233,10 +230,6 @@ private: sp<HTTPBase> mConnectingDataSource; sp<NuCachedSource2> mCachedSource; - sp<ALooper> mLooper; - sp<ARTSPController> mRTSPController; - sp<ARTSPController> mConnectingRTSPController; - DrmManagerClient *mDrmManagerClient; sp<DecryptHandle> mDecryptHandle; @@ -287,9 +280,6 @@ private: 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 @@ struct ATSParser : public RefBase { 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 @@ private: 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 @@ LOCAL_SRC_FILES:= \ 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 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() { return NULL; } + unsigned layer = 4 - ((header >> 17) & 3); + sp<ABuffer> accessUnit = new ABuffer(frameSize); memcpy(accessUnit->data(), data, frameSize); @@ -601,7 +603,24 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() { 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 @@ static sp<ABuffer> MakeMPEG4VideoCodecSpecificData( 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 @@ APacketSource::APacketSource( 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 @@ status_t APacketSource::initCheck() const { 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 @@ LOCAL_SRC_FILES:= \ 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 @@ static bool GetAttribute(const char *s, const char *key, AString *value) { } 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ struct MyHandler : public AHandler { 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 @@ private: 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 @@ private: 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 @@ private: Vector<TrackInfo> mTracks; - sp<AMessage> mDoneMsg; - void setupTrack(size_t index) { sp<APacketSource> source = new APacketSource(mSessionDesc, index); @@ -1158,6 +1152,8 @@ private: info->mNewSegment = true; info->mRTPAnchor = 0; info->mNTPAnchorUs = -1; + info->mNormalPlayTimeRTP = 0; + info->mNormalPlayTimeUs = 0ll; unsigned long PT; AString formatDesc; @@ -1283,9 +1279,17 @@ private: 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 @@ private: 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 @@ private: 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.Handler; 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 @@ public class BackupRestoreConfirmation extends Activity { Handler mHandler; IBackupManager mBackupManager; + IMountService mMountService; FullObserver mObserver; int mToken; + boolean mIsEncrypted; boolean mDidAcknowledge; TextView mStatusView; @@ -152,6 +156,7 @@ public class BackupRestoreConfirmation extends Activity { } 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 @@ public class BackupRestoreConfirmation extends Activity { 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 @@ public class BackupRestoreConfirmation extends Activity { 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 @@ public class BackupRestoreConfirmation extends Activity { } } + 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/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.ParcelFileDescriptor; 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 @@ class BackupManagerService extends IBackupManager.Stub { 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 @@ class BackupManagerService extends IBackupManager.Stub { 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 @@ class BackupManagerService extends IBackupManager.Stub { // 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 @@ class BackupManagerService extends IBackupManager.Stub { 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 @@ class BackupManagerService extends IBackupManager.Stub { 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 @@ class MountService extends IMountService.Stub } } + /** + * 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 @@ public class NetworkManagementService extends INetworkManagementService.Stub * 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 3232eed..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.app.Activity; 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.EGLDisplay; 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 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa 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 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa 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 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa while (!mFinished) { checkCurrent(); - Log.d(LOG_TAG, "Rendering frame"); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); checkGlError(); @@ -237,7 +239,7 @@ public class GLTextureViewActivity extends Activity implements TextureView.Surfa 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 @@ public class TextureViewActivity extends Activity implements TextureView.Surface 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 @@ public class TextureViewActivity extends Activity implements TextureView.Surface @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 @@ public class TextureViewActivity extends Activity implements TextureView.Surface 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 @@ void updateMeshInfo() { 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 @@ void updateMeshInfo() { 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; |