diff options
| -rw-r--r-- | core/java/android/provider/MediaStore.java | 2 | ||||
| -rwxr-xr-x | core/java/android/view/WindowOrientationListener.java | 134 | ||||
| -rw-r--r-- | core/java/android/webkit/WebView.java | 96 | ||||
| -rw-r--r-- | core/java/android/webkit/WebViewCore.java | 27 | ||||
| -rw-r--r-- | media/java/android/media/MediaFile.java | 2 | ||||
| -rw-r--r-- | media/java/android/media/MediaScanner.java | 10 | ||||
| -rw-r--r-- | media/libmediaplayerservice/MetadataRetrieverClient.cpp | 18 | ||||
| -rw-r--r-- | media/libstagefright/codecs/avc/dec/AVCDecoder.cpp | 10 | ||||
| -rw-r--r-- | media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp | 78 | ||||
| -rw-r--r-- | media/libstagefright/include/M4vH263Decoder.h | 1 |
10 files changed, 272 insertions, 106 deletions
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 964567a..1d06f90 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -972,7 +972,7 @@ public final class MediaStore { public static String keyFor(String name) { if (name != null) { boolean sortfirst = false; - if (name.equals(android.media.MediaFile.UNKNOWN_STRING)) { + if (name.equals(UNKNOWN_STRING)) { return "\001"; } // Check if the first character is \001. We use this to diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java index 13606e7..afd158e 100755 --- a/core/java/android/view/WindowOrientationListener.java +++ b/core/java/android/view/WindowOrientationListener.java @@ -32,14 +32,13 @@ import android.util.Log; */ public abstract class WindowOrientationListener { private static final String TAG = "WindowOrientationListener"; - private static final boolean DEBUG = false; - private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; + private static final boolean DEBUG = true; + private static final boolean localLOGV = DEBUG || Config.DEBUG; private SensorManager mSensorManager; private boolean mEnabled = false; private int mRate; private Sensor mSensor; - private SensorEventListener mSensorEventListener; - private int mSensorRotation = -1; + private SensorEventListenerImpl mSensorEventListener; /** * Creates a new WindowOrientationListener. @@ -80,7 +79,6 @@ public abstract class WindowOrientationListener { } if (mEnabled == false) { if (localLOGV) Log.d(TAG, "WindowOrientationListener enabled"); - mSensorRotation = -1; mSensorManager.registerListener(mSensorEventListener, mSensor, mRate); mEnabled = true; } @@ -96,23 +94,22 @@ public abstract class WindowOrientationListener { } if (mEnabled == true) { if (localLOGV) Log.d(TAG, "WindowOrientationListener disabled"); - mSensorRotation = -1; mSensorManager.unregisterListener(mSensorEventListener); mEnabled = false; } } public int getCurrentRotation() { - return mSensorRotation; + if (mEnabled) { + return mSensorEventListener.getCurrentRotation(); + } + return -1; } class SensorEventListenerImpl implements SensorEventListener { private static final int _DATA_X = 0; private static final int _DATA_Y = 1; private static final int _DATA_Z = 2; - // Angle around x-axis thats considered almost perfect vertical to hold - // the device - private static final int PIVOT = 20; // Angle around x-asis that's considered almost too vertical. Beyond // this angle will not result in any orientation changes. f phone faces uses, // the device is leaning backward. @@ -121,30 +118,61 @@ public abstract class WindowOrientationListener { // angle will not result in any orientation changes. If phone faces uses, // the device is leaning forward. private static final int PIVOT_LOWER = -10; - // Upper threshold limit for switching from portrait to landscape - private static final int PL_UPPER = 295; - // Lower threshold limit for switching from landscape to portrait - private static final int LP_LOWER = 320; - // Lower threshold limt for switching from portrait to landscape - private static final int PL_LOWER = 270; - // Upper threshold limit for switching from landscape to portrait - private static final int LP_UPPER = 359; - // Minimum angle which is considered landscape - private static final int LANDSCAPE_LOWER = 235; - // Minimum angle which is considered portrait - private static final int PORTRAIT_LOWER = 60; - - // Internal value used for calculating linear variant - private static final float PL_LF_UPPER = - ((float)(PL_UPPER-PL_LOWER))/((float)(PIVOT_UPPER-PIVOT)); - private static final float PL_LF_LOWER = - ((float)(PL_UPPER-PL_LOWER))/((float)(PIVOT-PIVOT_LOWER)); - // Internal value used for calculating linear variant - private static final float LP_LF_UPPER = - ((float)(LP_UPPER - LP_LOWER))/((float)(PIVOT_UPPER-PIVOT)); - private static final float LP_LF_LOWER = - ((float)(LP_UPPER - LP_LOWER))/((float)(PIVOT-PIVOT_LOWER)); + static final int ROTATION_0 = 0; + static final int ROTATION_90 = 1; + static final int ROTATION_180 = 2; + static final int ROTATION_270 = 3; + int mRotation = ROTATION_0; + + // Threshold values defined for device rotation positions + // follow order ROTATION_0 .. ROTATION_270 + final int THRESHOLDS[][][] = new int[][][] { + {{60, 135}, {135, 225}, {225, 300}}, + {{0, 45}, {45, 135}, {135, 210}, {330, 360}}, + {{0, 45}, {45, 120}, {240, 315}, {315, 360}}, + {{0, 30}, {150, 225}, {225, 315}, {315, 360}} + }; + + // Transform rotation ranges based on THRESHOLDS. This + // has to be in step with THESHOLDS + final int ROTATE_TO[][] = new int[][] { + {ROTATION_270, ROTATION_180, ROTATION_90}, + {ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0}, + {ROTATION_0, ROTATION_270, ROTATION_90, ROTATION_0}, + {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0} + }; + + // Mapping into actual Surface rotation values + final int TRANSFORM_ROTATIONS[] = new int[]{Surface.ROTATION_0, + Surface.ROTATION_90, Surface.ROTATION_180, Surface.ROTATION_270}; + + int getCurrentRotation() { + return TRANSFORM_ROTATIONS[mRotation]; + } + private void calculateNewRotation(int orientation, int zyangle) { + if (localLOGV) Log.i(TAG, orientation + ", " + zyangle + ", " + mRotation); + int rangeArr[][] = THRESHOLDS[mRotation]; + int row = -1; + for (int i = 0; i < rangeArr.length; i++) { + if ((orientation >= rangeArr[i][0]) && (orientation < rangeArr[i][1])) { + row = i; + break; + } + } + if (row != -1) { + // Find new rotation based on current rotation value. + // This also takes care of irregular rotations as well. + int rotation = ROTATE_TO[mRotation][row]; + if (localLOGV) Log.i(TAG, " new rotation = " + rotation); + if (rotation != mRotation) { + mRotation = rotation; + // Trigger orientation change + onOrientationChanged(TRANSFORM_ROTATIONS[rotation]); + } + } + } + public void onSensorChanged(SensorEvent event) { float[] values = event.values; float X = values[_DATA_X]; @@ -153,53 +181,19 @@ public abstract class WindowOrientationListener { float OneEightyOverPi = 57.29577957855f; float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z); float zyangle = (float)Math.asin(Z/gravity)*OneEightyOverPi; - int rotation = -1; if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) { // Check orientation only if the phone is flat enough // Don't trust the angle if the magnitude is small compared to the y value float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi; - int orientation = 90 - (int)Math.round(angle); + int orientation = 90 - Math.round(angle); // normalize to 0 - 359 range while (orientation >= 360) { orientation -= 360; - } + } while (orientation < 0) { orientation += 360; } - // Orientation values between LANDSCAPE_LOWER and PL_LOWER - // are considered landscape. - // Ignore orientation values between 0 and LANDSCAPE_LOWER - // For orientation values between LP_UPPER and PL_LOWER, - // the threshold gets set linearly around PIVOT. - if ((orientation >= PL_LOWER) && (orientation <= LP_UPPER)) { - float threshold; - float delta = zyangle - PIVOT; - if (mSensorRotation == Surface.ROTATION_90) { - if (delta < 0) { - // Delta is negative - threshold = LP_LOWER - (LP_LF_LOWER * delta); - } else { - threshold = LP_LOWER + (LP_LF_UPPER * delta); - } - rotation = (orientation >= threshold) ? Surface.ROTATION_0 : Surface.ROTATION_90; - } else { - if (delta < 0) { - // Delta is negative - threshold = PL_UPPER+(PL_LF_LOWER * delta); - } else { - threshold = PL_UPPER-(PL_LF_UPPER * delta); - } - rotation = (orientation <= threshold) ? Surface.ROTATION_90: Surface.ROTATION_0; - } - } else if ((orientation >= LANDSCAPE_LOWER) && (orientation < LP_LOWER)) { - rotation = Surface.ROTATION_90; - } else if ((orientation >= PL_UPPER) || (orientation <= PORTRAIT_LOWER)) { - rotation = Surface.ROTATION_0; - } - if ((rotation != -1) && (rotation != mSensorRotation)) { - mSensorRotation = rotation; - onOrientationChanged(mSensorRotation); - } + calculateNewRotation(orientation, Math.round(zyangle)); } } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 28a3404..f58446a 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -208,6 +208,9 @@ public class WebView extends AbsoluteLayout static private final boolean AUTO_REDRAW_HACK = false; // true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK private boolean mAutoRedraw; + private int mRootLayer; // C++ pointer to the root layer + private boolean mLayersHaveAnimations; + private EvaluateLayersAnimations mEvaluateThread; static final String LOGTAG = "webview"; @@ -494,6 +497,8 @@ public class WebView extends AbsoluteLayout static final int SHOW_FULLSCREEN = 29; static final int HIDE_FULLSCREEN = 30; static final int DOM_FOCUS_CHANGED = 31; + static final int IMMEDIATE_REPAINT_MSG_ID = 32; + static final int SET_ROOT_LAYER_MSG_ID = 33; static final String[] HandlerDebugString = { "REMEMBER_PASSWORD", // = 1; @@ -526,7 +531,9 @@ public class WebView extends AbsoluteLayout "DO_MOTION_UP", // = 28; "SHOW_FULLSCREEN", // = 29; "HIDE_FULLSCREEN", // = 30; - "DOM_FOCUS_CHANGED" // = 31; + "DOM_FOCUS_CHANGED", // = 31; + "IMMEDIATE_REPAINT_MSG_ID", // = 32; + "SET_ROOT_LAYER_MSG_ID" // = 33; }; // If the site doesn't use the viewport meta tag to specify the viewport, @@ -2919,6 +2926,7 @@ public class WebView extends AbsoluteLayout if (AUTO_REDRAW_HACK && mAutoRedraw) { invalidate(); } + mWebViewCore.signalRepaintDone(); } @Override @@ -2986,11 +2994,20 @@ public class WebView extends AbsoluteLayout } } + private void drawLayers(Canvas canvas) { + if (mRootLayer != 0) { + float scrollY = Math.max(mScrollY - getTitleHeight(), 0); + nativeDrawLayers(mRootLayer, mScrollX, scrollY, + mActualScale, canvas); + } + } + private void drawCoreAndCursorRing(Canvas canvas, int color, boolean drawCursorRing) { if (mDrawHistory) { canvas.scale(mActualScale, mActualScale); canvas.drawPicture(mHistoryPicture); + drawLayers(canvas); return; } @@ -3069,6 +3086,8 @@ public class WebView extends AbsoluteLayout mWebViewCore.drawContentPicture(canvas, color, animateZoom, animateScroll); + drawLayers(canvas); + if (mNativeClass == 0) return; if (mShiftIsPressed && !animateZoom) { if (mTouchSelection || mExtendSelection) { @@ -3290,6 +3309,40 @@ public class WebView extends AbsoluteLayout } /* + * This class runs the layers animations in their own thread, + * so that we do not slow down the UI. + */ + private class EvaluateLayersAnimations extends Thread { + boolean mRunning = true; + // delay corresponds to 40fps, no need to go faster. + int mDelay = 25; // in ms + public void run() { + while (mRunning) { + if (mLayersHaveAnimations && mRootLayer != 0) { + // updates is a C++ pointer to a Vector of AnimationValues + int updates = nativeEvaluateLayersAnimations(mRootLayer); + if (updates == 0) { + mRunning = false; + } + Message.obtain(mPrivateHandler, + WebView.IMMEDIATE_REPAINT_MSG_ID, + updates, 0).sendToTarget(); + } else { + mRunning = false; + } + try { + Thread.currentThread().sleep(mDelay); + } catch (InterruptedException e) { + mRunning = false; + } + } + } + public void cancel() { + mRunning = false; + } + } + + /* * This class requests an Adapter for the WebTextView which shows past * entries stored in the database. It is a Runnable so that it can be done * in its own thread, without slowing down the UI. @@ -5308,7 +5361,7 @@ public class WebView extends AbsoluteLayout // exclude INVAL_RECT_MSG_ID since it is frequently output if (DebugFlags.WEB_VIEW && msg.what != INVAL_RECT_MSG_ID) { Log.v(LOGTAG, msg.what < REMEMBER_PASSWORD || msg.what - > DOM_FOCUS_CHANGED ? Integer.toString(msg.what) + > SET_ROOT_LAYER_MSG_ID ? Integer.toString(msg.what) : HandlerDebugString[msg.what - REMEMBER_PASSWORD]); } if (mWebViewCore == null) { @@ -5564,6 +5617,38 @@ public class WebView extends AbsoluteLayout } break; } + case IMMEDIATE_REPAINT_MSG_ID: { + int updates = msg.arg1; + if (updates != 0) { + // updates is a C++ pointer to a Vector of + // AnimationValues that we apply to the layers. + // The Vector is deallocated in nativeUpdateLayers(). + nativeUpdateLayers(mRootLayer, updates); + } + invalidate(); + break; + } + case SET_ROOT_LAYER_MSG_ID: { + int oldLayer = mRootLayer; + mRootLayer = msg.arg1; + if (oldLayer > 0) { + nativeDestroyLayer(oldLayer); + } + if (mRootLayer == 0) { + mLayersHaveAnimations = false; + } + if (mEvaluateThread != null) { + mEvaluateThread.cancel(); + mEvaluateThread = null; + } + if (nativeLayersHaveAnimations(mRootLayer)) { + mLayersHaveAnimations = true; + mEvaluateThread = new EvaluateLayersAnimations(); + mEvaluateThread.start(); + } + invalidate(); + break; + } case REQUEST_FORM_DATA: AutoCompleteAdapter adapter = (AutoCompleteAdapter) msg.obj; if (mWebTextView.isSameTextField(msg.arg1)) { @@ -6251,6 +6336,13 @@ public class WebView extends AbsoluteLayout private native void nativeDebugDump(); private native void nativeDestroy(); private native void nativeDrawCursorRing(Canvas content); + private native void nativeDestroyLayer(int layer); + private native int nativeEvaluateLayersAnimations(int layer); + private native boolean nativeLayersHaveAnimations(int layer); + private native void nativeUpdateLayers(int layer, int updates); + private native void nativeDrawLayers(int layer, + float scrollX, float scrollY, + float scale, Canvas canvas); private native void nativeDrawMatches(Canvas canvas); private native void nativeDrawSelectionPointer(Canvas content, float scale, int x, int y, boolean extendSelection); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index fc22f37..2de25e8 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1908,6 +1908,33 @@ final class WebViewCore { } } + private static boolean mRepaintScheduled = false; + + /* + * Called by the WebView thread + */ + /* package */ void signalRepaintDone() { + mRepaintScheduled = false; + } + + // called by JNI + private void sendImmediateRepaint() { + if (mWebView != null && !mRepaintScheduled) { + mRepaintScheduled = true; + Message.obtain(mWebView.mPrivateHandler, + WebView.IMMEDIATE_REPAINT_MSG_ID).sendToTarget(); + } + } + + // called by JNI + private void setRootLayer(int layer) { + if (mWebView != null) { + Message.obtain(mWebView.mPrivateHandler, + WebView.SET_ROOT_LAYER_MSG_ID, + layer, 0).sendToTarget(); + } + } + /* package */ WebView getWebView() { return mWebView; } diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java index 8180a7c..a09aa5c 100644 --- a/media/java/android/media/MediaFile.java +++ b/media/java/android/media/MediaFile.java @@ -155,8 +155,6 @@ public class MediaFile { sFileExtensions = builder.toString(); } - public static final String UNKNOWN_STRING = "<unknown>"; - public static boolean isAudioFileType(int fileType) { return ((fileType >= FIRST_AUDIO_FILE_TYPE && fileType <= LAST_AUDIO_FILE_TYPE) || diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 4296afb..3a2f47a 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -637,8 +637,8 @@ public class MediaScanner map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType); if (MediaFile.isVideoFileType(mFileType)) { - map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaFile.UNKNOWN_STRING)); - map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaFile.UNKNOWN_STRING)); + map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING)); + map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaStore.UNKNOWN_STRING)); map.put(Video.Media.DURATION, mDuration); map.put(Video.Media.DATE_TAKEN, mLastModified * 1000); // FIXME - add RESOLUTION @@ -648,8 +648,8 @@ public class MediaScanner // contains date time information. map.put(Images.Media.DATE_TAKEN, mLastModified * 1000); } else if (MediaFile.isAudioFileType(mFileType)) { - map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaFile.UNKNOWN_STRING)); - map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaFile.UNKNOWN_STRING)); + map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING)); + map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaStore.UNKNOWN_STRING)); map.put(Audio.Media.COMPOSER, mComposer); if (mYear != 0) { map.put(Audio.Media.YEAR, mYear); @@ -705,7 +705,7 @@ public class MediaScanner values.put(MediaStore.MediaColumns.TITLE, title); } String album = values.getAsString(Audio.Media.ALBUM); - if (MediaFile.UNKNOWN_STRING.equals(album)) { + if (MediaStore.UNKNOWN_STRING.equals(album)) { album = values.getAsString(MediaStore.MediaColumns.DATA); // extract last path segment before file name int lastSlash = album.lastIndexOf('/'); diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp index 3572b52..66de2ee 100644 --- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp +++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp @@ -27,6 +27,7 @@ #include <string.h> #include <cutils/atomic.h> +#include <cutils/properties.h> #include <binder/MemoryDealer.h> #include <android_runtime/ActivityManager.h> #include <binder/IPCThreadState.h> @@ -107,14 +108,17 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType) switch (playerType) { #if BUILD_WITH_FULL_STAGEFRIGHT case STAGEFRIGHT_PLAYER: - // For now we are going to keep using PV for meta-data support - // until stagefright is up to par. + { + char value[PROPERTY_VALUE_MAX]; + if (property_get("media.stagefright.enable-meta", value, NULL) + && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { + LOGV("create StagefrightMetadataRetriever"); + p = new StagefrightMetadataRetriever; + break; + } - // LOGV("create StagefrightMetadataRetriever"); - // p = new StagefrightMetadataRetriever; - // break; - - // fall through to PV_PLAYER + // fall through + } #endif #ifndef NO_OPENCORE case PV_PLAYER: diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp index 484c742..22e6188 100644 --- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp +++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp @@ -262,6 +262,8 @@ status_t AVCDecoder::read( &nalType, &nalRefIdc); if (res != AVCDEC_SUCCESS) { + LOGE("cannot determine nal type"); + mInputBuffer->release(); mInputBuffer = NULL; @@ -375,18 +377,19 @@ status_t AVCDecoder::read( mInputBuffer->release(); mInputBuffer = NULL; - if (res == AVCDEC_PICTURE_READY) { + if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) { *out = new MediaBuffer(0); return OK; } else { + LOGE("failed to decode frame (res = %d)", res); return UNKNOWN_ERROR; } } case AVC_NALTYPE_SEI: { - res = PVAVCDecodeSlice( + res = PVAVCDecSEI( mHandle, const_cast<uint8_t *>(inPtr), mInputBuffer->range_length()); @@ -404,6 +407,9 @@ status_t AVCDecoder::read( case AVC_NALTYPE_AUD: { + mInputBuffer->release(); + mInputBuffer = NULL; + *out = new MediaBuffer(0); return OK; diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp index c3ef0d2..ec3ad47 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp @@ -43,8 +43,17 @@ M4vH263Decoder::M4vH263Decoder(const sp<MediaSource> &source) memset(mHandle, 0, sizeof(tagvideoDecControls)); mFormat = new MetaData; mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - CHECK(mSource->getFormat()->findInt32(kKeyWidth, &mWidth)); - CHECK(mSource->getFormat()->findInt32(kKeyHeight, &mHeight)); + + // CHECK(mSource->getFormat()->findInt32(kKeyWidth, &mWidth)); + // CHECK(mSource->getFormat()->findInt32(kKeyHeight, &mHeight)); + + // We'll ignore the dimension advertised by the source, the decoder + // appears to require us to always start with the default dimensions + // of 352 x 288 to operate correctly and later react to changes in + // the dimensions as needed. + mWidth = 352; + mHeight = 288; + mFormat->setInt32(kKeyWidth, mWidth); mFormat->setInt32(kKeyHeight, mHeight); mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar); @@ -60,6 +69,20 @@ M4vH263Decoder::~M4vH263Decoder() { mHandle = NULL; } +void M4vH263Decoder::allocateFrames(int32_t width, int32_t height) { + size_t frameSize = + (((width + 15) & - 16) * ((height + 15) & - 16) * 3) / 2; + + for (uint32_t i = 0; i < 2; ++i) { + mFrames[i] = new MediaBuffer(frameSize); + mFrames[i]->setObserver(this); + } + + PVSetReferenceYUV( + mHandle, + (uint8_t *)mFrames[1]->data()); +} + status_t M4vH263Decoder::start(MetaData *) { CHECK(!mStarted); @@ -85,7 +108,8 @@ status_t M4vH263Decoder::start(MetaData *) { const void *codec_specific_data; size_t codec_specific_data_size; - esds.getCodecSpecificInfo(&codec_specific_data, &codec_specific_data_size); + esds.getCodecSpecificInfo( + &codec_specific_data, &codec_specific_data_size); vol_data[0] = (uint8_t *) malloc(codec_specific_data_size); memcpy(vol_data[0], codec_specific_data, codec_specific_data_size); @@ -102,12 +126,14 @@ status_t M4vH263Decoder::start(MetaData *) { CHECK_EQ(mode, actualMode); PVSetPostProcType((VideoDecControls *) mHandle, 0); - size_t frameSize = (((mWidth + 15) & - 16) * ((mHeight + 15) & - 16) * 3) / 2; - for (uint32_t i = 0; i < 2; ++i) { - mFrames[i] = new MediaBuffer(frameSize); - mFrames[i]->setObserver(this); + + int32_t width, height; + PVGetVideoDimensions(mHandle, &width, &height); + if (mode == H263_MODE && (width == 0 || height == 0)) { + width = 352; + height = 288; } - PVSetReferenceYUV(mHandle, (uint8_t *)mFrames[1]->data()); + allocateFrames(width, height); mSource->start(); @@ -152,24 +178,41 @@ status_t M4vH263Decoder::read( return err; } - uint8_t *bitstream = (uint8_t *) inputBuffer->data() + inputBuffer->range_offset(); + uint8_t *bitstream = + (uint8_t *) inputBuffer->data() + inputBuffer->range_offset(); + uint32_t timestamp = 0xFFFFFFFF; int32_t bufferSize = inputBuffer->range_length(); uint32_t useExtTimestamp = 0; - CHECK_EQ(PV_TRUE, PVDecodeVideoFrame(mHandle, &bitstream, ×tamp, &bufferSize, - &useExtTimestamp, (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data())); + if (PVDecodeVideoFrame( + mHandle, &bitstream, ×tamp, &bufferSize, + &useExtTimestamp, + (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data()) + != PV_TRUE) { + LOGE("failed to decode video frame."); + + inputBuffer->release(); + inputBuffer = NULL; + + return UNKNOWN_ERROR; + } - // Check whether video dimension is changed. - // If so, notify the client about the change. int32_t width, height; PVGetVideoDimensions(mHandle, &width, &height); - if (mWidth != width || mHeight != height) { - mFormat->setInt32(kKeyWidth, width); - mFormat->setInt32(kKeyHeight, height); + if (width != mWidth || height != mHeight) { + ++mNumSamplesOutput; // The client will never get to see this frame. + + inputBuffer->release(); + inputBuffer = NULL; + + mWidth = width; + mHeight = height; + mFormat->setInt32(kKeyWidth, mWidth); + mFormat->setInt32(kKeyHeight, mHeight); + return INFO_FORMAT_CHANGED; } - PVSetReferenceYUV(mHandle, (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data()); *out = mFrames[mNumSamplesOutput & 0x01]; (*out)->add_ref(); @@ -179,6 +222,7 @@ status_t M4vH263Decoder::read( ++mNumSamplesOutput; inputBuffer->release(); + inputBuffer = NULL; return OK; } diff --git a/media/libstagefright/include/M4vH263Decoder.h b/media/libstagefright/include/M4vH263Decoder.h index 880ec7c..ec49e80 100644 --- a/media/libstagefright/include/M4vH263Decoder.h +++ b/media/libstagefright/include/M4vH263Decoder.h @@ -55,6 +55,7 @@ private: int64_t mNumSamplesOutput; + void allocateFrames(int32_t width, int32_t height); void releaseFrames(); M4vH263Decoder(const M4vH263Decoder &); |
