summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/provider/MediaStore.java2
-rwxr-xr-xcore/java/android/view/WindowOrientationListener.java134
-rw-r--r--core/java/android/webkit/WebView.java96
-rw-r--r--core/java/android/webkit/WebViewCore.java27
-rw-r--r--media/java/android/media/MediaFile.java2
-rw-r--r--media/java/android/media/MediaScanner.java10
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp18
-rw-r--r--media/libstagefright/codecs/avc/dec/AVCDecoder.cpp10
-rw-r--r--media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp78
-rw-r--r--media/libstagefright/include/M4vH263Decoder.h1
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, &timestamp, &bufferSize,
- &useExtTimestamp, (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data()));
+ if (PVDecodeVideoFrame(
+ mHandle, &bitstream, &timestamp, &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 &);