Merge "NDK sensor API" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index e66b2e7..9e62637 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -26353,7 +26353,9 @@
 >
 <implements name="android.view.InputQueue.Callback">
 </implements>
-<implements name="android.view.SurfaceHolder.Callback">
+<implements name="android.view.SurfaceHolder.Callback2">
+</implements>
+<implements name="android.view.ViewTreeObserver.OnGlobalLayoutListener">
 </implements>
 <constructor name="NativeActivity"
  type="android.app.NativeActivity"
@@ -26363,6 +26365,17 @@
  visibility="public"
 >
 </constructor>
+<method name="onGlobalLayout"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onInputQueueCreated"
  return="void"
  abstract="false"
@@ -26434,6 +26447,19 @@
 <parameter name="holder" type="android.view.SurfaceHolder">
 </parameter>
 </method>
+<method name="surfaceRedrawNeeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
 <field name="META_DATA_LIB_NAME"
  type="java.lang.String"
  transient="false"
@@ -142938,6 +142964,19 @@
 <parameter name="holder" type="android.view.SurfaceHolder">
 </parameter>
 </method>
+<method name="onSurfaceRedrawNeeded"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
 <method name="onTouchEvent"
  return="void"
  abstract="false"
@@ -174296,6 +174335,171 @@
  visibility="public"
 >
 </field>
+<field name="KEYCODE_BUTTON_A"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="96"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_B"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="97"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_C"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="98"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_L1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="102"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_L2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="104"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_MODE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="110"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_R1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="103"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_R2"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="105"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_SELECT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="109"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_START"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="108"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_THUMBL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="106"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_THUMBR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="107"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_X"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="99"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_Y"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="100"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYCODE_BUTTON_Z"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="101"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="KEYCODE_C"
  type="int"
  transient="false"
@@ -178903,6 +179107,29 @@
 </parameter>
 </method>
 </interface>
+<interface name="SurfaceHolder.Callback2"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.view.SurfaceHolder.Callback">
+</implements>
+<method name="surfaceRedrawNeeded"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="holder" type="android.view.SurfaceHolder">
+</parameter>
+</method>
+</interface>
 <class name="SurfaceView"
  extends="android.view.View"
  abstract="false"
@@ -187492,7 +187719,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="callback" type="android.view.SurfaceHolder.Callback">
+<parameter name="callback" type="android.view.SurfaceHolder.Callback2">
 </parameter>
 </method>
 <method name="togglePanel"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 63bbf9c..167bd3c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -67,6 +67,7 @@
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
+import android.net.DownloadManager;
 import android.net.ThrottleManager;
 import android.net.IThrottleManager;
 import android.net.Uri;
@@ -199,6 +200,7 @@
     private DropBoxManager mDropBoxManager = null;
     private DevicePolicyManager mDevicePolicyManager = null;
     private UiModeManager mUiModeManager = null;
+    private DownloadManager mDownloadManager = null;
 
     private final Object mSync = new Object();
 
@@ -973,6 +975,8 @@
             return getDevicePolicyManager();
         } else if (UI_MODE_SERVICE.equals(name)) {
             return getUiModeManager();
+        } else if (DOWNLOAD_SERVICE.equals(name)) {
+            return getDownloadManager();
         }
 
         return null;
@@ -1191,6 +1195,15 @@
         return mUiModeManager;
     }
 
+    private DownloadManager getDownloadManager() {
+        synchronized (mSync) {
+            if (mDownloadManager == null) {
+                mDownloadManager = new DownloadManager(getContentResolver());
+            }
+        }
+        return mDownloadManager;
+    }
+
     @Override
     public int checkPermission(String permission, int pid, int uid) {
         if (permission == null) {
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index d72dda7..ccc9ae3 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -2,6 +2,7 @@
 
 import dalvik.system.PathClassLoader;
 
+import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -11,12 +12,16 @@
 import android.os.Environment;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.util.AttributeSet;
 import android.view.InputChannel;
 import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.View;
+import android.view.WindowManager;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.view.inputmethod.InputMethodManager;
 
 import java.io.File;
 
@@ -24,15 +29,26 @@
  * Convenience for implementing an activity that will be implemented
  * purely in native code.  That is, a game (or game-like thing).
  */
-public class NativeActivity extends Activity implements SurfaceHolder.Callback,
-        InputQueue.Callback {
+public class NativeActivity extends Activity implements SurfaceHolder.Callback2,
+        InputQueue.Callback, OnGlobalLayoutListener {
     public static final String META_DATA_LIB_NAME = "android.app.lib_name";
     
+    private NativeContentView mNativeContentView;
+    private InputMethodManager mIMM;
+
     private int mNativeHandle;
     
     private InputQueue mCurInputQueue;
     private SurfaceHolder mCurSurfaceHolder;
     
+    final int[] mLocation = new int[2];
+    int mLastContentX;
+    int mLastContentY;
+    int mLastContentWidth;
+    int mLastContentHeight;
+
+    private boolean mDispatchingUnhandledKey;
+
     private boolean mDestroyed;
     
     private native int loadNativeCode(String path, MessageQueue queue,
@@ -49,18 +65,44 @@
     private native void onSurfaceCreatedNative(int handle, Surface surface);
     private native void onSurfaceChangedNative(int handle, Surface surface,
             int format, int width, int height);
+    private native void onSurfaceRedrawNeededNative(int handle, Surface surface);
     private native void onSurfaceDestroyedNative(int handle);
     private native void onInputChannelCreatedNative(int handle, InputChannel channel);
     private native void onInputChannelDestroyedNative(int handle, InputChannel channel);
+    private native void onContentRectChangedNative(int handle, int x, int y, int w, int h);
+    private native void dispatchKeyEventNative(int handle, KeyEvent event);
+
+    static class NativeContentView extends View {
+        NativeActivity mActivity;
+
+        public NativeContentView(Context context) {
+            super(context);
+        }
+
+        public NativeContentView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         String libname = "main";
         ActivityInfo ai;
         
+        mIMM = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+
         getWindow().takeSurface(this);
         getWindow().takeInputQueue(this);
         getWindow().setFormat(PixelFormat.RGB_565);
+        getWindow().setSoftInputMode(
+                WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
+                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+
+        mNativeContentView = new NativeContentView(this);
+        mNativeContentView.mActivity = this;
+        setContentView(mNativeContentView);
+        mNativeContentView.requestFocus();
+        mNativeContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
         
         try {
             ai = getPackageManager().getActivityInfo(
@@ -165,6 +207,18 @@
         }
     }
     
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (mDispatchingUnhandledKey) {
+            return super.dispatchKeyEvent(event);
+        } else {
+            // Key events from the IME do not go through the input channel;
+            // we need to intercept them here to hand to the application.
+            dispatchKeyEventNative(mNativeHandle, event);
+            return true;
+        }
+    }
+
     public void surfaceCreated(SurfaceHolder holder) {
         if (!mDestroyed) {
             mCurSurfaceHolder = holder;
@@ -179,6 +233,13 @@
         }
     }
     
+    public void surfaceRedrawNeeded(SurfaceHolder holder) {
+        if (!mDestroyed) {
+            mCurSurfaceHolder = holder;
+            onSurfaceRedrawNeededNative(mNativeHandle, holder.getSurface());
+        }
+    }
+
     public void surfaceDestroyed(SurfaceHolder holder) {
         mCurSurfaceHolder = null;
         if (!mDestroyed) {
@@ -200,10 +261,32 @@
         }
     }
     
+    public void onGlobalLayout() {
+        mNativeContentView.getLocationInWindow(mLocation);
+        int w = mNativeContentView.getWidth();
+        int h = mNativeContentView.getHeight();
+        if (mLocation[0] != mLastContentX || mLocation[1] != mLastContentY
+                || w != mLastContentWidth || h != mLastContentHeight) {
+            mLastContentX = mLocation[0];
+            mLastContentY = mLocation[1];
+            mLastContentWidth = w;
+            mLastContentHeight = h;
+            if (!mDestroyed) {
+                onContentRectChangedNative(mNativeHandle, mLastContentX,
+                        mLastContentY, mLastContentWidth, mLastContentHeight);
+            }
+        }
+    }
+
     void dispatchUnhandledKeyEvent(KeyEvent event) {
-        View decor = getWindow().getDecorView();
-        if (decor != null) {
-            decor.dispatchKeyEvent(event);
+        try {
+            mDispatchingUnhandledKey = true;
+            View decor = getWindow().getDecorView();
+            if (decor != null) {
+                decor.dispatchKeyEvent(event);
+            }
+        } finally {
+            mDispatchingUnhandledKey = false;
         }
     }
     
@@ -214,4 +297,12 @@
     void setWindowFormat(int format) {
         getWindow().setFormat(format);
     }
+
+    void showIme(int mode) {
+        mIMM.showSoftInput(mNativeContentView, mode);
+    }
+
+    void hideIme(int mode) {
+        mIMM.hideSoftInputFromWindow(mNativeContentView.getWindowToken(), mode);
+    }
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 30822d4..a14bd8f 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1535,6 +1535,15 @@
     public static final String UI_MODE_SERVICE = "uimode";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.net.DownloadManager} for requesting HTTP downloads.
+     *
+     * @see #getSystemService
+     * @hide (TODO) for now
+     */
+    public static final String DOWNLOAD_SERVICE = "download";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java
new file mode 100644
index 0000000..b2a214c
--- /dev/null
+++ b/core/java/android/net/DownloadManager.java
@@ -0,0 +1,719 @@
+/*
+ * 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.
+ */
+
+package android.net;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import android.os.ParcelFileDescriptor;
+import android.provider.Downloads;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The download manager is a system service that handles long-running HTTP downloads. Clients may
+ * request that a URI be downloaded to a particular destination file. The download manager will
+ * conduct the download in the background, taking care of HTTP interactions and retrying downloads
+ * after failures or across connectivity changes and system reboots.
+ *
+ * Instances of this class should be obtained through
+ * {@link android.content.Context#getSystemService(String)} by passing
+ * {@link android.content.Context#DOWNLOAD_SERVICE}.
+ *
+ * @hide
+ */
+public class DownloadManager {
+    /**
+     * An identifier for a particular download, unique across the system.  Clients use this ID to
+     * make subsequent calls related to the download.
+     */
+    public final static String COLUMN_ID = "id";
+
+    /**
+     * The client-supplied title for this download.  This will be displayed in system notifications,
+     * if enabled.
+     */
+    public final static String COLUMN_TITLE = "title";
+
+    /**
+     * The client-supplied description of this download.  This will be displayed in system
+     * notifications, if enabled.
+     */
+    public final static String COLUMN_DESCRIPTION = "description";
+
+    /**
+     * URI to be downloaded.
+     */
+    public final static String COLUMN_URI = "uri";
+
+    /**
+     * Internet Media Type of the downloaded file.  This will be filled in based on the server's
+     * response once the download has started.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1590.txt">RFC 1590, defining Media Types</a>
+     */
+    public final static String COLUMN_MEDIA_TYPE = "media_type";
+
+    /**
+     * Total size of the download in bytes.  This will be filled in once the download starts.
+     */
+    public final static String COLUMN_TOTAL_SIZE_BYTES = "total_size";
+
+    /**
+     * Uri where downloaded file will be stored.  If a destination is supplied by client, that URI
+     * will be used here.  Otherwise, the value will be filled in with a generated URI once the
+     * download has started.
+     */
+    public final static String COLUMN_LOCAL_URI = "local_uri";
+
+    /**
+     * Current status of the download, as one of the STATUS_* constants.
+     */
+    public final static String COLUMN_STATUS = "status";
+
+    /**
+     * Indicates the type of error that occurred, when {@link #COLUMN_STATUS} is
+     * {@link #STATUS_FAILED}.  If an HTTP error occurred, this will hold the HTTP status code as
+     * defined in RFC 2616.  Otherwise, it will hold one of the ERROR_* constants.
+     *
+     * If {@link #COLUMN_STATUS} is not {@link #STATUS_FAILED}, this column's value is undefined.
+     *
+     * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1">RFC 2616
+     * status codes</a>
+     */
+    public final static String COLUMN_ERROR_CODE = "error_code";
+
+    /**
+     * Number of bytes download so far.
+     */
+    public final static String COLUMN_BYTES_DOWNLOADED_SO_FAR = "bytes_so_far";
+
+    /**
+     * Timestamp when the download was requested, in {@link System#currentTimeMillis
+     * System.currentTimeMillis()} (wall clock time in UTC).
+     */
+    public final static String COLUMN_REQUESTED_TIMESTAMP = "requested_timestamp";
+
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download is waiting to start.
+     */
+    public final static int STATUS_PENDING = 1 << 0;
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download is currently running.
+     */
+    public final static int STATUS_RUNNING = 1 << 1;
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download is waiting to retry or resume.
+     */
+    public final static int STATUS_PAUSED = 1 << 2;
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download has successfully completed.
+     */
+    public final static int STATUS_SUCCESSFUL = 1 << 3;
+
+    /**
+     * Value of {@link #COLUMN_STATUS} when the download has failed (and will not be retried).
+     */
+    public final static int STATUS_FAILED = 1 << 4;
+
+
+    /**
+     * Value of COLUMN_ERROR_CODE when the download has completed with an error that doesn't fit
+     * under any other error code.
+     */
+    public final static int ERROR_UNKNOWN = 1000;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when a storage issue arises which doesn't fit under any
+     * other error code. Use the more specific {@link #ERROR_INSUFFICIENT_SPACE} and
+     * {@link #ERROR_DEVICE_NOT_FOUND} when appropriate.
+     */
+    public final static int ERROR_FILE_ERROR = 1001;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when an HTTP code was received that download manager
+     * can't handle.
+     */
+    public final static int ERROR_UNHANDLED_HTTP_CODE = 1002;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when an error receiving or processing data occurred at
+     * the HTTP level.
+     */
+    public final static int ERROR_HTTP_DATA_ERROR = 1004;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when there were too many redirects.
+     */
+    public final static int ERROR_TOO_MANY_REDIRECTS = 1005;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when there was insufficient storage space. Typically,
+     * this is because the SD card is full.
+     */
+    public final static int ERROR_INSUFFICIENT_SPACE = 1006;
+
+    /**
+     * Value of {@link #COLUMN_ERROR_CODE} when no external storage device was found. Typically,
+     * this is because the SD card is not mounted.
+     */
+    public final static int ERROR_DEVICE_NOT_FOUND = 1007;
+
+
+    // this array must contain all public columns
+    private static final String[] COLUMNS = new String[] {
+        COLUMN_ID,
+        COLUMN_TITLE,
+        COLUMN_DESCRIPTION,
+        COLUMN_URI,
+        COLUMN_MEDIA_TYPE,
+        COLUMN_TOTAL_SIZE_BYTES,
+        COLUMN_LOCAL_URI,
+        COLUMN_STATUS,
+        COLUMN_ERROR_CODE,
+        COLUMN_BYTES_DOWNLOADED_SO_FAR,
+        COLUMN_REQUESTED_TIMESTAMP
+    };
+
+    // columns to request from DownloadProvider
+    private static final String[] UNDERLYING_COLUMNS = new String[] {
+        Downloads.Impl._ID,
+        Downloads.COLUMN_TITLE,
+        Downloads.COLUMN_DESCRIPTION,
+        Downloads.COLUMN_URI,
+        Downloads.COLUMN_MIME_TYPE,
+        Downloads.COLUMN_TOTAL_BYTES,
+        Downloads._DATA,
+        Downloads.COLUMN_STATUS,
+        Downloads.COLUMN_CURRENT_BYTES
+    };
+
+    private static final Set<String> LONG_COLUMNS = new HashSet<String>(
+            Arrays.asList(COLUMN_ID, COLUMN_TOTAL_SIZE_BYTES, COLUMN_STATUS, COLUMN_ERROR_CODE,
+                          COLUMN_BYTES_DOWNLOADED_SO_FAR, COLUMN_REQUESTED_TIMESTAMP));
+
+    /**
+     * This class contains all the information necessary to request a new download.  The URI is the
+     * only required parameter.
+     */
+    public static class Request {
+        /**
+         * Bit flag for setShowNotification indicated a notification should be created while the
+         * download is running.
+         */
+        private static final int NOTIFICATION_WHEN_RUNNING = 1;
+
+        Uri mUri;
+        Uri mDestinationUri;
+        Map<String, String> mRequestHeaders = new HashMap<String, String>();
+        String mTitle;
+        String mDescription;
+        int mNotificationFlags;
+
+        private String mMediaType;
+
+        /**
+         * @param uri the HTTP URI to download.
+         */
+        public Request(Uri uri) {
+            if (uri == null) {
+                throw new NullPointerException();
+            }
+            String scheme = uri.getScheme();
+            if (scheme == null || !scheme.equals("http")) {
+                throw new IllegalArgumentException("Can only download HTTP URIs: " + uri);
+            }
+            mUri = uri;
+        }
+
+        /**
+         * Set the local destination for the downloaded data. Must be a file URI to a path on
+         * external storage, and the calling application must have the WRITE_EXTERNAL_STORAGE
+         * permission.
+         *
+         *  By default, downloads are saved to a generated file in the download cache and may be
+         * deleted by the download manager at any time.
+         *
+         * @return this object
+         */
+        public Request setDestinationUri(Uri uri) {
+            mDestinationUri = uri;
+            return this;
+        }
+
+        /**
+         * Set an HTTP header to be included with the download request.
+         * @param header HTTP header name
+         * @param value header value
+         * @return this object
+         */
+        public Request setRequestHeader(String header, String value) {
+            mRequestHeaders.put(header, value);
+            return this;
+        }
+
+        /**
+         * Set the title of this download, to be displayed in notifications (if enabled)
+         * @return this object
+         */
+        public Request setTitle(String title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * Set a description of this download, to be displayed in notifications (if enabled)
+         * @return this object
+         */
+        public Request setDescription(String description) {
+            mDescription = description;
+            return this;
+        }
+
+        /**
+         * Set the Internet Media Type of this download.  This will override the media type declared
+         * in the server's response.
+         * @see <a href="http://www.ietf.org/rfc/rfc1590.txt">RFC 1590, defining Media Types</a>
+         * @return this object
+         */
+        public Request setMediaType(String mediaType) {
+            mMediaType = mediaType;
+            return this;
+        }
+
+        /**
+         * Control system notifications posted by the download manager for this download.  If
+         * enabled, the download manager posts notifications about downloads through the system
+         * {@link android.app.NotificationManager}.
+         *
+         * @param flags any combination of the NOTIFICATION_* bit flags
+         * @return this object
+         */
+        public Request setShowNotification(int flags) {
+            mNotificationFlags = flags;
+            return this;
+        }
+
+        public Request setAllowedNetworkTypes(int flags) {
+            // TODO allowed networks support
+            throw new UnsupportedOperationException();
+        }
+
+        public Request setAllowedOverRoaming(boolean allowed) {
+            // TODO roaming support
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * @return ContentValues to be passed to DownloadProvider.insert()
+         */
+        ContentValues toContentValues() {
+            ContentValues values = new ContentValues();
+            assert mUri != null;
+            values.put(Downloads.COLUMN_URI, mUri.toString());
+
+            if (mDestinationUri != null) {
+                // TODO destination support
+                throw new UnsupportedOperationException();
+            } else {
+                values.put(Downloads.COLUMN_DESTINATION,
+                           Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE);
+            }
+
+            if (!mRequestHeaders.isEmpty()) {
+                // TODO request headers support
+                throw new UnsupportedOperationException();
+            }
+
+            putIfNonNull(values, Downloads.COLUMN_TITLE, mTitle);
+            putIfNonNull(values, Downloads.COLUMN_DESCRIPTION, mDescription);
+            putIfNonNull(values, Downloads.COLUMN_MIME_TYPE, mMediaType);
+
+            int visibility = Downloads.VISIBILITY_HIDDEN;
+            if ((mNotificationFlags & NOTIFICATION_WHEN_RUNNING) != 0) {
+                visibility = Downloads.VISIBILITY_VISIBLE;
+            }
+            values.put(Downloads.COLUMN_VISIBILITY, visibility);
+
+            return values;
+        }
+
+        private void putIfNonNull(ContentValues contentValues, String key, String value) {
+            if (value != null) {
+                contentValues.put(key, value);
+            }
+        }
+    }
+
+    /**
+     * This class may be used to filter download manager queries.
+     */
+    public static class Query {
+        private Long mId;
+        private Integer mStatusFlags = null;
+
+        /**
+         * Include only the download with the given ID.
+         * @return this object
+         */
+        public Query setFilterById(long id) {
+            mId = id;
+            return this;
+        }
+
+        /**
+         * Include only downloads with status matching any the given status flags.
+         * @param flags any combination of the STATUS_* bit flags
+         * @return this object
+         */
+        public Query setFilterByStatus(int flags) {
+            mStatusFlags = flags;
+            return this;
+        }
+
+        /**
+         * Run this query using the given ContentResolver.
+         * @param projection the projection to pass to ContentResolver.query()
+         * @return the Cursor returned by ContentResolver.query()
+         */
+        Cursor runQuery(ContentResolver resolver, String[] projection) {
+            Uri uri = Downloads.CONTENT_URI;
+            String selection = null;
+
+            if (mId != null) {
+                uri = Uri.withAppendedPath(uri, mId.toString());
+            }
+
+            if (mStatusFlags != null) {
+                List<String> parts = new ArrayList<String>();
+                if ((mStatusFlags & STATUS_PENDING) != 0) {
+                    parts.add(statusClause("=", Downloads.STATUS_PENDING));
+                }
+                if ((mStatusFlags & STATUS_RUNNING) != 0) {
+                    parts.add(statusClause("=", Downloads.STATUS_RUNNING));
+                }
+                if ((mStatusFlags & STATUS_PAUSED) != 0) {
+                    parts.add(statusClause("=", Downloads.STATUS_PENDING_PAUSED));
+                    parts.add(statusClause("=", Downloads.STATUS_RUNNING_PAUSED));
+                }
+                if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
+                    parts.add(statusClause("=", Downloads.STATUS_SUCCESS));
+                }
+                if ((mStatusFlags & STATUS_FAILED) != 0) {
+                    parts.add("(" + statusClause(">=", 400)
+                              + " AND " + statusClause("<", 600) + ")");
+                }
+                selection = joinStrings(" OR ", parts);
+                Log.w("DownloadManagerPublic", selection);
+            }
+            // TODO: ordering
+            return resolver.query(uri, projection, selection, null, null);
+        }
+
+        private String joinStrings(String joiner, Iterable<String> parts) {
+            StringBuilder builder = new StringBuilder();
+            boolean first = true;
+            for (String part : parts) {
+                if (!first) {
+                    builder.append(joiner);
+                }
+                builder.append(part);
+                first = false;
+            }
+            return builder.toString();
+        }
+
+        private String statusClause(String operator, int value) {
+            return Downloads.COLUMN_STATUS + operator + "'" + value + "'";
+        }
+    }
+
+    private ContentResolver mResolver;
+
+    /**
+     * @hide
+     */
+    public DownloadManager(ContentResolver resolver) {
+        mResolver = resolver;
+    }
+
+    /**
+     * Enqueue a new download.  The download will start automatically once the download manager is
+     * ready to execute it and connectivity is available.
+     *
+     * @param request the parameters specifying this download
+     * @return an ID for the download, unique across the system.  This ID is used to make future
+     * calls related to this download.
+     */
+    public long enqueue(Request request) {
+        ContentValues values = request.toContentValues();
+        Uri downloadUri = mResolver.insert(Downloads.CONTENT_URI, values);
+        long id = Long.parseLong(downloadUri.getLastPathSegment());
+        return id;
+    }
+
+    /**
+     * Cancel a download and remove it from the download manager.  The download will be stopped if
+     * it was running, and it will no longer be accessible through the download manager.  If a file
+     * was already downloaded, it will not be deleted.
+     *
+     * @param id the ID of the download
+     */
+    public void remove(long id) {
+        int numDeleted = mResolver.delete(getDownloadUri(id), null, null);
+        if (numDeleted == 0) {
+            throw new IllegalArgumentException("Download " + id + " does not exist");
+        }
+    }
+
+    /**
+     * Query the download manager about downloads that have been requested.
+     * @param query parameters specifying filters for this query
+     * @return a Cursor over the result set of downloads, with columns consisting of all the
+     * COLUMN_* constants.
+     */
+    public Cursor query(Query query) {
+        Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS);
+        return new CursorTranslator(underlyingCursor);
+    }
+
+    /**
+     * Open a downloaded file for reading.  The download must have completed.
+     * @param id the ID of the download
+     * @return a read-only {@link ParcelFileDescriptor}
+     * @throws FileNotFoundException if the destination file does not already exist
+     */
+    public ParcelFileDescriptor openDownloadedFile(long id) throws FileNotFoundException {
+        return mResolver.openFileDescriptor(getDownloadUri(id), "r");
+    }
+
+    /**
+     * Get the DownloadProvider URI for the download with the given ID.
+     */
+    private Uri getDownloadUri(long id) {
+        Uri downloadUri = Uri.withAppendedPath(Downloads.CONTENT_URI, Long.toString(id));
+        return downloadUri;
+    }
+
+    /**
+     * This class wraps a cursor returned by DownloadProvider -- the "underlying cursor" -- and
+     * presents a different set of columns, those defined in the DownloadManager.COLUMN_* constants.
+     * Some columns correspond directly to underlying values while others are computed from
+     * underlying data.
+     */
+    private static class CursorTranslator extends CursorWrapper {
+        public CursorTranslator(Cursor cursor) {
+            super(cursor);
+        }
+
+        @Override
+        public int getColumnIndex(String columnName) {
+            return Arrays.asList(COLUMNS).indexOf(columnName);
+        }
+
+        @Override
+        public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException {
+            int index = getColumnIndex(columnName);
+            if (index == -1) {
+                throw new IllegalArgumentException();
+            }
+            return index;
+        }
+
+        @Override
+        public String getColumnName(int columnIndex) {
+            int numColumns = COLUMNS.length;
+            if (columnIndex < 0 || columnIndex >= numColumns) {
+                throw new IllegalArgumentException("Invalid column index " + columnIndex + ", "
+                                                   + numColumns + " columns exist");
+            }
+            return COLUMNS[columnIndex];
+        }
+
+        @Override
+        public String[] getColumnNames() {
+            String[] returnColumns = new String[COLUMNS.length];
+            System.arraycopy(COLUMNS, 0, returnColumns, 0, COLUMNS.length);
+            return returnColumns;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return COLUMNS.length;
+        }
+
+        @Override
+        public byte[] getBlob(int columnIndex) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public double getDouble(int columnIndex) {
+            return getLong(columnIndex);
+        }
+
+        private boolean isLongColumn(String column) {
+            return LONG_COLUMNS.contains(column);
+        }
+
+        @Override
+        public float getFloat(int columnIndex) {
+            return (float) getDouble(columnIndex);
+        }
+
+        @Override
+        public int getInt(int columnIndex) {
+            return (int) getLong(columnIndex);
+        }
+
+        @Override
+        public long getLong(int columnIndex) {
+            return translateLong(getColumnName(columnIndex));
+        }
+
+        @Override
+        public short getShort(int columnIndex) {
+            return (short) getLong(columnIndex);
+        }
+
+        @Override
+        public String getString(int columnIndex) {
+            return translateString(getColumnName(columnIndex));
+        }
+
+        private String translateString(String column) {
+            if (isLongColumn(column)) {
+                return Long.toString(translateLong(column));
+            }
+            if (column.equals(COLUMN_TITLE)) {
+                return getUnderlyingString(Downloads.COLUMN_TITLE);
+            }
+            if (column.equals(COLUMN_DESCRIPTION)) {
+                return getUnderlyingString(Downloads.COLUMN_DESCRIPTION);
+            }
+            if (column.equals(COLUMN_URI)) {
+                return getUnderlyingString(Downloads.COLUMN_URI);
+            }
+            if (column.equals(COLUMN_MEDIA_TYPE)) {
+                return getUnderlyingString(Downloads.COLUMN_MIME_TYPE);
+            }
+            assert column.equals(COLUMN_LOCAL_URI);
+            return Uri.fromParts("file", getUnderlyingString(Downloads._DATA), null).toString();
+        }
+
+        private long translateLong(String column) {
+            if (!isLongColumn(column)) {
+                // mimic behavior of underlying cursor -- most likely, throw NumberFormatException
+                return Long.valueOf(translateString(column));
+            }
+
+            if (column.equals(COLUMN_ID)) {
+                return getUnderlyingLong(Downloads.Impl._ID);
+            }
+            if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
+                return getUnderlyingLong(Downloads.COLUMN_TOTAL_BYTES);
+            }
+            if (column.equals(COLUMN_STATUS)) {
+                return translateStatus((int) getUnderlyingLong(Downloads.COLUMN_STATUS));
+            }
+            if (column.equals(COLUMN_ERROR_CODE)) {
+                return translateErrorCode((int) getUnderlyingLong(Downloads.COLUMN_STATUS));
+            }
+            if (column.equals(COLUMN_BYTES_DOWNLOADED_SO_FAR)) {
+                return getUnderlyingLong(Downloads.COLUMN_CURRENT_BYTES);
+            }
+            assert column.equals(COLUMN_REQUESTED_TIMESTAMP);
+            throw new UnsupportedOperationException(); // TODO
+        }
+
+        private long translateErrorCode(int status) {
+            if (translateStatus(status) != STATUS_FAILED) {
+                return 0; // arbitrary value when status is not an error
+            }
+            if ((400 <= status && status < 490) || (500 <= status && status < 600)) {
+                // HTTP status code
+                return status;
+            }
+
+            switch (status) {
+                case Downloads.STATUS_FILE_ERROR:
+                    return ERROR_FILE_ERROR;
+
+                case Downloads.STATUS_UNHANDLED_HTTP_CODE:
+                case Downloads.STATUS_UNHANDLED_REDIRECT:
+                    return ERROR_UNHANDLED_HTTP_CODE;
+
+                case Downloads.STATUS_HTTP_DATA_ERROR:
+                    return ERROR_HTTP_DATA_ERROR;
+
+                case Downloads.STATUS_TOO_MANY_REDIRECTS:
+                    return ERROR_TOO_MANY_REDIRECTS;
+
+                case Downloads.STATUS_INSUFFICIENT_SPACE_ERROR:
+                    return ERROR_INSUFFICIENT_SPACE;
+
+                case Downloads.STATUS_DEVICE_NOT_FOUND_ERROR:
+                    return ERROR_DEVICE_NOT_FOUND;
+
+                default:
+                    return ERROR_UNKNOWN;
+            }
+        }
+
+        private long getUnderlyingLong(String column) {
+            return super.getLong(super.getColumnIndex(column));
+        }
+
+        private String getUnderlyingString(String column) {
+            return super.getString(super.getColumnIndex(column));
+        }
+
+        private long translateStatus(int status) {
+            switch (status) {
+                case Downloads.STATUS_PENDING:
+                    return STATUS_PENDING;
+
+                case Downloads.STATUS_RUNNING:
+                    return STATUS_RUNNING;
+
+                case Downloads.STATUS_PENDING_PAUSED:
+                case Downloads.STATUS_RUNNING_PAUSED:
+                    return STATUS_PAUSED;
+
+                case Downloads.STATUS_SUCCESS:
+                    return STATUS_SUCCESSFUL;
+
+                default:
+                    assert Downloads.isStatusError(status);
+                    return STATUS_FAILED;
+            }
+        }
+    }
+}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 6f12f19..e26a090 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -336,7 +336,7 @@
                     ? (mWindowFlags&~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
                     : (mWindowFlags|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
             if (mCreated) {
-                updateSurface(false, false);
+                updateSurface(false, false, false);
             }
         }
         
@@ -421,6 +421,13 @@
         }
 
         /**
+         * Convenience for {@link SurfaceHolder.Callback2#surfaceRedrawNeeded
+         * SurfaceHolder.Callback.surfaceRedrawNeeded()}.
+         */
+        public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
+        }
+
+        /**
          * Convenience for {@link SurfaceHolder.Callback#surfaceCreated
          * SurfaceHolder.Callback.surfaceCreated()}.
          */
@@ -450,7 +457,7 @@
             }
         }
 
-        void updateSurface(boolean forceRelayout, boolean forceReport) {
+        void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {
             if (mDestroyed) {
                 Log.w(TAG, "Ignoring updateSurface: destroyed");
             }
@@ -467,7 +474,7 @@
             final boolean typeChanged = mType != mSurfaceHolder.getRequestedType();
             final boolean flagsChanged = mCurWindowFlags != mWindowFlags;
             if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged
-                    || typeChanged || flagsChanged) {
+                    || typeChanged || flagsChanged || redrawNeeded) {
 
                 if (DEBUG) Log.v(TAG, "Changes: creating=" + creating
                         + " format=" + formatChanged + " size=" + sizeChanged);
@@ -555,6 +562,10 @@
                                 }
                             }
                         }
+
+                        redrawNeeded |= creating
+                                || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0;
+
                         if (forceReport || creating || surfaceCreating
                                 || formatChanged || sizeChanged) {
                             if (DEBUG) {
@@ -578,10 +589,24 @@
                                 }
                             }
                         }
+
+                        if (redrawNeeded) {
+                            onSurfaceRedrawNeeded(mSurfaceHolder);
+                            SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                            if (callbacks != null) {
+                                for (SurfaceHolder.Callback c : callbacks) {
+                                    if (c instanceof SurfaceHolder.Callback2) {
+                                        ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+                                                mSurfaceHolder);
+                                    }
+                                }
+                            }
+                        }
+
                     } finally {
                         mIsCreating = false;
                         mSurfaceCreated = true;
-                        if (creating || (relayoutResult&WindowManagerImpl.RELAYOUT_FIRST_TIME) != 0) {
+                        if (redrawNeeded) {
                             mSession.finishDrawing(mWindow);
                         }
                     }
@@ -618,7 +643,7 @@
             onCreate(mSurfaceHolder);
             
             mInitializing = false;
-            updateSurface(false, false);
+            updateSurface(false, false, false);
         }
         
         void doDesiredSizeChanged(int desiredWidth, int desiredHeight) {
@@ -647,7 +672,7 @@
                         // If becoming visible, in preview mode the surface
                         // may have been destroyed so now we need to make
                         // sure it is re-created.
-                        updateSurface(false, false);
+                        updateSurface(false, false, false);
                     }
                     onVisibilityChanged(visible);
                 }
@@ -852,7 +877,7 @@
                     return;
                 }
                 case MSG_UPDATE_SURFACE:
-                    mEngine.updateSurface(true, false);
+                    mEngine.updateSurface(true, false, false);
                     break;
                 case MSG_VISIBILITY_CHANGED:
                     if (DEBUG) Log.v(TAG, "Visibility change in " + mEngine
@@ -868,14 +893,8 @@
                 } break;
                 case MSG_WINDOW_RESIZED: {
                     final boolean reportDraw = message.arg1 != 0;
-                    mEngine.updateSurface(true, false);
+                    mEngine.updateSurface(true, false, reportDraw);
                     mEngine.doOffsetsChanged();
-                    if (reportDraw) {
-                        try {
-                            mEngine.mSession.finishDrawing(mEngine.mWindow);
-                        } catch (RemoteException e) {
-                        }
-                    }
                 } break;
                 case MSG_TOUCH_EVENT: {
                     MotionEvent ev = (MotionEvent)message.obj;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 0bfb6d6..9c05008 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -124,11 +124,27 @@
     public static final int KEYCODE_PAGE_DOWN       = 93;
     public static final int KEYCODE_PICTSYMBOLS     = 94;   // switch symbol-sets (Emoji,Kao-moji)
     public static final int KEYCODE_SWITCH_CHARSET  = 95;   // switch char-sets (Kanji,Katakana)
+    public static final int KEYCODE_BUTTON_A        = 96;
+    public static final int KEYCODE_BUTTON_B        = 97;
+    public static final int KEYCODE_BUTTON_C        = 98;
+    public static final int KEYCODE_BUTTON_X        = 99;
+    public static final int KEYCODE_BUTTON_Y        = 100;
+    public static final int KEYCODE_BUTTON_Z        = 101;
+    public static final int KEYCODE_BUTTON_L1       = 102;
+    public static final int KEYCODE_BUTTON_R1       = 103;
+    public static final int KEYCODE_BUTTON_L2       = 104;
+    public static final int KEYCODE_BUTTON_R2       = 105;
+    public static final int KEYCODE_BUTTON_THUMBL   = 106;
+    public static final int KEYCODE_BUTTON_THUMBR   = 107;
+    public static final int KEYCODE_BUTTON_START    = 108;
+    public static final int KEYCODE_BUTTON_SELECT   = 109;
+    public static final int KEYCODE_BUTTON_MODE     = 110;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
     //  native/include/android/keycodes.h
     //  frameworks/base/include/ui/KeycodeLabels.h
+    //  external/webkit/WebKit/android/plugins/ANPKeyCodes.h
     //  tools/puppet_master/PuppetMaster/nav_keys.py
     //  frameworks/base/core/res/res/values/attrs.xml
     //  commands/monkey/Monkey.java
diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java
index 34e4638..0d38f7b 100644
--- a/core/java/android/view/SurfaceHolder.java
+++ b/core/java/android/view/SurfaceHolder.java
@@ -119,6 +119,23 @@
     }
 
     /**
+     * Additional callbacks that can be received for {@link Callback}.
+     */
+    public interface Callback2 extends Callback {
+        /**
+         * Called when the application needs to redraw the content of its
+         * surface, after it is resized or for some other reason.  By not
+         * returning here until the redraw is complete, you can ensure that
+         * the user will not see your surface in a bad state (at its new
+         * size before it has been correctly drawn that way).  This will
+         * typically be preceeded by a call to {@link #surfaceChanged}.
+         *
+         * @param holder The SurfaceHolder whose surface has changed.
+         */
+        public void surfaceRedrawNeeded(SurfaceHolder holder);
+    }
+
+    /**
      * Add a Callback interface for this holder.  There can several Callback
      * interfaces associated to a holder.
      * 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index e4d1ae1..c469bcc 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -123,7 +123,7 @@
                     handleGetNewSurface();
                 } break;
                 case UPDATE_WINDOW_MSG: {
-                    updateWindow(false);
+                    updateWindow(false, false);
                 } break;
             }
         }
@@ -132,7 +132,7 @@
     final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
             = new ViewTreeObserver.OnScrollChangedListener() {
                     public void onScrollChanged() {
-                        updateWindow(false);
+                        updateWindow(false, false);
                     }
             };
             
@@ -210,7 +210,7 @@
         super.onWindowVisibilityChanged(visibility);
         mWindowVisibility = visibility == VISIBLE;
         mRequestedVisible = mWindowVisibility && mViewVisibility;
-        updateWindow(false);
+        updateWindow(false, false);
     }
 
     @Override
@@ -218,7 +218,7 @@
         super.setVisibility(visibility);
         mViewVisibility = visibility == VISIBLE;
         mRequestedVisible = mWindowVisibility && mViewVisibility;
-        updateWindow(false);
+        updateWindow(false, false);
     }
 
     /**
@@ -232,7 +232,7 @@
      */
     protected void showSurface() {
         if (mSession != null) {
-            updateWindow(true);
+            updateWindow(true, false);
         }
     }
 
@@ -265,7 +265,7 @@
     protected void onDetachedFromWindow() {
         getViewTreeObserver().removeOnScrollChangedListener(mScrollChangedListener);
         mRequestedVisible = false;
-        updateWindow(false);
+        updateWindow(false, false);
         mHaveFrame = false;
         if (mWindow != null) {
             try {
@@ -290,7 +290,7 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        updateWindow(false);
+        updateWindow(false, false);
     }
 
     @Override
@@ -343,7 +343,7 @@
         }
         // reposition ourselves where the surface is 
         mHaveFrame = true;
-        updateWindow(false);
+        updateWindow(false, false);
         super.dispatchDraw(canvas);
     }
 
@@ -397,7 +397,7 @@
         mWindowType = type;
     }
 
-    private void updateWindow(boolean force) {
+    private void updateWindow(boolean force, boolean redrawNeeded) {
         if (!mHaveFrame) {
             return;
         }
@@ -425,7 +425,7 @@
         final boolean typeChanged = mType != mRequestedType;
         if (force || creating || formatChanged || sizeChanged || visibleChanged
             || typeChanged || mLeft != mLocation[0] || mTop != mLocation[1]
-            || mUpdateWindowNeeded || mReportDrawNeeded) {
+            || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
 
             if (localLOGV) Log.i(TAG, "Changes: creating=" + creating
                     + " format=" + formatChanged + " size=" + sizeChanged
@@ -524,6 +524,8 @@
                 }
 
                 try {
+                    redrawNeeded |= creating | reportDrawNeeded;
+
                     if (visible) {
                         mDestroyReportNeeded = true;
 
@@ -541,8 +543,13 @@
                         }
                         if (creating || formatChanged || sizeChanged
                                 || visibleChanged || realSizeChanged) {
+                        }
+                        if (redrawNeeded) {
                             for (SurfaceHolder.Callback c : callbacks) {
-                                c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
+                                if (c instanceof SurfaceHolder.Callback2) {
+                                    ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+                                            mSurfaceHolder);
+                                }
                             }
                         }
                     } else {
@@ -550,7 +557,7 @@
                     }
                 } finally {
                     mIsCreating = false;
-                    if (creating || reportDrawNeeded) {
+                    if (redrawNeeded) {
                         mSession.finishDrawing(mWindow);
                     }
                 }
@@ -580,7 +587,7 @@
 
     void handleGetNewSurface() {
         mNewSurfaceNeeded = true;
-        updateWindow(false);
+        updateWindow(false, false);
     }
 
     /**
@@ -696,7 +703,7 @@
 
             mRequestedFormat = format;
             if (mWindow != null) {
-                updateWindow(false);
+                updateWindow(false, false);
             }
         }
 
@@ -713,7 +720,7 @@
             case SURFACE_TYPE_PUSH_BUFFERS:
                 mRequestedType = type;
                 if (mWindow != null) {
-                    updateWindow(false);
+                    updateWindow(false, false);
                 }
                 break;
             }
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index fb45971..260bf7bc 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -137,7 +137,7 @@
     int mViewVisibility;
     boolean mAppVisible = true;
 
-    SurfaceHolder.Callback mSurfaceHolderCallback;
+    SurfaceHolder.Callback2 mSurfaceHolderCallback;
     BaseSurfaceHolder mSurfaceHolder;
     boolean mIsCreating;
     boolean mDrawingAllowed;
@@ -1263,6 +1263,18 @@
                     Log.v("ViewRoot", "FINISHED DRAWING: " + mWindowAttributes.getTitle());
                 }
                 mReportNextDraw = false;
+                if (mSurfaceHolder != null && mSurface.isValid()) {
+                    mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
+                    SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
+                    if (callbacks != null) {
+                        for (SurfaceHolder.Callback c : callbacks) {
+                            if (c instanceof SurfaceHolder.Callback2) {
+                                ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
+                                        mSurfaceHolder);
+                            }
+                        }
+                    }
+                }
                 try {
                     sWindowSession.finishDrawing(mWindow);
                 } catch (RemoteException e) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f40734b..11c09c1 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -478,7 +478,7 @@
      * to operate (such as for receiving input events).  The given SurfaceHolder
      * callback will be used to tell you about state changes to the surface.
      */
-    public abstract void takeSurface(SurfaceHolder.Callback callback);
+    public abstract void takeSurface(SurfaceHolder.Callback2 callback);
     
     /**
      * Take ownership of this window's InputQueue.  The window will no
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
index 7ff8d4c..9c1b558 100644
--- a/core/java/com/android/internal/view/RootViewSurfaceTaker.java
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -5,7 +5,7 @@
 
 /** hahahah */
 public interface RootViewSurfaceTaker {
-    SurfaceHolder.Callback willYouTakeTheSurface();
+    SurfaceHolder.Callback2 willYouTakeTheSurface();
     void setSurfaceType(int type);
     void setSurfaceFormat(int format);
     void setSurfaceKeepScreenOn(boolean keepOn);
diff --git a/core/jni/ActivityManager.cpp b/core/jni/ActivityManager.cpp
index 8950dfb..0bd14fa 100644
--- a/core/jni/ActivityManager.cpp
+++ b/core/jni/ActivityManager.cpp
@@ -39,7 +39,7 @@
         data.writeString16(uri);
         status_t ret = am->transact(OPEN_CONTENT_URI_TRANSACTION, data, &reply);
         if (ret == NO_ERROR) {
-            int32_t exceptionCode = reply.readInt32();
+            int32_t exceptionCode = reply.readExceptionCode();
             if (!exceptionCode) {
                 // Success is indicated here by a nonzero int followed by the fd;
                 // failure by a zero int with no data following.
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 54a9c2a..acbf854 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -19,6 +19,7 @@
 
 #include <poll.h>
 #include <dlfcn.h>
+#include <fcntl.h>
 
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
@@ -33,6 +34,9 @@
 #include "android_view_InputChannel.h"
 #include "android_view_KeyEvent.h"
 
+//#define LOG_TRACE(...)
+#define LOG_TRACE(...) LOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+
 namespace android
 {
 
@@ -42,6 +46,8 @@
     jmethodID dispatchUnhandledKeyEvent;
     jmethodID setWindowFlags;
     jmethodID setWindowFormat;
+    jmethodID showIme;
+    jmethodID hideIme;
 } gNativeActivityClassInfo;
 
 // ------------------------------------------------------------------------
@@ -56,6 +62,8 @@
     CMD_DEF_KEY = 1,
     CMD_SET_WINDOW_FORMAT,
     CMD_SET_WINDOW_FLAGS,
+    CMD_SHOW_SOFT_INPUT,
+    CMD_HIDE_SOFT_INPUT,
 };
 
 static void write_work(int fd, int32_t cmd, int32_t arg1=0, int32_t arg2=0) {
@@ -64,6 +72,8 @@
     work.arg1 = arg1;
     work.arg2 = arg2;
     
+    LOG_TRACE("write_work: cmd=%d", cmd);
+
 restart:
     int res = write(fd, &work, sizeof(work));
     if (res < 0 && errno == EINTR) {
@@ -88,43 +98,177 @@
 
 // ------------------------------------------------------------------------
 
-/*
- * Specialized input queue that allows unhandled key events to be dispatched
- * back to the native activity's Java framework code.
- */
-struct MyInputQueue : AInputQueue {
-    explicit MyInputQueue(const android::sp<android::InputChannel>& channel, int workWrite)
-        : AInputQueue(channel), mWorkWrite(workWrite) {
+} // namespace android
+
+using namespace android;
+
+AInputQueue::AInputQueue(const sp<InputChannel>& channel, int workWrite) :
+        mWorkWrite(workWrite), mConsumer(channel) {
+    int msgpipe[2];
+    if (pipe(msgpipe)) {
+        LOGW("could not create pipe: %s", strerror(errno));
+        mDispatchKeyRead = mDispatchKeyWrite = -1;
+    } else {
+        mDispatchKeyRead = msgpipe[0];
+        mDispatchKeyWrite = msgpipe[1];
+        int result = fcntl(mDispatchKeyRead, F_SETFL, O_NONBLOCK);
+        SLOGW_IF(result != 0, "Could not make AInputQueue read pipe "
+                "non-blocking: %s", strerror(errno));
+        result = fcntl(mDispatchKeyWrite, F_SETFL, O_NONBLOCK);
+        SLOGW_IF(result != 0, "Could not make AInputQueue write pipe "
+                "non-blocking: %s", strerror(errno));
     }
+}
+
+AInputQueue::~AInputQueue() {
+    close(mDispatchKeyRead);
+    close(mDispatchKeyWrite);
+}
+
+void AInputQueue::attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data) {
+    mPollLoop = static_cast<android::PollLoop*>(looper);
+    mPollLoop->setLooperCallback(mConsumer.getChannel()->getReceivePipeFd(),
+            POLLIN, callback, data);
+    mPollLoop->setLooperCallback(mDispatchKeyRead,
+            POLLIN, callback, data);
+}
+
+void AInputQueue::detachLooper() {
+    mPollLoop->removeCallback(mConsumer.getChannel()->getReceivePipeFd());
+    mPollLoop->removeCallback(mDispatchKeyRead);
+}
+
+int32_t AInputQueue::hasEvents() {
+    struct pollfd pfd[2];
+
+    pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd();
+    pfd[0].events = POLLIN;
+    pfd[0].revents = 0;
+    pfd[1].fd = mDispatchKeyRead;
+    pfd[0].events = POLLIN;
+    pfd[0].revents = 0;
     
-    virtual void doDefaultKey(android::KeyEvent* keyEvent) {
+    int nfd = poll(pfd, 2, 0);
+    if (nfd <= 0) return 0;
+    return (pfd[0].revents == POLLIN || pfd[1].revents == POLLIN) ? 1 : -1;
+}
+
+int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
+    *outEvent = NULL;
+
+    char byteread;
+    ssize_t nRead = read(mDispatchKeyRead, &byteread, 1);
+    if (nRead == 1) {
         mLock.lock();
-        LOGI("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
-        if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
-            write_work(mWorkWrite, CMD_DEF_KEY);
-        }
-        mPendingKeys.add(keyEvent);
-        mLock.unlock();
-    }
-    
-    KeyEvent* getNextEvent() {
-        KeyEvent* event = NULL;
-        
-        mLock.lock();
-        if (mPendingKeys.size() > 0) {
-            event = mPendingKeys[0];
-            mPendingKeys.removeAt(0);
+        if (mDispatchingKeys.size() > 0) {
+            KeyEvent* kevent = mDispatchingKeys[0];
+            *outEvent = kevent;
+            mDispatchingKeys.removeAt(0);
+            mDeliveringKeys.add(kevent);
         }
         mLock.unlock();
-        
-        return event;
+        if (*outEvent != NULL) {
+            return 0;
+        }
     }
     
-    int mWorkWrite;
+    int32_t res = mConsumer.receiveDispatchSignal();
+    if (res != android::OK) {
+        LOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
+                mConsumer.getChannel()->getName().string(), res);
+        return -1;
+    }
+
+    InputEvent* myEvent = NULL;
+    res = mConsumer.consume(&mInputEventFactory, &myEvent);
+    if (res != android::OK) {
+        LOGW("channel '%s' ~ Failed to consume input event.  status=%d",
+                mConsumer.getChannel()->getName().string(), res);
+        mConsumer.sendFinishedSignal();
+        return -1;
+    }
+
+    *outEvent = myEvent;
+    return 0;
+}
+
+void AInputQueue::finishEvent(AInputEvent* event, bool handled) {
+    bool needFinished = true;
+
+    if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
+            && ((KeyEvent*)event)->hasDefaultAction()) {
+        // The app didn't handle this, but it may have a default action
+        // associated with it.  We need to hand this back to Java to be
+        // executed.
+        doDefaultKey((KeyEvent*)event);
+        needFinished = false;
+    }
+
+    const size_t N = mDeliveringKeys.size();
+    for (size_t i=0; i<N; i++) {
+        if (mDeliveringKeys[i] == event) {
+            delete event;
+            mDeliveringKeys.removeAt(i);
+            needFinished = false;
+            break;
+        }
+    }
     
-    Mutex mLock;
-    Vector<KeyEvent*> mPendingKeys;
-};
+    if (needFinished) {
+        int32_t res = mConsumer.sendFinishedSignal();
+        if (res != android::OK) {
+            LOGW("Failed to send finished signal on channel '%s'.  status=%d",
+                    mConsumer.getChannel()->getName().string(), res);
+        }
+    }
+}
+
+void AInputQueue::dispatchEvent(android::KeyEvent* event) {
+    mLock.lock();
+    LOG_TRACE("dispatchEvent: dispatching=%d write=%d\n", mDispatchingKeys.size(),
+            mDispatchKeyWrite);
+    mDispatchingKeys.add(event);
+    mLock.unlock();
+    
+restart:
+    char dummy = 0;
+    int res = write(mDispatchKeyWrite, &dummy, sizeof(dummy));
+    if (res < 0 && errno == EINTR) {
+        goto restart;
+    }
+
+    if (res == sizeof(dummy)) return;
+
+    if (res < 0) LOGW("Failed writing to dispatch fd: %s", strerror(errno));
+    else LOGW("Truncated writing to dispatch fd: %d", res);
+}
+
+KeyEvent* AInputQueue::consumeUnhandledEvent() {
+    KeyEvent* event = NULL;
+
+    mLock.lock();
+    if (mPendingKeys.size() > 0) {
+        event = mPendingKeys[0];
+        mPendingKeys.removeAt(0);
+    }
+    mLock.unlock();
+
+    LOG_TRACE("consumeUnhandledEvent: KeyEvent=%p", event);
+
+    return event;
+}
+
+void AInputQueue::doDefaultKey(KeyEvent* keyEvent) {
+    mLock.lock();
+    LOG_TRACE("Default key: pending=%d write=%d\n", mPendingKeys.size(), mWorkWrite);
+    if (mPendingKeys.size() <= 0 && mWorkWrite >= 0) {
+        write_work(mWorkWrite, CMD_DEF_KEY);
+    }
+    mPendingKeys.add(keyEvent);
+    mLock.unlock();
+}
+
+namespace android {
 
 // ------------------------------------------------------------------------
 
@@ -133,8 +277,8 @@
  */
 struct NativeCode : public ANativeActivity {
     NativeCode(void* _dlhandle, ANativeActivity_createFunc* _createFunc) {
-        memset((ANativeActivity*)this, sizeof(ANativeActivity), 0);
-        memset(&callbacks, sizeof(callbacks), 0);
+        memset((ANativeActivity*)this, 0, sizeof(ANativeActivity));
+        memset(&callbacks, 0, sizeof(callbacks));
         dlhandle = _dlhandle;
         createActivityFunc = _createFunc;
         nativeWindow = NULL;
@@ -188,7 +332,7 @@
             sp<InputChannel> ic =
                     android_view_InputChannel_getInputChannel(env, _channel);
             if (ic != NULL) {
-                nativeInputQueue = new MyInputQueue(ic, mainWorkWrite);
+                nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
                 if (nativeInputQueue->getConsumer().initialize() != android::OK) {
                     delete nativeInputQueue;
                     nativeInputQueue = NULL;
@@ -210,8 +354,11 @@
     String8 externalDataPath;
     
     sp<ANativeWindow> nativeWindow;
+    int32_t lastWindowWidth;
+    int32_t lastWindowHeight;
+
     jobject inputChannel;
-    struct MyInputQueue* nativeInputQueue;
+    struct AInputQueue* nativeInputQueue;
     
     // These are used to wake up the main thread to process work.
     int mainWorkRead;
@@ -231,6 +378,18 @@
     write_work(code->mainWorkWrite, CMD_SET_WINDOW_FLAGS, values, mask);
 }
 
+void android_NativeActivity_showSoftInput(
+        ANativeActivity* activity, int32_t flags) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_SHOW_SOFT_INPUT, flags);
+}
+
+void android_NativeActivity_hideSoftInput(
+        ANativeActivity* activity, int32_t flags) {
+    NativeCode* code = static_cast<NativeCode*>(activity);
+    write_work(code->mainWorkWrite, CMD_HIDE_SOFT_INPUT, flags);
+}
+
 // ------------------------------------------------------------------------
 
 /*
@@ -246,10 +405,13 @@
     if (!read_work(code->mainWorkRead, &work)) {
         return true;
     }
+
+    LOG_TRACE("mainWorkCallback: cmd=%d", work.cmd);
+
     switch (work.cmd) {
         case CMD_DEF_KEY: {
             KeyEvent* keyEvent;
-            while ((keyEvent=code->nativeInputQueue->getNextEvent()) != NULL) {
+            while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) {
                 jobject inputEventObj = android_view_KeyEvent_fromNative(
                         code->env, keyEvent);
                 code->env->CallVoidMethod(code->clazz,
@@ -269,6 +431,14 @@
             code->env->CallVoidMethod(code->clazz,
                     gNativeActivityClassInfo.setWindowFlags, work.arg1, work.arg2);
         } break;
+        case CMD_SHOW_SOFT_INPUT: {
+            code->env->CallVoidMethod(code->clazz,
+                    gNativeActivityClassInfo.showIme, work.arg1);
+        } break;
+        case CMD_HIDE_SOFT_INPUT: {
+            code->env->CallVoidMethod(code->clazz,
+                    gNativeActivityClassInfo.hideIme, work.arg1);
+        } break;
         default:
             LOGW("Unknown work command: %d", work.cmd);
             break;
@@ -283,6 +453,8 @@
 loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path, jobject messageQueue,
         jstring internalDataDir, jstring externalDataDir, int sdkVersion)
 {
+    LOG_TRACE("loadNativeCode_native");
+
     const char* pathStr = env->GetStringUTFChars(path, NULL);
     NativeCode* code = NULL;
     
@@ -314,6 +486,12 @@
         }
         code->mainWorkRead = msgpipe[0];
         code->mainWorkWrite = msgpipe[1];
+        int result = fcntl(code->mainWorkRead, F_SETFL, O_NONBLOCK);
+        SLOGW_IF(result != 0, "Could not make main work read pipe "
+                "non-blocking: %s", strerror(errno));
+        result = fcntl(code->mainWorkWrite, F_SETFL, O_NONBLOCK);
+        SLOGW_IF(result != 0, "Could not make main work write pipe "
+                "non-blocking: %s", strerror(errno));
         code->pollLoop->setCallback(code->mainWorkRead, POLLIN, mainWorkCallback, code);
         
         code->ANativeActivity::callbacks = &code->callbacks;
@@ -346,6 +524,7 @@
 static void
 unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("unloadNativeCode_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         delete code;
@@ -355,6 +534,7 @@
 static void
 onStart_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onStart_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onStart != NULL) {
@@ -366,6 +546,7 @@
 static void
 onResume_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onResume_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onResume != NULL) {
@@ -377,6 +558,7 @@
 static void
 onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onSaveInstanceState_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onSaveInstanceState != NULL) {
@@ -389,6 +571,7 @@
 static void
 onPause_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onPause_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onPause != NULL) {
@@ -400,6 +583,7 @@
 static void
 onStop_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onStop_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onStop != NULL) {
@@ -411,6 +595,7 @@
 static void
 onLowMemory_native(JNIEnv* env, jobject clazz, jint handle)
 {
+    LOG_TRACE("onLowMemory_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onLowMemory != NULL) {
@@ -422,6 +607,7 @@
 static void
 onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused)
 {
+    LOG_TRACE("onWindowFocusChanged_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->callbacks.onWindowFocusChanged != NULL) {
@@ -433,6 +619,7 @@
 static void
 onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
 {
+    LOG_TRACE("onSurfaceCreated_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         code->setSurface(surface);
@@ -443,10 +630,17 @@
     }
 }
 
+static int32_t getWindowProp(ANativeWindow* window, int what) {
+    int value;
+    int res = window->query(window, what, &value);
+    return res < 0 ? res : value;
+}
+
 static void
 onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface,
         jint format, jint width, jint height)
 {
+    LOG_TRACE("onSurfaceChanged_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         sp<ANativeWindow> oldNativeWindow = code->nativeWindow;
@@ -456,10 +650,41 @@
                 code->callbacks.onNativeWindowDestroyed(code,
                         oldNativeWindow.get());
             }
-            if (code->nativeWindow != NULL && code->callbacks.onNativeWindowCreated != NULL) {
-                code->callbacks.onNativeWindowCreated(code,
-                        code->nativeWindow.get());
+            if (code->nativeWindow != NULL) {
+                if (code->callbacks.onNativeWindowCreated != NULL) {
+                    code->callbacks.onNativeWindowCreated(code,
+                            code->nativeWindow.get());
+                }
+                code->lastWindowWidth = getWindowProp(code->nativeWindow.get(),
+                        NATIVE_WINDOW_WIDTH);
+                code->lastWindowHeight = getWindowProp(code->nativeWindow.get(),
+                        NATIVE_WINDOW_HEIGHT);
             }
+        } else {
+            // Maybe it resized?
+            int32_t newWidth = getWindowProp(code->nativeWindow.get(),
+                    NATIVE_WINDOW_WIDTH);
+            int32_t newHeight = getWindowProp(code->nativeWindow.get(),
+                    NATIVE_WINDOW_HEIGHT);
+            if (newWidth != code->lastWindowWidth
+                    || newHeight != code->lastWindowHeight) {
+                if (code->callbacks.onNativeWindowResized != NULL) {
+                    code->callbacks.onNativeWindowResized(code,
+                            code->nativeWindow.get());
+                }
+            }
+        }
+    }
+}
+
+static void
+onSurfaceRedrawNeeded_native(JNIEnv* env, jobject clazz, jint handle)
+{
+    LOG_TRACE("onSurfaceRedrawNeeded_native");
+    if (handle != 0) {
+        NativeCode* code = (NativeCode*)handle;
+        if (code->nativeWindow != NULL && code->callbacks.onNativeWindowRedrawNeeded != NULL) {
+            code->callbacks.onNativeWindowRedrawNeeded(code, code->nativeWindow.get());
         }
     }
 }
@@ -467,6 +692,7 @@
 static void
 onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface)
 {
+    LOG_TRACE("onSurfaceDestroyed_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeWindow != NULL && code->callbacks.onNativeWindowDestroyed != NULL) {
@@ -480,6 +706,7 @@
 static void
 onInputChannelCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
 {
+    LOG_TRACE("onInputChannelCreated_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         status_t err = code->setInputChannel(channel);
@@ -498,6 +725,7 @@
 static void
 onInputChannelDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject channel)
 {
+    LOG_TRACE("onInputChannelDestroyed_native");
     if (handle != 0) {
         NativeCode* code = (NativeCode*)handle;
         if (code->nativeInputQueue != NULL
@@ -509,6 +737,38 @@
     }
 }
 
+static void
+onContentRectChanged_native(JNIEnv* env, jobject clazz, jint handle,
+        jint x, jint y, jint w, jint h)
+{
+    LOG_TRACE("onContentRectChanged_native");
+    if (handle != 0) {
+        NativeCode* code = (NativeCode*)handle;
+        if (code->callbacks.onContentRectChanged != NULL) {
+            ARect rect;
+            rect.left = x;
+            rect.top = y;
+            rect.right = x+w;
+            rect.bottom = y+h;
+            code->callbacks.onContentRectChanged(code, &rect);
+        }
+    }
+}
+
+static void
+dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventObj)
+{
+    LOG_TRACE("dispatchKeyEvent_native");
+    if (handle != 0) {
+        NativeCode* code = (NativeCode*)handle;
+        if (code->nativeInputQueue != NULL) {
+            KeyEvent* event = new KeyEvent();
+            android_view_KeyEvent_toNative(env, eventObj, INPUT_EVENT_NATURE_KEY, event);
+            code->nativeInputQueue->dispatchEvent(event);
+        }
+    }
+}
+
 static const JNINativeMethod g_methods[] = {
     { "loadNativeCode", "(Ljava/lang/String;Landroid/os/MessageQueue;Ljava/lang/String;Ljava/lang/String;I)I",
             (void*)loadNativeCode_native },
@@ -522,9 +782,12 @@
     { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native },
     { "onSurfaceCreatedNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceCreated_native },
     { "onSurfaceChangedNative", "(ILandroid/view/Surface;III)V", (void*)onSurfaceChanged_native },
+    { "onSurfaceRedrawNeededNative", "(ILandroid/view/Surface;)V", (void*)onSurfaceRedrawNeeded_native },
     { "onSurfaceDestroyedNative", "(I)V", (void*)onSurfaceDestroyed_native },
     { "onInputChannelCreatedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelCreated_native },
     { "onInputChannelDestroyedNative", "(ILandroid/view/InputChannel;)V", (void*)onInputChannelDestroyed_native },
+    { "onContentRectChangedNative", "(IIIII)V", (void*)onContentRectChanged_native },
+    { "dispatchKeyEventNative", "(ILandroid/view/KeyEvent;)V", (void*)dispatchKeyEvent_native },
 };
 
 static const char* const kNativeActivityPathName = "android/app/NativeActivity";
@@ -554,6 +817,12 @@
     GET_METHOD_ID(gNativeActivityClassInfo.setWindowFormat,
             gNativeActivityClassInfo.clazz,
             "setWindowFormat", "(I)V");
+    GET_METHOD_ID(gNativeActivityClassInfo.showIme,
+            gNativeActivityClassInfo.clazz,
+            "showIme", "(I)V");
+    GET_METHOD_ID(gNativeActivityClassInfo.hideIme,
+            gNativeActivityClassInfo.clazz,
+            "hideIme", "(I)V");
 
     return AndroidRuntime::registerNativeMethods(
         env, kNativeActivityPathName,
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8d4fa4e..d16b91c 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -920,6 +920,21 @@
         <enum name="KEYCODE_PAGE_DOWN" value="93" />
         <enum name="KEYCODE_PICTSYMBOLS" value="94" />
         <enum name="KEYCODE_SWITCH_CHARSET" value="95" />
+        <enum name="KEYCODE_BUTTON_A" value="96" />
+        <enum name="KEYCODE_BUTTON_B" value="97" />
+        <enum name="KEYCODE_BUTTON_C" value="98" />
+        <enum name="KEYCODE_BUTTON_X" value="99" />
+        <enum name="KEYCODE_BUTTON_Y" value="100" />
+        <enum name="KEYCODE_BUTTON_Z" value="101" />
+        <enum name="KEYCODE_BUTTON_L1" value="102" />
+        <enum name="KEYCODE_BUTTON_R1" value="103" />
+        <enum name="KEYCODE_BUTTON_L2" value="104" />
+        <enum name="KEYCODE_BUTTON_R2" value="105" />
+        <enum name="KEYCODE_BUTTON_THUMBL" value="106" />
+        <enum name="KEYCODE_BUTTON_THUMBR" value="107" />
+        <enum name="KEYCODE_BUTTON_START" value="108" />
+        <enum name="KEYCODE_BUTTON_SELECT" value="109" />
+        <enum name="KEYCODE_BUTTON_MODE" value="110" />
     </attr>
 
     <!-- ***************************************************************** -->
diff --git a/docs/html/sdk/android-1.5.jd b/docs/html/sdk/android-1.5.jd
index 1d6e0ad..0c16b60 100644
--- a/docs/html/sdk/android-1.5.jd
+++ b/docs/html/sdk/android-1.5.jd
@@ -139,7 +139,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 1.5, Revision 3</a> <em>(July 2009)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-1.6.jd b/docs/html/sdk/android-1.6.jd
index c2651b6..c4e08ff 100644
--- a/docs/html/sdk/android-1.6.jd
+++ b/docs/html/sdk/android-1.6.jd
@@ -138,7 +138,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 1.6, Revision 2</a> <em>(December 2009)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-2.1.jd b/docs/html/sdk/android-2.1.jd
index 7490bae..cd48a72 100644
--- a/docs/html/sdk/android-2.1.jd
+++ b/docs/html/sdk/android-2.1.jd
@@ -139,7 +139,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android 2.1, Revision 1</a> <em>(January 2010)</em></a>
   <div class="toggleme">
 <dl>
diff --git a/docs/html/sdk/android-2.2.jd b/docs/html/sdk/android-2.2.jd
index f82edf9..495fd80 100644
--- a/docs/html/sdk/android-2.2.jd
+++ b/docs/html/sdk/android-2.2.jd
@@ -2,7 +2,6 @@
 sdk.platform.version=2.2
 sdk.platform.apiLevel=8
 sdk.platform.majorMinor=minor
-sdk.platform.deployableDate=May 2010
 
 @jd:body
 
@@ -118,6 +117,30 @@
 <div class="toggleable opened">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        Android {@sdkPlatformVersion}, Revision 2</a> <em>(July 2010)</em></a>
+  <div class="toggleme">
+<dl>
+<dt>Dependencies:</dt>
+<dd>
+<p>Requires SDK Tools r6 or higher.</p>
+</dd>
+
+<dt>System Image:</dt>
+<dd>
+<ul>
+<li>Adds default Search Widget.</li>
+<li>Includes proper provisioning for the platform's Backup Manager. For more information about how to use the Backup Manager, see <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a>.</li>
+<li>Updates the Android 2.2 system image to FRF91.</li>
+</ul>
+</dd>
+
+</dl>
+ </div>
+</div>
+
+<div class="toggleable closed">
+  <a href="#" onclick="return toggleDiv(this)">
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
         Android {@sdkPlatformVersion}, Revision 1</a> <em>(May 2010)</em></a>
   <div class="toggleme">
 <dl>
@@ -135,7 +158,6 @@
  </div>
 </div>
 
-
 <h2 id="api-level">API Level</h2>
 
 <p>The Android {@sdkPlatformVersion} platform delivers an updated version of
@@ -444,4 +466,4 @@
 <p>For more information about how to develop an application that displays
 and functions properly on all Android-powered devices, see <a
 href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-Screens</a>.</p>
\ No newline at end of file
+Screens</a>.</p>
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 69cc73d..9e88d94 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,16 +1,16 @@
 ndk=true
 
-ndk.win_download=android-ndk-r4-windows.zip
-ndk.win_bytes=45778965
-ndk.win_checksum=1eded98a7f5cd5e71f8ac74565f73f11
+ndk.win_download=android-ndk-r4b-windows.zip
+ndk.win_bytes=45792835
+ndk.win_checksum=e397145e155a639be53ee4b6db8ad511
 
-ndk.mac_download=android-ndk-r4-darwin-x86.zip
-ndk.mac_bytes=50572163
-ndk.mac_checksum=b7d5f149fecf951c05a79b045f00419f
+ndk.mac_download=android-ndk-r4b-darwin-x86.zip
+ndk.mac_bytes=50586041
+ndk.mac_checksum=41dbd54335fb828ee408eab17103a1b0
 
-ndk.linux_download=android-ndk-r4-linux-x86.zip
-ndk.linux_bytes=49450682
-ndk.linux_checksum=0892b0637d45d145e045cc68e163dee3
+ndk.linux_download=android-ndk-r4b-linux-x86.zip
+ndk.linux_bytes=49464776
+ndk.linux_checksum=2deabcb125c219b34140975b710f00ec
 
 page.title=Android NDK
 @jd:body
@@ -62,8 +62,15 @@
 <div class="toggleable open">
   <a href="#" onclick="return toggleDiv(this)">
         <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
-Android NDK, Revision 4</a> <em>(May 2010)</em>
+Android NDK, Revision 4b</a> <em>(June 2010)</em>
   <div class="toggleme">
+<dl>
+<dt>NDK r4b notes:</dt>
+<dd><p>Includes fixes for several issues in the NDK build and debugging scripts
+&mdash; if you are using NDK r4, we recommend downloading the NDK r4b build. For
+detailed information the changes in this release, read the CHANGES.TXT document
+included in the downloaded NDK package.</p></dd>
+</dl>
 
 <dl>
 <dt>General notes:</dt>
@@ -114,7 +121,7 @@
 
 <div class="toggleable closed">
   <a href="#" onclick="return toggleDiv(this)">
-        <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px" />
+        <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px" />
 Android NDK, Revision 3</a> <em>(March 2010)</em>
   <div class="toggleme">
 
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index a80981c..404e938 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -75,7 +75,8 @@
       </li>
     </ul>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r6</a> <span class="new">new!</span></li>
+      <li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r6</a>
+      </li>
       <li><a href="<?cs var:toroot ?>sdk/win-usb.html">USB Driver for
       Windows, r3</a>
       </li>
@@ -101,7 +102,6 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span></a>
-        <span class="new">new!</span>
       </li>
     </ul>
   </li>
@@ -116,7 +116,7 @@
       <span style="display:none" class="zh-TW"></span>
     </h2>
     <ul>
-      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r4</a>
+      <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r4b</a>
       <span class="new">new!</span></li>
     </ul>
   </li>
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index f808328..d7a9a2c 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -17,6 +17,8 @@
 #ifndef _ANDROID_APP_NATIVEACTIVITY_H
 #define _ANDROID_APP_NATIVEACTIVITY_H
 
+#include <ui/InputTransport.h>
+
 #include <android/native_activity.h>
 
 #include "jni.h"
@@ -29,7 +31,65 @@
 extern void android_NativeActivity_setWindowFlags(
         ANativeActivity* activity, int32_t values, int32_t mask);
 
+extern void android_NativeActivity_showSoftInput(
+        ANativeActivity* activity, int32_t flags);
+
+extern void android_NativeActivity_hideSoftInput(
+        ANativeActivity* activity, int32_t flags);
 
 } // namespace android
 
+
+/*
+ * NDK input queue API.
+ */
+struct AInputQueue {
+public:
+    /* Creates a consumer associated with an input channel. */
+    explicit AInputQueue(const android::sp<android::InputChannel>& channel, int workWrite);
+
+    /* Destroys the consumer and releases its input channel. */
+    ~AInputQueue();
+
+    void attachLooper(ALooper* looper, ALooper_callbackFunc* callback, void* data);
+
+    void detachLooper();
+
+    int32_t hasEvents();
+
+    int32_t getEvent(AInputEvent** outEvent);
+
+    void finishEvent(AInputEvent* event, bool handled);
+
+
+    // ----------------------------------------------------------
+
+    inline android::InputConsumer& getConsumer() { return mConsumer; }
+
+    void dispatchEvent(android::KeyEvent* event);
+
+    android::KeyEvent* consumeUnhandledEvent();
+
+    int mWorkWrite;
+
+private:
+    void doDefaultKey(android::KeyEvent* keyEvent);
+
+    android::InputConsumer mConsumer;
+    android::PreallocatedInputEventFactory mInputEventFactory;
+    android::sp<android::PollLoop> mPollLoop;
+
+    int mDispatchKeyRead;
+    int mDispatchKeyWrite;
+
+    // This is only touched by the event reader thread.  It is the current
+    // key events that came out of the mDispatchingKeys list and are now
+    //Êdelivered to the app.
+    android::Vector<android::KeyEvent*> mDeliveringKeys;
+
+    android::Mutex mLock;
+    android::Vector<android::KeyEvent*> mPendingKeys;
+    android::Vector<android::KeyEvent*> mDispatchingKeys;
+};
+
 #endif // _ANDROID_APP_NATIVEACTIVITY_H
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 2cc4db9..3aba5f6 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -103,6 +103,11 @@
     
     status_t            writeObject(const flat_binder_object& val, bool nullMetaData);
 
+    // Like Parcel.java's writeNoException().  Just writes a zero int32.
+    // Currently the native implementation doesn't do any of the StrictMode
+    // stack gathering and serialization that the Java implementation does.
+    status_t            writeNoException();
+
     void                remove(size_t start, size_t amt);
     
     status_t            read(void* outData, size_t len) const;
@@ -125,7 +130,14 @@
     sp<IBinder>         readStrongBinder() const;
     wp<IBinder>         readWeakBinder() const;
     status_t            read(Flattenable& val) const;
-    
+
+    // Like Parcel.java's readExceptionCode().  Reads the first int32
+    // off of a Parcel's header, returning 0 or the negative error
+    // code on exceptions, but also deals with skipping over rich
+    // response headers.  Callers should use this to read & parse the
+    // response headers rather than doing it by hand.
+    int32_t             readExceptionCode() const;
+
     // Retrieve native_handle from the parcel. This returns a copy of the
     // parcel's native_handle (the caller takes ownership). The caller
     // must free the native_handle with native_handle_close() and 
diff --git a/include/media/EffectApi.h b/include/media/EffectApi.h
index b4d738c..9f3d0b6 100644
--- a/include/media/EffectApi.h
+++ b/include/media/EffectApi.h
@@ -223,6 +223,11 @@
 //          samples as specified in output buffer descriptor. If the buffer descriptor
 //          is not specified the function must use either the buffer or the
 //          buffer provider function installed by the EFFECT_CMD_CONFIGURE command.
+//          The effect framework will call the process() function after the EFFECT_CMD_ENABLE
+//          command is received and until the EFFECT_CMD_DISABLE is received. When the engine
+//          receives the EFFECT_CMD_DISABLE command it should turn off the effect gracefully
+//          and when done indicate that it is OK to stop calling the process() function by
+//          returning the -ENODATA status.
 //
 //    NOTE: the process() function implementation should be "real-time safe" that is
 //      it should not perform blocking calls: malloc/free, sleep, read/write/open/close,
@@ -239,6 +244,8 @@
 //
 //    Output:
 //        returned value:    0 successful operation
+//                          -ENODATA the engine has finished the disable phase and the framework
+//                                  can stop calling process()
 //                          -EINVAL invalid interface handle or
 //                                  invalid input/output buffer description
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/include/ui/Input.h b/include/ui/Input.h
index a2e0ba06..a7d23d4 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -43,7 +43,9 @@
 /*
  * Declare a concrete type for the NDK's input event forward declaration.
  */
-struct AInputEvent { };
+struct AInputEvent {
+    virtual ~AInputEvent() { }
+};
 
 namespace android {
 
diff --git a/include/ui/InputDevice.h b/include/ui/InputDevice.h
new file mode 100644
index 0000000..4420600
--- /dev/null
+++ b/include/ui/InputDevice.h
@@ -0,0 +1,338 @@
+/*
+ * 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 _UI_INPUT_DEVICE_H
+#define _UI_INPUT_DEVICE_H
+
+#include <ui/EventHub.h>
+#include <ui/Input.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Timers.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/BitSet.h>
+
+#include <stddef.h>
+#include <unistd.h>
+
+/* Maximum pointer id value supported.
+ * (This is limited by our use of BitSet32 to track pointer assignments.) */
+#define MAX_POINTER_ID 31
+
+/* Maximum number of historical samples to average. */
+#define AVERAGING_HISTORY_SIZE 5
+
+
+namespace android {
+
+extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
+extern int32_t rotateKeyCode(int32_t keyCode, int32_t orientation);
+
+/*
+ * An input device structure tracks the state of a single input device.
+ *
+ * This structure is only used by ReaderThread and is not intended to be shared with
+ * DispatcherThread (because that would require locking).  This works out fine because
+ * DispatcherThread is only interested in cooked event data anyways and does not need
+ * any of the low-level data from InputDevice.
+ */
+struct InputDevice {
+    struct AbsoluteAxisInfo {
+        bool valid;        // set to true if axis parameters are known, false otherwise
+
+        int32_t minValue;  // minimum value
+        int32_t maxValue;  // maximum value
+        int32_t range;     // range of values, equal to maxValue - minValue
+        int32_t flat;      // center flat position, eg. flat == 8 means center is between -8 and 8
+        int32_t fuzz;      // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
+    };
+
+    struct VirtualKey {
+        int32_t keyCode;
+        int32_t scanCode;
+        uint32_t flags;
+
+        // computed hit box, specified in touch screen coords based on known display size
+        int32_t hitLeft;
+        int32_t hitTop;
+        int32_t hitRight;
+        int32_t hitBottom;
+
+        inline bool isHit(int32_t x, int32_t y) const {
+            return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
+        }
+    };
+
+    struct KeyboardState {
+        struct Current {
+            int32_t metaState;
+            nsecs_t downTime; // time of most recent key down
+        } current;
+
+        void reset();
+    };
+
+    struct TrackballState {
+        struct Accumulator {
+            enum {
+                FIELD_BTN_MOUSE = 1,
+                FIELD_REL_X = 2,
+                FIELD_REL_Y = 4
+            };
+
+            uint32_t fields;
+
+            bool btnMouse;
+            int32_t relX;
+            int32_t relY;
+
+            inline void clear() {
+                fields = 0;
+            }
+
+            inline bool isDirty() {
+                return fields != 0;
+            }
+        } accumulator;
+
+        struct Current {
+            bool down;
+            nsecs_t downTime;
+        } current;
+
+        struct Precalculated {
+            float xScale;
+            float yScale;
+            float xPrecision;
+            float yPrecision;
+        } precalculated;
+
+        void reset();
+    };
+
+    struct SingleTouchScreenState {
+        struct Accumulator {
+            enum {
+                FIELD_BTN_TOUCH = 1,
+                FIELD_ABS_X = 2,
+                FIELD_ABS_Y = 4,
+                FIELD_ABS_PRESSURE = 8,
+                FIELD_ABS_TOOL_WIDTH = 16
+            };
+
+            uint32_t fields;
+
+            bool btnTouch;
+            int32_t absX;
+            int32_t absY;
+            int32_t absPressure;
+            int32_t absToolWidth;
+
+            inline void clear() {
+                fields = 0;
+            }
+
+            inline bool isDirty() {
+                return fields != 0;
+            }
+        } accumulator;
+
+        struct Current {
+            bool down;
+            int32_t x;
+            int32_t y;
+            int32_t pressure;
+            int32_t size;
+        } current;
+
+        void reset();
+    };
+
+    struct MultiTouchScreenState {
+        struct Accumulator {
+            enum {
+                FIELD_ABS_MT_POSITION_X = 1,
+                FIELD_ABS_MT_POSITION_Y = 2,
+                FIELD_ABS_MT_TOUCH_MAJOR = 4,
+                FIELD_ABS_MT_WIDTH_MAJOR = 8,
+                FIELD_ABS_MT_TRACKING_ID = 16
+            };
+
+            uint32_t pointerCount;
+            struct Pointer {
+                uint32_t fields;
+
+                int32_t absMTPositionX;
+                int32_t absMTPositionY;
+                int32_t absMTTouchMajor;
+                int32_t absMTWidthMajor;
+                int32_t absMTTrackingId;
+
+                inline void clear() {
+                    fields = 0;
+                }
+            } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
+
+            inline void clear() {
+                pointerCount = 0;
+                pointers[0].clear();
+            }
+
+            inline bool isDirty() {
+                return pointerCount != 0;
+            }
+        } accumulator;
+
+        void reset();
+    };
+
+    struct PointerData {
+        uint32_t id;
+        int32_t x;
+        int32_t y;
+        int32_t pressure;
+        int32_t size;
+    };
+
+    struct TouchData {
+        uint32_t pointerCount;
+        PointerData pointers[MAX_POINTERS];
+        BitSet32 idBits;
+        uint32_t idToIndex[MAX_POINTER_ID + 1];
+
+        void copyFrom(const TouchData& other);
+
+        inline void clear() {
+            pointerCount = 0;
+            idBits.clear();
+        }
+    };
+
+    // common state used for both single-touch and multi-touch screens after the initial
+    // touch decoding has been performed
+    struct TouchScreenState {
+        Vector<VirtualKey> virtualKeys;
+
+        struct Parameters {
+            bool useBadTouchFilter;
+            bool useJumpyTouchFilter;
+            bool useAveragingTouchFilter;
+
+            AbsoluteAxisInfo xAxis;
+            AbsoluteAxisInfo yAxis;
+            AbsoluteAxisInfo pressureAxis;
+            AbsoluteAxisInfo sizeAxis;
+        } parameters;
+
+        // The touch data of the current sample being processed.
+        TouchData currentTouch;
+
+        // The touch data of the previous sample that was processed.  This is updated
+        // incrementally while the current sample is being processed.
+        TouchData lastTouch;
+
+        // The time the primary pointer last went down.
+        nsecs_t downTime;
+
+        struct CurrentVirtualKeyState {
+            enum Status {
+                STATUS_UP,
+                STATUS_DOWN,
+                STATUS_CANCELED
+            };
+
+            Status status;
+            nsecs_t downTime;
+            int32_t keyCode;
+            int32_t scanCode;
+        } currentVirtualKey;
+
+        struct AveragingTouchFilterState {
+            // Individual history tracks are stored by pointer id
+            uint32_t historyStart[MAX_POINTERS];
+            uint32_t historyEnd[MAX_POINTERS];
+            struct {
+                struct {
+                    int32_t x;
+                    int32_t y;
+                    int32_t pressure;
+                } pointers[MAX_POINTERS];
+            } historyData[AVERAGING_HISTORY_SIZE];
+        } averagingTouchFilter;
+
+        struct JumpTouchFilterState {
+            int32_t jumpyPointsDropped;
+        } jumpyTouchFilter;
+
+        struct Precalculated {
+            int32_t xOrigin;
+            float xScale;
+
+            int32_t yOrigin;
+            float yScale;
+
+            int32_t pressureOrigin;
+            float pressureScale;
+
+            int32_t sizeOrigin;
+            float sizeScale;
+        } precalculated;
+
+        void reset();
+
+        bool applyBadTouchFilter();
+        bool applyJumpyTouchFilter();
+        void applyAveragingTouchFilter();
+        void calculatePointerIds();
+
+        bool isPointInsideDisplay(int32_t x, int32_t y) const;
+        const InputDevice::VirtualKey* findVirtualKeyHit() const;
+    };
+
+    InputDevice(int32_t id, uint32_t classes, String8 name);
+
+    int32_t id;
+    uint32_t classes;
+    String8 name;
+    bool ignored;
+
+    KeyboardState keyboard;
+    TrackballState trackball;
+    TouchScreenState touchScreen;
+    union {
+        SingleTouchScreenState singleTouchScreen;
+        MultiTouchScreenState multiTouchScreen;
+    };
+
+    void reset();
+
+    inline bool isKeyboard() const { return classes & INPUT_DEVICE_CLASS_KEYBOARD; }
+    inline bool isAlphaKey() const { return classes & INPUT_DEVICE_CLASS_ALPHAKEY; }
+    inline bool isTrackball() const { return classes & INPUT_DEVICE_CLASS_TRACKBALL; }
+    inline bool isDPad() const { return classes & INPUT_DEVICE_CLASS_DPAD; }
+    inline bool isSingleTouchScreen() const { return (classes
+            & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT))
+            == INPUT_DEVICE_CLASS_TOUCHSCREEN; }
+    inline bool isMultiTouchScreen() const { return classes
+            & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; }
+    inline bool isTouchScreen() const { return classes
+            & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT); }
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_DEVICE_H
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 03c8112..85a0084 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -19,6 +19,7 @@
 
 #include <ui/EventHub.h>
 #include <ui/Input.h>
+#include <ui/InputDevice.h>
 #include <ui/InputDispatcher.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
@@ -30,311 +31,8 @@
 #include <stddef.h>
 #include <unistd.h>
 
-/* Maximum pointer id value supported.
- * (This is limited by our use of BitSet32 to track pointer assignments.) */
-#define MAX_POINTER_ID 32
-
-/* Maximum number of historical samples to average. */
-#define AVERAGING_HISTORY_SIZE 5
-
-
 namespace android {
 
-extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
-extern int32_t rotateKeyCode(int32_t keyCode, int32_t orientation);
-
-/*
- * An input device structure tracks the state of a single input device.
- *
- * This structure is only used by ReaderThread and is not intended to be shared with
- * DispatcherThread (because that would require locking).  This works out fine because
- * DispatcherThread is only interested in cooked event data anyways and does not need
- * any of the low-level data from InputDevice.
- */
-struct InputDevice {
-    struct AbsoluteAxisInfo {
-        bool valid;        // set to true if axis parameters are known, false otherwise
-
-        int32_t minValue;  // minimum value
-        int32_t maxValue;  // maximum value
-        int32_t range;     // range of values, equal to maxValue - minValue
-        int32_t flat;      // center flat position, eg. flat == 8 means center is between -8 and 8
-        int32_t fuzz;      // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise
-    };
-
-    struct VirtualKey {
-        int32_t keyCode;
-        int32_t scanCode;
-        uint32_t flags;
-
-        // computed hit box, specified in touch screen coords based on known display size
-        int32_t hitLeft;
-        int32_t hitTop;
-        int32_t hitRight;
-        int32_t hitBottom;
-
-        inline bool isHit(int32_t x, int32_t y) const {
-            return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom;
-        }
-    };
-
-    struct KeyboardState {
-        struct Current {
-            int32_t metaState;
-            nsecs_t downTime; // time of most recent key down
-        } current;
-
-        void reset();
-    };
-
-    struct TrackballState {
-        struct Accumulator {
-            enum {
-                FIELD_BTN_MOUSE = 1,
-                FIELD_REL_X = 2,
-                FIELD_REL_Y = 4
-            };
-
-            uint32_t fields;
-
-            bool btnMouse;
-            int32_t relX;
-            int32_t relY;
-
-            inline void clear() {
-                fields = 0;
-            }
-
-            inline bool isDirty() {
-                return fields != 0;
-            }
-        } accumulator;
-
-        struct Current {
-            bool down;
-            nsecs_t downTime;
-        } current;
-
-        struct Precalculated {
-            float xScale;
-            float yScale;
-            float xPrecision;
-            float yPrecision;
-        } precalculated;
-
-        void reset();
-    };
-
-    struct SingleTouchScreenState {
-        struct Accumulator {
-            enum {
-                FIELD_BTN_TOUCH = 1,
-                FIELD_ABS_X = 2,
-                FIELD_ABS_Y = 4,
-                FIELD_ABS_PRESSURE = 8,
-                FIELD_ABS_TOOL_WIDTH = 16
-            };
-
-            uint32_t fields;
-
-            bool btnTouch;
-            int32_t absX;
-            int32_t absY;
-            int32_t absPressure;
-            int32_t absToolWidth;
-
-            inline void clear() {
-                fields = 0;
-            }
-
-            inline bool isDirty() {
-                return fields != 0;
-            }
-        } accumulator;
-
-        struct Current {
-            bool down;
-            int32_t x;
-            int32_t y;
-            int32_t pressure;
-            int32_t size;
-        } current;
-
-        void reset();
-    };
-
-    struct MultiTouchScreenState {
-        struct Accumulator {
-            enum {
-                FIELD_ABS_MT_POSITION_X = 1,
-                FIELD_ABS_MT_POSITION_Y = 2,
-                FIELD_ABS_MT_TOUCH_MAJOR = 4,
-                FIELD_ABS_MT_WIDTH_MAJOR = 8,
-                FIELD_ABS_MT_TRACKING_ID = 16
-            };
-
-            uint32_t pointerCount;
-            struct Pointer {
-                uint32_t fields;
-
-                int32_t absMTPositionX;
-                int32_t absMTPositionY;
-                int32_t absMTTouchMajor;
-                int32_t absMTWidthMajor;
-                int32_t absMTTrackingId;
-
-                inline void clear() {
-                    fields = 0;
-                }
-            } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks
-
-            inline void clear() {
-                pointerCount = 0;
-                pointers[0].clear();
-            }
-
-            inline bool isDirty() {
-                return pointerCount != 0;
-            }
-        } accumulator;
-
-        void reset();
-    };
-
-    struct PointerData {
-        uint32_t id;
-        int32_t x;
-        int32_t y;
-        int32_t pressure;
-        int32_t size;
-    };
-
-    struct TouchData {
-        uint32_t pointerCount;
-        PointerData pointers[MAX_POINTERS];
-        BitSet32 idBits;
-        uint32_t idToIndex[MAX_POINTER_ID];
-
-        void copyFrom(const TouchData& other);
-
-        inline void clear() {
-            pointerCount = 0;
-            idBits.clear();
-        }
-    };
-
-    // common state used for both single-touch and multi-touch screens after the initial
-    // touch decoding has been performed
-    struct TouchScreenState {
-        Vector<VirtualKey> virtualKeys;
-
-        struct Parameters {
-            bool useBadTouchFilter;
-            bool useJumpyTouchFilter;
-            bool useAveragingTouchFilter;
-
-            AbsoluteAxisInfo xAxis;
-            AbsoluteAxisInfo yAxis;
-            AbsoluteAxisInfo pressureAxis;
-            AbsoluteAxisInfo sizeAxis;
-        } parameters;
-
-        // The touch data of the current sample being processed.
-        TouchData currentTouch;
-
-        // The touch data of the previous sample that was processed.  This is updated
-        // incrementally while the current sample is being processed.
-        TouchData lastTouch;
-
-        // The time the primary pointer last went down.
-        nsecs_t downTime;
-
-        struct CurrentVirtualKeyState {
-            enum Status {
-                STATUS_UP,
-                STATUS_DOWN,
-                STATUS_CANCELED
-            };
-
-            Status status;
-            nsecs_t downTime;
-            int32_t keyCode;
-            int32_t scanCode;
-        } currentVirtualKey;
-
-        struct AveragingTouchFilterState {
-            // Individual history tracks are stored by pointer id
-            uint32_t historyStart[MAX_POINTERS];
-            uint32_t historyEnd[MAX_POINTERS];
-            struct {
-                struct {
-                    int32_t x;
-                    int32_t y;
-                    int32_t pressure;
-                } pointers[MAX_POINTERS];
-            } historyData[AVERAGING_HISTORY_SIZE];
-        } averagingTouchFilter;
-
-        struct JumpTouchFilterState {
-            int32_t jumpyPointsDropped;
-        } jumpyTouchFilter;
-
-        struct Precalculated {
-            int32_t xOrigin;
-            float xScale;
-
-            int32_t yOrigin;
-            float yScale;
-
-            int32_t pressureOrigin;
-            float pressureScale;
-
-            int32_t sizeOrigin;
-            float sizeScale;
-        } precalculated;
-
-        void reset();
-
-        bool applyBadTouchFilter();
-        bool applyJumpyTouchFilter();
-        void applyAveragingTouchFilter();
-        void calculatePointerIds();
-
-        bool isPointInsideDisplay(int32_t x, int32_t y) const;
-        const InputDevice::VirtualKey* findVirtualKeyHit() const;
-    };
-
-    InputDevice(int32_t id, uint32_t classes, String8 name);
-
-    int32_t id;
-    uint32_t classes;
-    String8 name;
-    bool ignored;
-
-    KeyboardState keyboard;
-    TrackballState trackball;
-    TouchScreenState touchScreen;
-    union {
-        SingleTouchScreenState singleTouchScreen;
-        MultiTouchScreenState multiTouchScreen;
-    };
-
-    void reset();
-
-    inline bool isKeyboard() const { return classes & INPUT_DEVICE_CLASS_KEYBOARD; }
-    inline bool isAlphaKey() const { return classes & INPUT_DEVICE_CLASS_ALPHAKEY; }
-    inline bool isTrackball() const { return classes & INPUT_DEVICE_CLASS_TRACKBALL; }
-    inline bool isDPad() const { return classes & INPUT_DEVICE_CLASS_DPAD; }
-    inline bool isSingleTouchScreen() const { return (classes
-            & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT))
-            == INPUT_DEVICE_CLASS_TOUCHSCREEN; }
-    inline bool isMultiTouchScreen() const { return classes
-            & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT; }
-    inline bool isTouchScreen() const { return classes
-            & (INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT); }
-};
-
-
 /*
  * Input reader policy interface.
  *
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 11714d5..226d1d5 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -331,30 +331,4 @@
 
 } // namespace android
 
-/*
- * NDK input queue API.
- */
-struct AInputQueue {
-public:
-    /* Creates a consumer associated with an input channel. */
-    explicit AInputQueue(const android::sp<android::InputChannel>& channel);
-
-    /* Destroys the consumer and releases its input channel. */
-    virtual ~AInputQueue();
-
-    inline android::InputConsumer& getConsumer() { return mConsumer; }
-    
-    android::status_t consume(android::InputEvent** event);
-    
-    void setPollLoop(const android::sp<android::PollLoop>& pollLoop) { mPollLoop = pollLoop; }
-    const android::sp<android::PollLoop> getPollLoop() const { return mPollLoop; }
-    
-    virtual void doDefaultKey(android::KeyEvent* keyEvent) = 0;
-    
-private:
-    android::InputConsumer mConsumer;
-    android::PreallocatedInputEventFactory mInputEventFactory;
-    android::sp<android::PollLoop> mPollLoop;
-};
-
 #endif // _UI_INPUT_TRANSPORT_H
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index e81d0f9..c8d6ffc 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -17,6 +17,8 @@
 #ifndef _UI_KEYCODE_LABELS_H
 #define _UI_KEYCODE_LABELS_H
 
+#include <android/keycodes.h>
+
 struct KeycodeLabel {
     const char *literal;
     int value;
@@ -118,117 +120,28 @@
     { "PAGE_DOWN", 93 },
     { "PICTSYMBOLS", 94 },
     { "SWITCH_CHARSET", 95 },
+    { "BUTTON_A", 96 },
+    { "BUTTON_B", 97 },
+    { "BUTTON_C", 98 },
+    { "BUTTON_X", 99 },
+    { "BUTTON_Y", 100 },
+    { "BUTTON_Z", 101 },
+    { "BUTTON_L1", 102 },
+    { "BUTTON_R1", 103 },
+    { "BUTTON_L2", 104 },
+    { "BUTTON_R2", 105 },
+    { "BUTTON_THUMBL", 106 },
+    { "BUTTON_THUMBR", 107 },
+    { "BUTTON_START", 108 },
+    { "BUTTON_SELECT", 109 },
+    { "BUTTON_MODE", 110 },
 
-    // NOTE: If you add a new keycode here you must also add it to:
-    //   (enum KeyCode, in this file)
-    //   frameworks/base/core/java/android/view/KeyEvent.java
-    //   tools/puppet_master/PuppetMaster.nav_keys.py
-    //   frameworks/base/core/res/res/values/attrs.xml
+    // NOTE: If you add a new keycode here you must also add it to several other files.
+    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
 
     { NULL, 0 }
 };
 
-// These constants need to match the above mappings.
-typedef enum KeyCode {
-    kKeyCodeUnknown = 0,
-
-    kKeyCodeSoftLeft = 1,
-    kKeyCodeSoftRight = 2,
-    kKeyCodeHome = 3,
-    kKeyCodeBack = 4,
-    kKeyCodeCall = 5,
-    kKeyCodeEndCall = 6,
-    kKeyCode0 = 7,
-    kKeyCode1 = 8,
-    kKeyCode2 = 9,
-    kKeyCode3 = 10,
-    kKeyCode4 = 11,
-    kKeyCode5 = 12,
-    kKeyCode6 = 13,
-    kKeyCode7 = 14,
-    kKeyCode8 = 15,
-    kKeyCode9 = 16,
-    kKeyCodeStar = 17,
-    kKeyCodePound = 18,
-    kKeyCodeDpadUp = 19,
-    kKeyCodeDpadDown = 20,
-    kKeyCodeDpadLeft = 21,
-    kKeyCodeDpadRight = 22,
-    kKeyCodeDpadCenter = 23,
-    kKeyCodeVolumeUp = 24,
-    kKeyCodeVolumeDown = 25,
-    kKeyCodePower = 26,
-    kKeyCodeCamera = 27,
-    kKeyCodeClear = 28,
-    kKeyCodeA = 29,
-    kKeyCodeB = 30,
-    kKeyCodeC = 31,
-    kKeyCodeD = 32,
-    kKeyCodeE = 33,
-    kKeyCodeF = 34,
-    kKeyCodeG = 35,
-    kKeyCodeH = 36,
-    kKeyCodeI = 37,
-    kKeyCodeJ = 38,
-    kKeyCodeK = 39,
-    kKeyCodeL = 40,
-    kKeyCodeM = 41,
-    kKeyCodeN = 42,
-    kKeyCodeO = 43,
-    kKeyCodeP = 44,
-    kKeyCodeQ = 45,
-    kKeyCodeR = 46,
-    kKeyCodeS = 47,
-    kKeyCodeT = 48,
-    kKeyCodeU = 49,
-    kKeyCodeV = 50,
-    kKeyCodeW = 51,
-    kKeyCodeX = 52,
-    kKeyCodeY = 53,
-    kKeyCodeZ = 54,
-    kKeyCodeComma = 55,
-    kKeyCodePeriod = 56,
-    kKeyCodeAltLeft = 57,
-    kKeyCodeAltRight = 58,
-    kKeyCodeShiftLeft = 59,
-    kKeyCodeShiftRight = 60,
-    kKeyCodeTab = 61,
-    kKeyCodeSpace = 62,
-    kKeyCodeSym = 63,
-    kKeyCodeExplorer = 64,
-    kKeyCodeEnvelope = 65,
-    kKeyCodeNewline = 66,
-    kKeyCodeDel = 67,
-    kKeyCodeGrave = 68,
-    kKeyCodeMinus = 69,
-    kKeyCodeEquals = 70,
-    kKeyCodeLeftBracket = 71,
-    kKeyCodeRightBracket = 72,
-    kKeyCodeBackslash = 73,
-    kKeyCodeSemicolon = 74,
-    kKeyCodeApostrophe = 75,
-    kKeyCodeSlash = 76,
-    kKeyCodeAt = 77,
-    kKeyCodeNum = 78,
-    kKeyCodeHeadSetHook = 79,
-    kKeyCodeFocus = 80,
-    kKeyCodePlus = 81,
-    kKeyCodeMenu = 82,
-    kKeyCodeNotification = 83,
-    kKeyCodeSearch = 84,
-    kKeyCodePlayPause = 85,
-    kKeyCodeStop = 86,
-    kKeyCodeNextSong = 87,
-    kKeyCodePreviousSong = 88,
-    kKeyCodeRewind = 89,
-    kKeyCodeForward = 90,
-    kKeyCodeMute = 91,
-    kKeyCodePageUp = 92,
-    kKeyCodePageDown = 93,
-    kKeyCodePictSymbols = 94,
-    kKeyCodeSwitchCharset = 95
-} KeyCode;
-
 static const KeycodeLabel FLAGS[] = {
     { "WAKE", 0x00000001 },
     { "WAKE_DROPPED", 0x00000002 },
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index e6f46ce..97eb6c0 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -17,8 +17,7 @@
 
 
 #define LOG_TAG "AudioFlinger"
-//
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 
 #include <math.h>
 #include <signal.h>
@@ -5085,15 +5084,53 @@
     }
 }
 
+void AudioFlinger::EffectModule::updateState() {
+    Mutex::Autolock _l(mLock);
+
+    switch (mState) {
+    case RESTART:
+        reset_l();
+        // FALL THROUGH
+
+    case STARTING:
+        // clear auxiliary effect input buffer for next accumulation
+        if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            memset(mConfig.inputCfg.buffer.raw,
+                   0,
+                   mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
+        }
+        start_l();
+        mState = ACTIVE;
+        break;
+    case STOPPING:
+        stop_l();
+        mDisableWaitCnt = mMaxDisableWaitCnt;
+        mState = STOPPED;
+        break;
+    case STOPPED:
+        // mDisableWaitCnt is forced to 1 by process() when the engine indicates the end of the
+        // turn off sequence.
+        if (--mDisableWaitCnt == 0) {
+            reset_l();
+            mState = IDLE;
+        }
+        break;
+    default: //IDLE , ACTIVE
+        break;
+    }
+}
+
 void AudioFlinger::EffectModule::process()
 {
     Mutex::Autolock _l(mLock);
 
-    if (mEffectInterface == NULL || mConfig.inputCfg.buffer.raw == NULL || mConfig.outputCfg.buffer.raw == NULL) {
+    if (mEffectInterface == NULL ||
+            mConfig.inputCfg.buffer.raw == NULL ||
+            mConfig.outputCfg.buffer.raw == NULL) {
         return;
     }
 
-    if (mState != IDLE) {
+    if (mState == ACTIVE || mState == STOPPING || mState == STOPPED) {
         // do 32 bit to 16 bit conversion for auxiliary effect input buffer
         if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
             AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
@@ -5101,33 +5138,15 @@
                                         mConfig.inputCfg.buffer.frameCount);
         }
 
-        // TODO: handle effects with buffer provider
-        if (mState != ACTIVE) {
-            switch (mState) {
-            case RESET:
-                reset_l();
-                mState = STARTING;
-                // clear auxiliary effect input buffer for next accumulation
-                if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
-                    memset(mConfig.inputCfg.buffer.raw, 0, mConfig.inputCfg.buffer.frameCount*sizeof(int32_t));
-                }
-                return;
-            case STARTING:
-                start_l();
-                mState = ACTIVE;
-                break;
-            case STOPPING:
-                mState = STOPPED;
-                break;
-            case STOPPED:
-                stop_l();
-                mState = IDLE;
-                return;
-            }
-        }
-
         // do the actual processing in the effect engine
-        (*mEffectInterface)->process(mEffectInterface, &mConfig.inputCfg.buffer, &mConfig.outputCfg.buffer);
+        int ret = (*mEffectInterface)->process(mEffectInterface,
+                                               &mConfig.inputCfg.buffer,
+                                               &mConfig.outputCfg.buffer);
+
+        // force transition to IDLE state when engine is ready
+        if (mState == STOPPED && ret == -ENODATA) {
+            mDisableWaitCnt = 1;
+        }
 
         // clear auxiliary effect input buffer for next accumulation
         if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
@@ -5216,6 +5235,10 @@
     if (status == 0) {
         status = cmdStatus;
     }
+
+    mMaxDisableWaitCnt = (MAX_DISABLE_TIME_MS * mConfig.outputCfg.samplingRate) /
+            (1000 * mConfig.outputCfg.buffer.frameCount);
+
     return status;
 }
 
@@ -5292,21 +5315,19 @@
         switch (mState) {
         // going from disabled to enabled
         case IDLE:
-            mState = RESET;
+            mState = STARTING;
+            break;
+        case STOPPED:
+            mState = RESTART;
             break;
         case STOPPING:
             mState = ACTIVE;
             break;
-        case STOPPED:
-            mState = STARTING;
-            break;
 
         // going from enabled to disabled
-        case RESET:
-            mState = IDLE;
-            break;
+        case RESTART:
         case STARTING:
-            mState = STOPPED;
+            mState = IDLE;
             break;
         case ACTIVE:
             mState = STOPPING;
@@ -5325,7 +5346,7 @@
 bool AudioFlinger::EffectModule::isEnabled()
 {
     switch (mState) {
-    case RESET:
+    case RESTART:
     case STARTING:
     case ACTIVE:
         return true;
@@ -5772,6 +5793,9 @@
     for (size_t i = 0; i < size; i++) {
         mEffects[i]->process();
     }
+    for (size_t i = 0; i < size; i++) {
+        mEffects[i]->updateState();
+    }
     // if no track is active, input buffer must be cleared here as the mixer process
     // will not do it
     if (mSessionId > 0 && activeTracks() == 0) {
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index ec3d7f1..507c9ac 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -905,7 +905,7 @@
 
         enum effect_state {
             IDLE,
-            RESET,
+            RESTART,
             STARTING,
             ACTIVE,
             STOPPING,
@@ -914,6 +914,7 @@
 
         int         id() { return mId; }
         void process();
+        void updateState();
         status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
 
         void reset_l();
@@ -948,6 +949,9 @@
 
     protected:
 
+        // Maximum time allocated to effect engines to complete the turn off sequence
+        static const uint32_t MAX_DISABLE_TIME_MS = 10000;
+
         EffectModule(const EffectModule&);
         EffectModule& operator = (const EffectModule&);
 
@@ -973,6 +977,9 @@
         status_t mStatus;               // initialization status
         uint32_t mState;                // current activation state (effect_state)
         Vector< wp<EffectHandle> > mHandles;    // list of client handles
+        uint32_t mMaxDisableWaitCnt;    // maximum grace period before forcing an effect off after
+                                        // sending disable command.
+        uint32_t mDisableWaitCnt;       // current process() calls count during disable period.
     };
 
     // The EffectHandle class implements the IEffect interface. It provides resources
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index bff4c9b..e13036f 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -36,7 +36,7 @@
         : BpInterface<IPermissionController>(impl)
     {
     }
-        
+
     virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
     {
         Parcel data, reply;
@@ -46,7 +46,7 @@
         data.writeInt32(uid);
         remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
         // fail on exception
-        if (reply.readInt32() != 0) return 0;
+        if (reply.readExceptionCode() != 0) return 0;
         return reply.readInt32() != 0;
     }
 };
@@ -66,8 +66,7 @@
             int32_t pid = data.readInt32();
             int32_t uid = data.readInt32();
             bool res = checkPermission(permission, pid, uid);
-            // write exception
-            reply->writeInt32(0);
+            reply->writeNoException();
             reply->writeInt32(res ? 1 : 0);
             return NO_ERROR;
         } break;
@@ -77,4 +76,3 @@
 }
 
 }; // namespace android
-
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index a3a3f0e..1fa4c35 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -158,7 +158,7 @@
         data.writeString16(name);
         data.writeStrongBinder(service);
         status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
-        return err == NO_ERROR ? reply.readInt32() : err;
+        return err == NO_ERROR ? reply.readExceptionCode() : err;
     }
 
     virtual Vector<String16> listServices()
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index c2574bd..47be1bf 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -754,6 +754,11 @@
     goto restart_write;
 }
 
+status_t Parcel::writeNoException()
+{
+    return writeInt32(0);
+}
+
 void Parcel::remove(size_t start, size_t amt)
 {
     LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
@@ -942,6 +947,12 @@
     return val;
 }
 
+int32_t Parcel::readExceptionCode() const
+{
+  int32_t exception_code = readAligned<int32_t>();
+  // TODO: skip over the response header here, once that's in.
+  return exception_code;
+}
 
 native_handle* Parcel::readNativeHandle() const
 {
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 24cdc78..4243bbf 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -12,6 +12,7 @@
 	KeyLayoutMap.cpp \
 	KeyCharacterMap.cpp \
 	Input.cpp \
+	InputDevice.cpp \
 	InputDispatcher.cpp \
 	InputManager.cpp \
 	InputReader.cpp \
@@ -38,3 +39,13 @@
 endif
 
 include $(BUILD_SHARED_LIBRARY)
+
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 27895f2..768b04e 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -54,6 +54,9 @@
  */
 #define test_bit(bit, array)    (array[bit/8] & (1<<(bit%8)))
 
+/* this macro computes the number of bytes needed to represent a bit array of the specified size */
+#define sizeof_bit_array(bits)  ((bits + 7) / 8)
+
 #define ID_MASK  0x0000ffff
 #define SEQ_MASK 0x7fff0000
 #define SEQ_SHIFT 16
@@ -182,7 +185,7 @@
 }
 
 int32_t EventHub::getScanCodeStateLocked(device_t* device, int32_t scanCode) const {
-    uint8_t key_bitmask[(KEY_MAX + 7) / 8];
+    uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
     if (ioctl(mFDs[id_to_index(device->id)].fd,
                EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
@@ -218,7 +221,7 @@
     Vector<int32_t> scanCodes;
     device->layoutMap->findScancodes(keyCode, &scanCodes);
 
-    uint8_t key_bitmask[(KEY_MAX + 7) / 8];
+    uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
     if (ioctl(mFDs[id_to_index(device->id)].fd,
                EVIOCGKEY(sizeof(key_bitmask)), key_bitmask) >= 0) {
@@ -264,7 +267,7 @@
 }
 
 int32_t EventHub::getSwitchStateLocked(device_t* device, int32_t sw) const {
-    uint8_t sw_bitmask[(SW_MAX + 7) / 8];
+    uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
     memset(sw_bitmask, 0, sizeof(sw_bitmask));
     if (ioctl(mFDs[id_to_index(device->id)].fd,
                EVIOCGSW(sizeof(sw_bitmask)), sw_bitmask) >= 0) {
@@ -409,7 +412,7 @@
                             LOGV("iev.code=%d outKeycode=%d outFlags=0x%08x err=%d\n",
                                 iev.code, *outKeycode, *outFlags, err);
                             if (err != 0) {
-                                *outKeycode = 0;
+                                *outKeycode = AKEYCODE_UNKNOWN;
                                 *outFlags = 0;
                             }
                         } else {
@@ -509,6 +512,26 @@
 
 // ----------------------------------------------------------------------------
 
+static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) {
+    const uint8_t* end = array + endIndex;
+    array += startIndex;
+    while (array != end) {
+        if (*(array++) != 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static const int32_t GAMEPAD_KEYCODES[] = {
+        AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C,
+        AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z,
+        AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1,
+        AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
+        AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
+        AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE
+};
+
 int EventHub::open_device(const char *deviceName)
 {
     int version;
@@ -626,27 +649,27 @@
     mFDs[mFDCount].fd = fd;
     mFDs[mFDCount].events = POLLIN;
 
-    // figure out the kinds of events the device reports
+    // Figure out the kinds of events the device reports.
     
-    // See if this is a keyboard, and classify it.  Note that we only
-    // consider up through the function keys; we don't want to include
-    // ones after that (play cd etc) so we don't mistakenly consider a
-    // controller to be a keyboard.
-    uint8_t key_bitmask[(KEY_MAX+7)/8];
+    uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
     memset(key_bitmask, 0, sizeof(key_bitmask));
+
     LOGV("Getting keys...");
     if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) >= 0) {
         //LOGI("MAP\n");
-        //for (int i=0; i<((KEY_MAX+7)/8); i++) {
+        //for (int i = 0; i < sizeof(key_bitmask); i++) {
         //    LOGI("%d: 0x%02x\n", i, key_bitmask[i]);
         //}
-        for (int i=0; i<((BTN_MISC+7)/8); i++) {
-            if (key_bitmask[i] != 0) {
-                device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
-                break;
-            }
-        }
-        if ((device->classes & INPUT_DEVICE_CLASS_KEYBOARD) != 0) {
+
+        // See if this is a keyboard.  Ignore everything in the button range except for
+        // gamepads which are also considered keyboards.
+        if (containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC))
+                || containsNonZeroByte(key_bitmask, sizeof_bit_array(BTN_GAMEPAD),
+                        sizeof_bit_array(BTN_DIGI))
+                || containsNonZeroByte(key_bitmask, sizeof_bit_array(KEY_OK),
+                        sizeof_bit_array(KEY_MAX + 1))) {
+            device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
+
             device->keyBitmask = new uint8_t[sizeof(key_bitmask)];
             if (device->keyBitmask != NULL) {
                 memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask));
@@ -658,39 +681,39 @@
         }
     }
     
-    // See if this is a trackball.
+    // See if this is a trackball (or mouse).
     if (test_bit(BTN_MOUSE, key_bitmask)) {
-        uint8_t rel_bitmask[(REL_MAX+7)/8];
+        uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
         memset(rel_bitmask, 0, sizeof(rel_bitmask));
         LOGV("Getting relative controllers...");
-        if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0)
-        {
+        if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) {
             if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
                 device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
             }
         }
     }
-    
-    uint8_t abs_bitmask[(ABS_MAX+7)/8];
+
+    // See if this is a touch pad.
+    uint8_t abs_bitmask[sizeof_bit_array(ABS_MAX + 1)];
     memset(abs_bitmask, 0, sizeof(abs_bitmask));
     LOGV("Getting absolute controllers...");
-    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask);
-    
-    // Is this a new modern multi-touch driver?
-    if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
-            && test_bit(ABS_MT_POSITION_X, abs_bitmask)
-            && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
-        device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT;
-        
-    // Is this an old style single-touch driver?
-    } else if (test_bit(BTN_TOUCH, key_bitmask)
-            && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
-        device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
+    if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) >= 0) {
+        // Is this a new modern multi-touch driver?
+        if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)
+                && test_bit(ABS_MT_POSITION_X, abs_bitmask)
+                && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {
+            device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN | INPUT_DEVICE_CLASS_TOUCHSCREEN_MT;
+
+        // Is this an old style single-touch driver?
+        } else if (test_bit(BTN_TOUCH, key_bitmask)
+                && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) {
+            device->classes |= INPUT_DEVICE_CLASS_TOUCHSCREEN;
+        }
     }
 
 #ifdef EV_SW
     // figure out the switches this device reports
-    uint8_t sw_bitmask[(SW_MAX+7)/8];
+    uint8_t sw_bitmask[sizeof_bit_array(SW_MAX + 1)];
     memset(sw_bitmask, 0, sizeof(sw_bitmask));
     if (ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask) >= 0) {
         for (int i=0; i<EV_SW; i++) {
@@ -726,7 +749,10 @@
                      "%s/usr/keylayout/%s", root, "qwerty.kl");
             defaultKeymap = true;
         }
-        device->layoutMap->load(keylayoutFilename);
+        status_t status = device->layoutMap->load(keylayoutFilename);
+        if (status) {
+            LOGE("Error %d loading key layout.", status);
+        }
 
         // tell the world about the devname (the descriptive name)
         if (!mHaveFirstKeyboard && !defaultKeymap && strstr(name, "-keypad")) {
@@ -746,19 +772,27 @@
         property_set(propName, name);
 
         // 'Q' key support = cheap test of whether this is an alpha-capable kbd
-        if (hasKeycode(device, kKeyCodeQ)) {
+        if (hasKeycode(device, AKEYCODE_Q)) {
             device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
         }
         
-        // See if this has a DPAD.
-        if (hasKeycode(device, kKeyCodeDpadUp) &&
-                hasKeycode(device, kKeyCodeDpadDown) &&
-                hasKeycode(device, kKeyCodeDpadLeft) &&
-                hasKeycode(device, kKeyCodeDpadRight) &&
-                hasKeycode(device, kKeyCodeDpadCenter)) {
+        // See if this device has a DPAD.
+        if (hasKeycode(device, AKEYCODE_DPAD_UP) &&
+                hasKeycode(device, AKEYCODE_DPAD_DOWN) &&
+                hasKeycode(device, AKEYCODE_DPAD_LEFT) &&
+                hasKeycode(device, AKEYCODE_DPAD_RIGHT) &&
+                hasKeycode(device, AKEYCODE_DPAD_CENTER)) {
             device->classes |= INPUT_DEVICE_CLASS_DPAD;
         }
         
+        // See if this device has a gamepad.
+        for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES); i++) {
+            if (hasKeycode(device, GAMEPAD_KEYCODES[i])) {
+                device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
+                break;
+            }
+        }
+
         LOGI("New keyboard: device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
                 device->id, name, propName, keylayoutFilename);
     }
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index a64251f..1f19c2c 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -22,26 +22,26 @@
 
 bool KeyEvent::hasDefaultAction(int32_t keyCode) {
     switch (keyCode) {
-        case KEYCODE_HOME:
-        case KEYCODE_BACK:
-        case KEYCODE_CALL:
-        case KEYCODE_ENDCALL:
-        case KEYCODE_VOLUME_UP:
-        case KEYCODE_VOLUME_DOWN:
-        case KEYCODE_POWER:
-        case KEYCODE_CAMERA:
-        case KEYCODE_HEADSETHOOK:
-        case KEYCODE_MENU:
-        case KEYCODE_NOTIFICATION:
-        case KEYCODE_FOCUS:
-        case KEYCODE_SEARCH:
-        case KEYCODE_MEDIA_PLAY_PAUSE:
-        case KEYCODE_MEDIA_STOP:
-        case KEYCODE_MEDIA_NEXT:
-        case KEYCODE_MEDIA_PREVIOUS:
-        case KEYCODE_MEDIA_REWIND:
-        case KEYCODE_MEDIA_FAST_FORWARD:
-        case KEYCODE_MUTE:
+        case AKEYCODE_HOME:
+        case AKEYCODE_BACK:
+        case AKEYCODE_CALL:
+        case AKEYCODE_ENDCALL:
+        case AKEYCODE_VOLUME_UP:
+        case AKEYCODE_VOLUME_DOWN:
+        case AKEYCODE_POWER:
+        case AKEYCODE_CAMERA:
+        case AKEYCODE_HEADSETHOOK:
+        case AKEYCODE_MENU:
+        case AKEYCODE_NOTIFICATION:
+        case AKEYCODE_FOCUS:
+        case AKEYCODE_SEARCH:
+        case AKEYCODE_MEDIA_PLAY_PAUSE:
+        case AKEYCODE_MEDIA_STOP:
+        case AKEYCODE_MEDIA_NEXT:
+        case AKEYCODE_MEDIA_PREVIOUS:
+        case AKEYCODE_MEDIA_REWIND:
+        case AKEYCODE_MEDIA_FAST_FORWARD:
+        case AKEYCODE_MUTE:
             return true;
     }
     
@@ -54,26 +54,26 @@
 
 bool KeyEvent::isSystemKey(int32_t keyCode) {
     switch (keyCode) {
-        case KEYCODE_MENU:
-        case KEYCODE_SOFT_RIGHT:
-        case KEYCODE_HOME:
-        case KEYCODE_BACK:
-        case KEYCODE_CALL:
-        case KEYCODE_ENDCALL:
-        case KEYCODE_VOLUME_UP:
-        case KEYCODE_VOLUME_DOWN:
-        case KEYCODE_MUTE:
-        case KEYCODE_POWER:
-        case KEYCODE_HEADSETHOOK:
-        case KEYCODE_MEDIA_PLAY_PAUSE:
-        case KEYCODE_MEDIA_STOP:
-        case KEYCODE_MEDIA_NEXT:
-        case KEYCODE_MEDIA_PREVIOUS:
-        case KEYCODE_MEDIA_REWIND:
-        case KEYCODE_MEDIA_FAST_FORWARD:
-        case KEYCODE_CAMERA:
-        case KEYCODE_FOCUS:
-        case KEYCODE_SEARCH:
+        case AKEYCODE_MENU:
+        case AKEYCODE_SOFT_RIGHT:
+        case AKEYCODE_HOME:
+        case AKEYCODE_BACK:
+        case AKEYCODE_CALL:
+        case AKEYCODE_ENDCALL:
+        case AKEYCODE_VOLUME_UP:
+        case AKEYCODE_VOLUME_DOWN:
+        case AKEYCODE_MUTE:
+        case AKEYCODE_POWER:
+        case AKEYCODE_HEADSETHOOK:
+        case AKEYCODE_MEDIA_PLAY_PAUSE:
+        case AKEYCODE_MEDIA_STOP:
+        case AKEYCODE_MEDIA_NEXT:
+        case AKEYCODE_MEDIA_PREVIOUS:
+        case AKEYCODE_MEDIA_REWIND:
+        case AKEYCODE_MEDIA_FAST_FORWARD:
+        case AKEYCODE_CAMERA:
+        case AKEYCODE_FOCUS:
+        case AKEYCODE_SEARCH:
             return true;
     }
     
diff --git a/libs/ui/InputDevice.cpp b/libs/ui/InputDevice.cpp
new file mode 100644
index 0000000..6014017
--- /dev/null
+++ b/libs/ui/InputDevice.cpp
@@ -0,0 +1,729 @@
+//
+// Copyright 2010 The Android Open Source Project
+//
+// The input reader.
+//
+#define LOG_TAG "InputDevice"
+
+//#define LOG_NDEBUG 0
+
+// Log debug messages for each raw event received from the EventHub.
+#define DEBUG_RAW_EVENTS 0
+
+// Log debug messages about touch screen filtering hacks.
+#define DEBUG_HACKS 0
+
+// Log debug messages about virtual key processing.
+#define DEBUG_VIRTUAL_KEYS 0
+
+// Log debug messages about pointers.
+#define DEBUG_POINTERS 0
+
+// Log debug messages about pointer assignment calculations.
+#define DEBUG_POINTER_ASSIGNMENT 0
+
+#include <cutils/log.h>
+#include <ui/InputDevice.h>
+
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+
+/* Slop distance for jumpy pointer detection.
+ * The vertical range of the screen divided by this is our epsilon value. */
+#define JUMPY_EPSILON_DIVISOR 212
+
+/* Number of jumpy points to drop for touchscreens that need it. */
+#define JUMPY_TRANSITION_DROPS 3
+#define JUMPY_DROP_LIMIT 3
+
+/* Maximum squared distance for averaging.
+ * If moving farther than this, turn of averaging to avoid lag in response. */
+#define AVERAGING_DISTANCE_LIMIT (75 * 75)
+
+
+namespace android {
+
+// --- Static Functions ---
+
+template<typename T>
+inline static T abs(const T& value) {
+    return value < 0 ? - value : value;
+}
+
+template<typename T>
+inline static T min(const T& a, const T& b) {
+    return a < b ? a : b;
+}
+
+template<typename T>
+inline static void swap(T& a, T& b) {
+    T temp = a;
+    a = b;
+    b = temp;
+}
+
+
+// --- InputDevice ---
+
+InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) :
+    id(id), classes(classes), name(name), ignored(false) {
+}
+
+void InputDevice::reset() {
+    if (isKeyboard()) {
+        keyboard.reset();
+    }
+
+    if (isTrackball()) {
+        trackball.reset();
+    }
+
+    if (isMultiTouchScreen()) {
+        multiTouchScreen.reset();
+    } else if (isSingleTouchScreen()) {
+        singleTouchScreen.reset();
+    }
+
+    if (isTouchScreen()) {
+        touchScreen.reset();
+    }
+}
+
+
+// --- InputDevice::TouchData ---
+
+void InputDevice::TouchData::copyFrom(const TouchData& other) {
+    pointerCount = other.pointerCount;
+    idBits = other.idBits;
+
+    for (uint32_t i = 0; i < pointerCount; i++) {
+        pointers[i] = other.pointers[i];
+        idToIndex[i] = other.idToIndex[i];
+    }
+}
+
+
+// --- InputDevice::KeyboardState ---
+
+void InputDevice::KeyboardState::reset() {
+    current.metaState = META_NONE;
+    current.downTime = 0;
+}
+
+
+// --- InputDevice::TrackballState ---
+
+void InputDevice::TrackballState::reset() {
+    accumulator.clear();
+    current.down = false;
+    current.downTime = 0;
+}
+
+
+// --- InputDevice::TouchScreenState ---
+
+void InputDevice::TouchScreenState::reset() {
+    lastTouch.clear();
+    downTime = 0;
+    currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP;
+
+    for (uint32_t i = 0; i < MAX_POINTERS; i++) {
+        averagingTouchFilter.historyStart[i] = 0;
+        averagingTouchFilter.historyEnd[i] = 0;
+    }
+
+    jumpyTouchFilter.jumpyPointsDropped = 0;
+}
+
+struct PointerDistanceHeapElement {
+    uint32_t currentPointerIndex : 8;
+    uint32_t lastPointerIndex : 8;
+    uint64_t distance : 48; // squared distance
+};
+
+void InputDevice::TouchScreenState::calculatePointerIds() {
+    uint32_t currentPointerCount = currentTouch.pointerCount;
+    uint32_t lastPointerCount = lastTouch.pointerCount;
+
+    if (currentPointerCount == 0) {
+        // No pointers to assign.
+        currentTouch.idBits.clear();
+    } else if (lastPointerCount == 0) {
+        // All pointers are new.
+        currentTouch.idBits.clear();
+        for (uint32_t i = 0; i < currentPointerCount; i++) {
+            currentTouch.pointers[i].id = i;
+            currentTouch.idToIndex[i] = i;
+            currentTouch.idBits.markBit(i);
+        }
+    } else if (currentPointerCount == 1 && lastPointerCount == 1) {
+        // Only one pointer and no change in count so it must have the same id as before.
+        uint32_t id = lastTouch.pointers[0].id;
+        currentTouch.pointers[0].id = id;
+        currentTouch.idToIndex[id] = 0;
+        currentTouch.idBits.value = BitSet32::valueForBit(id);
+    } else {
+        // General case.
+        // We build a heap of squared euclidean distances between current and last pointers
+        // associated with the current and last pointer indices.  Then, we find the best
+        // match (by distance) for each current pointer.
+        PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
+
+        uint32_t heapSize = 0;
+        for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
+                currentPointerIndex++) {
+            for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
+                    lastPointerIndex++) {
+                int64_t deltaX = currentTouch.pointers[currentPointerIndex].x
+                        - lastTouch.pointers[lastPointerIndex].x;
+                int64_t deltaY = currentTouch.pointers[currentPointerIndex].y
+                        - lastTouch.pointers[lastPointerIndex].y;
+
+                uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
+
+                // Insert new element into the heap (sift up).
+                heap[heapSize].currentPointerIndex = currentPointerIndex;
+                heap[heapSize].lastPointerIndex = lastPointerIndex;
+                heap[heapSize].distance = distance;
+                heapSize += 1;
+            }
+        }
+
+        // Heapify
+        for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
+            startIndex -= 1;
+            for (uint32_t parentIndex = startIndex; ;) {
+                uint32_t childIndex = parentIndex * 2 + 1;
+                if (childIndex >= heapSize) {
+                    break;
+                }
+
+                if (childIndex + 1 < heapSize
+                        && heap[childIndex + 1].distance < heap[childIndex].distance) {
+                    childIndex += 1;
+                }
+
+                if (heap[parentIndex].distance <= heap[childIndex].distance) {
+                    break;
+                }
+
+                swap(heap[parentIndex], heap[childIndex]);
+                parentIndex = childIndex;
+            }
+        }
+
+#if DEBUG_POINTER_ASSIGNMENT
+        LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
+        for (size_t i = 0; i < heapSize; i++) {
+            LOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
+                    i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+                    heap[i].distance);
+        }
+#endif
+
+        // Pull matches out by increasing order of distance.
+        // To avoid reassigning pointers that have already been matched, the loop keeps track
+        // of which last and current pointers have been matched using the matchedXXXBits variables.
+        // It also tracks the used pointer id bits.
+        BitSet32 matchedLastBits(0);
+        BitSet32 matchedCurrentBits(0);
+        BitSet32 usedIdBits(0);
+        bool first = true;
+        for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
+            for (;;) {
+                if (first) {
+                    // The first time through the loop, we just consume the root element of
+                    // the heap (the one with smallest distance).
+                    first = false;
+                } else {
+                    // Previous iterations consumed the root element of the heap.
+                    // Pop root element off of the heap (sift down).
+                    heapSize -= 1;
+                    assert(heapSize > 0);
+
+                    // Sift down.
+                    heap[0] = heap[heapSize];
+                    for (uint32_t parentIndex = 0; ;) {
+                        uint32_t childIndex = parentIndex * 2 + 1;
+                        if (childIndex >= heapSize) {
+                            break;
+                        }
+
+                        if (childIndex + 1 < heapSize
+                                && heap[childIndex + 1].distance < heap[childIndex].distance) {
+                            childIndex += 1;
+                        }
+
+                        if (heap[parentIndex].distance <= heap[childIndex].distance) {
+                            break;
+                        }
+
+                        swap(heap[parentIndex], heap[childIndex]);
+                        parentIndex = childIndex;
+                    }
+
+#if DEBUG_POINTER_ASSIGNMENT
+                    LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
+                    for (size_t i = 0; i < heapSize; i++) {
+                        LOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
+                                i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+                                heap[i].distance);
+                    }
+#endif
+                }
+
+                uint32_t currentPointerIndex = heap[0].currentPointerIndex;
+                if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
+
+                uint32_t lastPointerIndex = heap[0].lastPointerIndex;
+                if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
+
+                matchedCurrentBits.markBit(currentPointerIndex);
+                matchedLastBits.markBit(lastPointerIndex);
+
+                uint32_t id = lastTouch.pointers[lastPointerIndex].id;
+                currentTouch.pointers[currentPointerIndex].id = id;
+                currentTouch.idToIndex[id] = currentPointerIndex;
+                usedIdBits.markBit(id);
+
+#if DEBUG_POINTER_ASSIGNMENT
+                LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
+                        lastPointerIndex, currentPointerIndex, id, heap[0].distance);
+#endif
+                break;
+            }
+        }
+
+        // Assign fresh ids to new pointers.
+        if (currentPointerCount > lastPointerCount) {
+            for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
+                uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
+                uint32_t id = usedIdBits.firstUnmarkedBit();
+
+                currentTouch.pointers[currentPointerIndex].id = id;
+                currentTouch.idToIndex[id] = currentPointerIndex;
+                usedIdBits.markBit(id);
+
+#if DEBUG_POINTER_ASSIGNMENT
+                LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
+                        currentPointerIndex, id);
+#endif
+
+                if (--i == 0) break; // done
+                matchedCurrentBits.markBit(currentPointerIndex);
+            }
+        }
+
+        // Fix id bits.
+        currentTouch.idBits = usedIdBits;
+    }
+}
+
+/* Special hack for devices that have bad screen data: if one of the
+ * points has moved more than a screen height from the last position,
+ * then drop it. */
+bool InputDevice::TouchScreenState::applyBadTouchFilter() {
+    // This hack requires valid axis parameters.
+    if (! parameters.yAxis.valid) {
+        return false;
+    }
+
+    uint32_t pointerCount = currentTouch.pointerCount;
+
+    // Nothing to do if there are no points.
+    if (pointerCount == 0) {
+        return false;
+    }
+
+    // Don't do anything if a finger is going down or up.  We run
+    // here before assigning pointer IDs, so there isn't a good
+    // way to do per-finger matching.
+    if (pointerCount != lastTouch.pointerCount) {
+        return false;
+    }
+
+    // We consider a single movement across more than a 7/16 of
+    // the long size of the screen to be bad.  This was a magic value
+    // determined by looking at the maximum distance it is feasible
+    // to actually move in one sample.
+    int32_t maxDeltaY = parameters.yAxis.range * 7 / 16;
+
+    // XXX The original code in InputDevice.java included commented out
+    //     code for testing the X axis.  Note that when we drop a point
+    //     we don't actually restore the old X either.  Strange.
+    //     The old code also tries to track when bad points were previously
+    //     detected but it turns out that due to the placement of a "break"
+    //     at the end of the loop, we never set mDroppedBadPoint to true
+    //     so it is effectively dead code.
+    // Need to figure out if the old code is busted or just overcomplicated
+    // but working as intended.
+
+    // Look through all new points and see if any are farther than
+    // acceptable from all previous points.
+    for (uint32_t i = pointerCount; i-- > 0; ) {
+        int32_t y = currentTouch.pointers[i].y;
+        int32_t closestY = INT_MAX;
+        int32_t closestDeltaY = 0;
+
+#if DEBUG_HACKS
+        LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
+#endif
+
+        for (uint32_t j = pointerCount; j-- > 0; ) {
+            int32_t lastY = lastTouch.pointers[j].y;
+            int32_t deltaY = abs(y - lastY);
+
+#if DEBUG_HACKS
+            LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
+                    j, lastY, deltaY);
+#endif
+
+            if (deltaY < maxDeltaY) {
+                goto SkipSufficientlyClosePoint;
+            }
+            if (deltaY < closestDeltaY) {
+                closestDeltaY = deltaY;
+                closestY = lastY;
+            }
+        }
+
+        // Must not have found a close enough match.
+#if DEBUG_HACKS
+        LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
+                i, y, closestY, closestDeltaY, maxDeltaY);
+#endif
+
+        currentTouch.pointers[i].y = closestY;
+        return true; // XXX original code only corrects one point
+
+    SkipSufficientlyClosePoint: ;
+    }
+
+    // No change.
+    return false;
+}
+
+/* Special hack for devices that have bad screen data: drop points where
+ * the coordinate value for one axis has jumped to the other pointer's location.
+ */
+bool InputDevice::TouchScreenState::applyJumpyTouchFilter() {
+    // This hack requires valid axis parameters.
+    if (! parameters.yAxis.valid) {
+        return false;
+    }
+
+    uint32_t pointerCount = currentTouch.pointerCount;
+    if (lastTouch.pointerCount != pointerCount) {
+#if DEBUG_HACKS
+        LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
+                lastTouch.pointerCount, pointerCount);
+        for (uint32_t i = 0; i < pointerCount; i++) {
+            LOGD("  Pointer %d (%d, %d)", i,
+                    currentTouch.pointers[i].x, currentTouch.pointers[i].y);
+        }
+#endif
+
+        if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
+            if (lastTouch.pointerCount == 1 && pointerCount == 2) {
+                // Just drop the first few events going from 1 to 2 pointers.
+                // They're bad often enough that they're not worth considering.
+                currentTouch.pointerCount = 1;
+                jumpyTouchFilter.jumpyPointsDropped += 1;
+
+#if DEBUG_HACKS
+                LOGD("JumpyTouchFilter: Pointer 2 dropped");
+#endif
+                return true;
+            } else if (lastTouch.pointerCount == 2 && pointerCount == 1) {
+                // The event when we go from 2 -> 1 tends to be messed up too
+                currentTouch.pointerCount = 2;
+                currentTouch.pointers[0] = lastTouch.pointers[0];
+                currentTouch.pointers[1] = lastTouch.pointers[1];
+                jumpyTouchFilter.jumpyPointsDropped += 1;
+
+#if DEBUG_HACKS
+                for (int32_t i = 0; i < 2; i++) {
+                    LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
+                            currentTouch.pointers[i].x, currentTouch.pointers[i].y);
+                }
+#endif
+                return true;
+            }
+        }
+        // Reset jumpy points dropped on other transitions or if limit exceeded.
+        jumpyTouchFilter.jumpyPointsDropped = 0;
+
+#if DEBUG_HACKS
+        LOGD("JumpyTouchFilter: Transition - drop limit reset");
+#endif
+        return false;
+    }
+
+    // We have the same number of pointers as last time.
+    // A 'jumpy' point is one where the coordinate value for one axis
+    // has jumped to the other pointer's location. No need to do anything
+    // else if we only have one pointer.
+    if (pointerCount < 2) {
+        return false;
+    }
+
+    if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
+        int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR;
+
+        // We only replace the single worst jumpy point as characterized by pointer distance
+        // in a single axis.
+        int32_t badPointerIndex = -1;
+        int32_t badPointerReplacementIndex = -1;
+        int32_t badPointerDistance = INT_MIN; // distance to be corrected
+
+        for (uint32_t i = pointerCount; i-- > 0; ) {
+            int32_t x = currentTouch.pointers[i].x;
+            int32_t y = currentTouch.pointers[i].y;
+
+#if DEBUG_HACKS
+            LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
+#endif
+
+            // Check if a touch point is too close to another's coordinates
+            bool dropX = false, dropY = false;
+            for (uint32_t j = 0; j < pointerCount; j++) {
+                if (i == j) {
+                    continue;
+                }
+
+                if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) {
+                    dropX = true;
+                    break;
+                }
+
+                if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) {
+                    dropY = true;
+                    break;
+                }
+            }
+            if (! dropX && ! dropY) {
+                continue; // not jumpy
+            }
+
+            // Find a replacement candidate by comparing with older points on the
+            // complementary (non-jumpy) axis.
+            int32_t distance = INT_MIN; // distance to be corrected
+            int32_t replacementIndex = -1;
+
+            if (dropX) {
+                // X looks too close.  Find an older replacement point with a close Y.
+                int32_t smallestDeltaY = INT_MAX;
+                for (uint32_t j = 0; j < pointerCount; j++) {
+                    int32_t deltaY = abs(y - lastTouch.pointers[j].y);
+                    if (deltaY < smallestDeltaY) {
+                        smallestDeltaY = deltaY;
+                        replacementIndex = j;
+                    }
+                }
+                distance = abs(x - lastTouch.pointers[replacementIndex].x);
+            } else {
+                // Y looks too close.  Find an older replacement point with a close X.
+                int32_t smallestDeltaX = INT_MAX;
+                for (uint32_t j = 0; j < pointerCount; j++) {
+                    int32_t deltaX = abs(x - lastTouch.pointers[j].x);
+                    if (deltaX < smallestDeltaX) {
+                        smallestDeltaX = deltaX;
+                        replacementIndex = j;
+                    }
+                }
+                distance = abs(y - lastTouch.pointers[replacementIndex].y);
+            }
+
+            // If replacing this pointer would correct a worse error than the previous ones
+            // considered, then use this replacement instead.
+            if (distance > badPointerDistance) {
+                badPointerIndex = i;
+                badPointerReplacementIndex = replacementIndex;
+                badPointerDistance = distance;
+            }
+        }
+
+        // Correct the jumpy pointer if one was found.
+        if (badPointerIndex >= 0) {
+#if DEBUG_HACKS
+            LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
+                    badPointerIndex,
+                    lastTouch.pointers[badPointerReplacementIndex].x,
+                    lastTouch.pointers[badPointerReplacementIndex].y);
+#endif
+
+            currentTouch.pointers[badPointerIndex].x =
+                    lastTouch.pointers[badPointerReplacementIndex].x;
+            currentTouch.pointers[badPointerIndex].y =
+                    lastTouch.pointers[badPointerReplacementIndex].y;
+            jumpyTouchFilter.jumpyPointsDropped += 1;
+            return true;
+        }
+    }
+
+    jumpyTouchFilter.jumpyPointsDropped = 0;
+    return false;
+}
+
+/* Special hack for devices that have bad screen data: aggregate and
+ * compute averages of the coordinate data, to reduce the amount of
+ * jitter seen by applications. */
+void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
+    for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) {
+        uint32_t id = currentTouch.pointers[currentIndex].id;
+        int32_t x = currentTouch.pointers[currentIndex].x;
+        int32_t y = currentTouch.pointers[currentIndex].y;
+        int32_t pressure = currentTouch.pointers[currentIndex].pressure;
+
+        if (lastTouch.idBits.hasBit(id)) {
+            // Pointer was down before and is still down now.
+            // Compute average over history trace.
+            uint32_t start = averagingTouchFilter.historyStart[id];
+            uint32_t end = averagingTouchFilter.historyEnd[id];
+
+            int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x;
+            int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y;
+            uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
+
+#if DEBUG_HACKS
+            LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
+                    id, distance);
+#endif
+
+            if (distance < AVERAGING_DISTANCE_LIMIT) {
+                // Increment end index in preparation for recording new historical data.
+                end += 1;
+                if (end > AVERAGING_HISTORY_SIZE) {
+                    end = 0;
+                }
+
+                // If the end index has looped back to the start index then we have filled
+                // the historical trace up to the desired size so we drop the historical
+                // data at the start of the trace.
+                if (end == start) {
+                    start += 1;
+                    if (start > AVERAGING_HISTORY_SIZE) {
+                        start = 0;
+                    }
+                }
+
+                // Add the raw data to the historical trace.
+                averagingTouchFilter.historyStart[id] = start;
+                averagingTouchFilter.historyEnd[id] = end;
+                averagingTouchFilter.historyData[end].pointers[id].x = x;
+                averagingTouchFilter.historyData[end].pointers[id].y = y;
+                averagingTouchFilter.historyData[end].pointers[id].pressure = pressure;
+
+                // Average over all historical positions in the trace by total pressure.
+                int32_t averagedX = 0;
+                int32_t averagedY = 0;
+                int32_t totalPressure = 0;
+                for (;;) {
+                    int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x;
+                    int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y;
+                    int32_t historicalPressure = averagingTouchFilter.historyData[start]
+                            .pointers[id].pressure;
+
+                    averagedX += historicalX * historicalPressure;
+                    averagedY += historicalY * historicalPressure;
+                    totalPressure += historicalPressure;
+
+                    if (start == end) {
+                        break;
+                    }
+
+                    start += 1;
+                    if (start > AVERAGING_HISTORY_SIZE) {
+                        start = 0;
+                    }
+                }
+
+                averagedX /= totalPressure;
+                averagedY /= totalPressure;
+
+#if DEBUG_HACKS
+                LOGD("AveragingTouchFilter: Pointer id %d - "
+                        "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
+                        averagedX, averagedY);
+#endif
+
+                currentTouch.pointers[currentIndex].x = averagedX;
+                currentTouch.pointers[currentIndex].y = averagedY;
+            } else {
+#if DEBUG_HACKS
+                LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
+#endif
+            }
+        } else {
+#if DEBUG_HACKS
+            LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
+#endif
+        }
+
+        // Reset pointer history.
+        averagingTouchFilter.historyStart[id] = 0;
+        averagingTouchFilter.historyEnd[id] = 0;
+        averagingTouchFilter.historyData[0].pointers[id].x = x;
+        averagingTouchFilter.historyData[0].pointers[id].y = y;
+        averagingTouchFilter.historyData[0].pointers[id].pressure = pressure;
+    }
+}
+
+bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const {
+    if (! parameters.xAxis.valid || ! parameters.yAxis.valid) {
+        // Assume all points on a touch screen without valid axis parameters are
+        // inside the display.
+        return true;
+    }
+
+    return x >= parameters.xAxis.minValue
+        && x <= parameters.xAxis.maxValue
+        && y >= parameters.yAxis.minValue
+        && y <= parameters.yAxis.maxValue;
+}
+
+const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const {
+    int32_t x = currentTouch.pointers[0].x;
+    int32_t y = currentTouch.pointers[0].y;
+    for (size_t i = 0; i < virtualKeys.size(); i++) {
+        const InputDevice::VirtualKey& virtualKey = virtualKeys[i];
+
+#if DEBUG_VIRTUAL_KEYS
+        LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
+                "left=%d, top=%d, right=%d, bottom=%d",
+                x, y,
+                virtualKey.keyCode, virtualKey.scanCode,
+                virtualKey.hitLeft, virtualKey.hitTop,
+                virtualKey.hitRight, virtualKey.hitBottom);
+#endif
+
+        if (virtualKey.isHit(x, y)) {
+            return & virtualKey;
+        }
+    }
+
+    return NULL;
+}
+
+
+// --- InputDevice::SingleTouchScreenState ---
+
+void InputDevice::SingleTouchScreenState::reset() {
+    accumulator.clear();
+    current.down = false;
+    current.x = 0;
+    current.y = 0;
+    current.pressure = 0;
+    current.size = 0;
+}
+
+
+// --- InputDevice::MultiTouchScreenState ---
+
+void InputDevice::MultiTouchScreenState::reset() {
+    accumulator.clear();
+}
+
+} // namespace android
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index f809cba..c4ffce1 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -40,10 +40,10 @@
 
 // TODO, this needs to be somewhere else, perhaps in the policy
 static inline bool isMovementKey(int32_t keyCode) {
-    return keyCode == KEYCODE_DPAD_UP
-            || keyCode == KEYCODE_DPAD_DOWN
-            || keyCode == KEYCODE_DPAD_LEFT
-            || keyCode == KEYCODE_DPAD_RIGHT;
+    return keyCode == AKEYCODE_DPAD_UP
+            || keyCode == AKEYCODE_DPAD_DOWN
+            || keyCode == AKEYCODE_DPAD_LEFT
+            || keyCode == AKEYCODE_DPAD_RIGHT;
 }
 
 static inline nsecs_t now() {
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index fced15c..0a21db7 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -33,18 +33,6 @@
 /** Amount that trackball needs to move in order to generate a key event. */
 #define TRACKBALL_MOVEMENT_THRESHOLD 6
 
-/* Slop distance for jumpy pointer detection.
- * The vertical range of the screen divided by this is our epsilon value. */
-#define JUMPY_EPSILON_DIVISOR 212
-
-/* Number of jumpy points to drop for touchscreens that need it. */
-#define JUMPY_TRANSITION_DROPS 3
-#define JUMPY_DROP_LIMIT 3
-
-/* Maximum squared distance for averaging.
- * If moving farther than this, turn of averaging to avoid lag in response. */
-#define AVERAGING_DISTANCE_LIMIT (75 * 75)
-
 
 namespace android {
 
@@ -71,19 +59,19 @@
 int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
     int32_t mask;
     switch (keyCode) {
-    case KEYCODE_ALT_LEFT:
+    case AKEYCODE_ALT_LEFT:
         mask = META_ALT_LEFT_ON;
         break;
-    case KEYCODE_ALT_RIGHT:
+    case AKEYCODE_ALT_RIGHT:
         mask = META_ALT_RIGHT_ON;
         break;
-    case KEYCODE_SHIFT_LEFT:
+    case AKEYCODE_SHIFT_LEFT:
         mask = META_SHIFT_LEFT_ON;
         break;
-    case KEYCODE_SHIFT_RIGHT:
+    case AKEYCODE_SHIFT_RIGHT:
         mask = META_SHIFT_RIGHT_ON;
         break;
-    case KEYCODE_SYM:
+    case AKEYCODE_SYM:
         mask = META_SYM_ON;
         break;
     default:
@@ -107,10 +95,10 @@
 static const int32_t keyCodeRotationMap[][4] = {
         // key codes enumerated counter-clockwise with the original (unrotated) key first
         // no rotation,        90 degree rotation,  180 degree rotation, 270 degree rotation
-        { KEYCODE_DPAD_DOWN,   KEYCODE_DPAD_RIGHT,  KEYCODE_DPAD_UP,     KEYCODE_DPAD_LEFT },
-        { KEYCODE_DPAD_RIGHT,  KEYCODE_DPAD_UP,     KEYCODE_DPAD_LEFT,   KEYCODE_DPAD_DOWN },
-        { KEYCODE_DPAD_UP,     KEYCODE_DPAD_LEFT,   KEYCODE_DPAD_DOWN,   KEYCODE_DPAD_RIGHT },
-        { KEYCODE_DPAD_LEFT,   KEYCODE_DPAD_DOWN,   KEYCODE_DPAD_RIGHT,  KEYCODE_DPAD_UP },
+        { AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT },
+        { AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN },
+        { AKEYCODE_DPAD_UP,     AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT },
+        { AKEYCODE_DPAD_LEFT,   AKEYCODE_DPAD_DOWN,   AKEYCODE_DPAD_RIGHT,  AKEYCODE_DPAD_UP },
 };
 static const int keyCodeRotationMapSize =
         sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
@@ -127,668 +115,6 @@
 }
 
 
-// --- InputDevice ---
-
-InputDevice::InputDevice(int32_t id, uint32_t classes, String8 name) :
-    id(id), classes(classes), name(name), ignored(false) {
-}
-
-void InputDevice::reset() {
-    if (isKeyboard()) {
-        keyboard.reset();
-    }
-
-    if (isTrackball()) {
-        trackball.reset();
-    }
-
-    if (isMultiTouchScreen()) {
-        multiTouchScreen.reset();
-    } else if (isSingleTouchScreen()) {
-        singleTouchScreen.reset();
-    }
-
-    if (isTouchScreen()) {
-        touchScreen.reset();
-    }
-}
-
-
-// --- InputDevice::TouchData ---
-
-void InputDevice::TouchData::copyFrom(const TouchData& other) {
-    pointerCount = other.pointerCount;
-    idBits = other.idBits;
-
-    for (uint32_t i = 0; i < pointerCount; i++) {
-        pointers[i] = other.pointers[i];
-        idToIndex[i] = other.idToIndex[i];
-    }
-}
-
-
-// --- InputDevice::KeyboardState ---
-
-void InputDevice::KeyboardState::reset() {
-    current.metaState = META_NONE;
-    current.downTime = 0;
-}
-
-
-// --- InputDevice::TrackballState ---
-
-void InputDevice::TrackballState::reset() {
-    accumulator.clear();
-    current.down = false;
-    current.downTime = 0;
-}
-
-
-// --- InputDevice::TouchScreenState ---
-
-void InputDevice::TouchScreenState::reset() {
-    lastTouch.clear();
-    downTime = 0;
-    currentVirtualKey.status = CurrentVirtualKeyState::STATUS_UP;
-
-    for (uint32_t i = 0; i < MAX_POINTERS; i++) {
-        averagingTouchFilter.historyStart[i] = 0;
-        averagingTouchFilter.historyEnd[i] = 0;
-    }
-
-    jumpyTouchFilter.jumpyPointsDropped = 0;
-}
-
-struct PointerDistanceHeapElement {
-    uint32_t currentPointerIndex : 8;
-    uint32_t lastPointerIndex : 8;
-    uint64_t distance : 48; // squared distance
-};
-
-void InputDevice::TouchScreenState::calculatePointerIds() {
-    uint32_t currentPointerCount = currentTouch.pointerCount;
-    uint32_t lastPointerCount = lastTouch.pointerCount;
-
-    if (currentPointerCount == 0) {
-        // No pointers to assign.
-        currentTouch.idBits.clear();
-    } else if (lastPointerCount == 0) {
-        // All pointers are new.
-        currentTouch.idBits.clear();
-        for (uint32_t i = 0; i < currentPointerCount; i++) {
-            currentTouch.pointers[i].id = i;
-            currentTouch.idToIndex[i] = i;
-            currentTouch.idBits.markBit(i);
-        }
-    } else if (currentPointerCount == 1 && lastPointerCount == 1) {
-        // Only one pointer and no change in count so it must have the same id as before.
-        uint32_t id = lastTouch.pointers[0].id;
-        currentTouch.pointers[0].id = id;
-        currentTouch.idToIndex[id] = 0;
-        currentTouch.idBits.value = BitSet32::valueForBit(id);
-    } else {
-        // General case.
-        // We build a heap of squared euclidean distances between current and last pointers
-        // associated with the current and last pointer indices.  Then, we find the best
-        // match (by distance) for each current pointer.
-        PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
-
-        uint32_t heapSize = 0;
-        for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
-                currentPointerIndex++) {
-            for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
-                    lastPointerIndex++) {
-                int64_t deltaX = currentTouch.pointers[currentPointerIndex].x
-                        - lastTouch.pointers[lastPointerIndex].x;
-                int64_t deltaY = currentTouch.pointers[currentPointerIndex].y
-                        - lastTouch.pointers[lastPointerIndex].y;
-
-                uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
-
-                // Insert new element into the heap (sift up).
-                heap[heapSize].currentPointerIndex = currentPointerIndex;
-                heap[heapSize].lastPointerIndex = lastPointerIndex;
-                heap[heapSize].distance = distance;
-                heapSize += 1;
-            }
-        }
-
-        // Heapify
-        for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
-            startIndex -= 1;
-            for (uint32_t parentIndex = startIndex; ;) {
-                uint32_t childIndex = parentIndex * 2 + 1;
-                if (childIndex >= heapSize) {
-                    break;
-                }
-
-                if (childIndex + 1 < heapSize
-                        && heap[childIndex + 1].distance < heap[childIndex].distance) {
-                    childIndex += 1;
-                }
-
-                if (heap[parentIndex].distance <= heap[childIndex].distance) {
-                    break;
-                }
-
-                swap(heap[parentIndex], heap[childIndex]);
-                parentIndex = childIndex;
-            }
-        }
-
-#if DEBUG_POINTER_ASSIGNMENT
-        LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
-        for (size_t i = 0; i < heapSize; i++) {
-            LOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
-                    i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
-                    heap[i].distance);
-        }
-#endif
-
-        // Pull matches out by increasing order of distance.
-        // To avoid reassigning pointers that have already been matched, the loop keeps track
-        // of which last and current pointers have been matched using the matchedXXXBits variables.
-        // It also tracks the used pointer id bits.
-        BitSet32 matchedLastBits(0);
-        BitSet32 matchedCurrentBits(0);
-        BitSet32 usedIdBits(0);
-        bool first = true;
-        for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
-            for (;;) {
-                if (first) {
-                    // The first time through the loop, we just consume the root element of
-                    // the heap (the one with smallest distance).
-                    first = false;
-                } else {
-                    // Previous iterations consumed the root element of the heap.
-                    // Pop root element off of the heap (sift down).
-                    heapSize -= 1;
-                    assert(heapSize > 0);
-
-                    // Sift down.
-                    heap[0] = heap[heapSize];
-                    for (uint32_t parentIndex = 0; ;) {
-                        uint32_t childIndex = parentIndex * 2 + 1;
-                        if (childIndex >= heapSize) {
-                            break;
-                        }
-
-                        if (childIndex + 1 < heapSize
-                                && heap[childIndex + 1].distance < heap[childIndex].distance) {
-                            childIndex += 1;
-                        }
-
-                        if (heap[parentIndex].distance <= heap[childIndex].distance) {
-                            break;
-                        }
-
-                        swap(heap[parentIndex], heap[childIndex]);
-                        parentIndex = childIndex;
-                    }
-
-#if DEBUG_POINTER_ASSIGNMENT
-                    LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
-                    for (size_t i = 0; i < heapSize; i++) {
-                        LOGD("  heap[%d]: cur=%d, last=%d, distance=%lld",
-                                i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
-                                heap[i].distance);
-                    }
-#endif
-                }
-
-                uint32_t currentPointerIndex = heap[0].currentPointerIndex;
-                if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
-
-                uint32_t lastPointerIndex = heap[0].lastPointerIndex;
-                if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
-
-                matchedCurrentBits.markBit(currentPointerIndex);
-                matchedLastBits.markBit(lastPointerIndex);
-
-                uint32_t id = lastTouch.pointers[lastPointerIndex].id;
-                currentTouch.pointers[currentPointerIndex].id = id;
-                currentTouch.idToIndex[id] = currentPointerIndex;
-                usedIdBits.markBit(id);
-
-#if DEBUG_POINTER_ASSIGNMENT
-                LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
-                        lastPointerIndex, currentPointerIndex, id, heap[0].distance);
-#endif
-                break;
-            }
-        }
-
-        // Assign fresh ids to new pointers.
-        if (currentPointerCount > lastPointerCount) {
-            for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
-                uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
-                uint32_t id = usedIdBits.firstUnmarkedBit();
-
-                currentTouch.pointers[currentPointerIndex].id = id;
-                currentTouch.idToIndex[id] = currentPointerIndex;
-                usedIdBits.markBit(id);
-
-#if DEBUG_POINTER_ASSIGNMENT
-                LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
-                        currentPointerIndex, id);
-#endif
-
-                if (--i == 0) break; // done
-                matchedCurrentBits.markBit(currentPointerIndex);
-            }
-        }
-
-        // Fix id bits.
-        currentTouch.idBits = usedIdBits;
-    }
-}
-
-/* Special hack for devices that have bad screen data: if one of the
- * points has moved more than a screen height from the last position,
- * then drop it. */
-bool InputDevice::TouchScreenState::applyBadTouchFilter() {
-    // This hack requires valid axis parameters.
-    if (! parameters.yAxis.valid) {
-        return false;
-    }
-
-    uint32_t pointerCount = currentTouch.pointerCount;
-
-    // Nothing to do if there are no points.
-    if (pointerCount == 0) {
-        return false;
-    }
-
-    // Don't do anything if a finger is going down or up.  We run
-    // here before assigning pointer IDs, so there isn't a good
-    // way to do per-finger matching.
-    if (pointerCount != lastTouch.pointerCount) {
-        return false;
-    }
-
-    // We consider a single movement across more than a 7/16 of
-    // the long size of the screen to be bad.  This was a magic value
-    // determined by looking at the maximum distance it is feasible
-    // to actually move in one sample.
-    int32_t maxDeltaY = parameters.yAxis.range * 7 / 16;
-
-    // XXX The original code in InputDevice.java included commented out
-    //     code for testing the X axis.  Note that when we drop a point
-    //     we don't actually restore the old X either.  Strange.
-    //     The old code also tries to track when bad points were previously
-    //     detected but it turns out that due to the placement of a "break"
-    //     at the end of the loop, we never set mDroppedBadPoint to true
-    //     so it is effectively dead code.
-    // Need to figure out if the old code is busted or just overcomplicated
-    // but working as intended.
-
-    // Look through all new points and see if any are farther than
-    // acceptable from all previous points.
-    for (uint32_t i = pointerCount; i-- > 0; ) {
-        int32_t y = currentTouch.pointers[i].y;
-        int32_t closestY = INT_MAX;
-        int32_t closestDeltaY = 0;
-
-#if DEBUG_HACKS
-        LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
-#endif
-
-        for (uint32_t j = pointerCount; j-- > 0; ) {
-            int32_t lastY = lastTouch.pointers[j].y;
-            int32_t deltaY = abs(y - lastY);
-
-#if DEBUG_HACKS
-            LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
-                    j, lastY, deltaY);
-#endif
-
-            if (deltaY < maxDeltaY) {
-                goto SkipSufficientlyClosePoint;
-            }
-            if (deltaY < closestDeltaY) {
-                closestDeltaY = deltaY;
-                closestY = lastY;
-            }
-        }
-
-        // Must not have found a close enough match.
-#if DEBUG_HACKS
-        LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
-                i, y, closestY, closestDeltaY, maxDeltaY);
-#endif
-
-        currentTouch.pointers[i].y = closestY;
-        return true; // XXX original code only corrects one point
-
-    SkipSufficientlyClosePoint: ;
-    }
-
-    // No change.
-    return false;
-}
-
-/* Special hack for devices that have bad screen data: drop points where
- * the coordinate value for one axis has jumped to the other pointer's location.
- */
-bool InputDevice::TouchScreenState::applyJumpyTouchFilter() {
-    // This hack requires valid axis parameters.
-    if (! parameters.yAxis.valid) {
-        return false;
-    }
-
-    uint32_t pointerCount = currentTouch.pointerCount;
-    if (lastTouch.pointerCount != pointerCount) {
-#if DEBUG_HACKS
-        LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
-                lastTouch.pointerCount, pointerCount);
-        for (uint32_t i = 0; i < pointerCount; i++) {
-            LOGD("  Pointer %d (%d, %d)", i,
-                    currentTouch.pointers[i].x, currentTouch.pointers[i].y);
-        }
-#endif
-
-        if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
-            if (lastTouch.pointerCount == 1 && pointerCount == 2) {
-                // Just drop the first few events going from 1 to 2 pointers.
-                // They're bad often enough that they're not worth considering.
-                currentTouch.pointerCount = 1;
-                jumpyTouchFilter.jumpyPointsDropped += 1;
-
-#if DEBUG_HACKS
-                LOGD("JumpyTouchFilter: Pointer 2 dropped");
-#endif
-                return true;
-            } else if (lastTouch.pointerCount == 2 && pointerCount == 1) {
-                // The event when we go from 2 -> 1 tends to be messed up too
-                currentTouch.pointerCount = 2;
-                currentTouch.pointers[0] = lastTouch.pointers[0];
-                currentTouch.pointers[1] = lastTouch.pointers[1];
-                jumpyTouchFilter.jumpyPointsDropped += 1;
-
-#if DEBUG_HACKS
-                for (int32_t i = 0; i < 2; i++) {
-                    LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
-                            currentTouch.pointers[i].x, currentTouch.pointers[i].y);
-                }
-#endif
-                return true;
-            }
-        }
-        // Reset jumpy points dropped on other transitions or if limit exceeded.
-        jumpyTouchFilter.jumpyPointsDropped = 0;
-
-#if DEBUG_HACKS
-        LOGD("JumpyTouchFilter: Transition - drop limit reset");
-#endif
-        return false;
-    }
-
-    // We have the same number of pointers as last time.
-    // A 'jumpy' point is one where the coordinate value for one axis
-    // has jumped to the other pointer's location. No need to do anything
-    // else if we only have one pointer.
-    if (pointerCount < 2) {
-        return false;
-    }
-
-    if (jumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
-        int jumpyEpsilon = parameters.yAxis.range / JUMPY_EPSILON_DIVISOR;
-
-        // We only replace the single worst jumpy point as characterized by pointer distance
-        // in a single axis.
-        int32_t badPointerIndex = -1;
-        int32_t badPointerReplacementIndex = -1;
-        int32_t badPointerDistance = INT_MIN; // distance to be corrected
-
-        for (uint32_t i = pointerCount; i-- > 0; ) {
-            int32_t x = currentTouch.pointers[i].x;
-            int32_t y = currentTouch.pointers[i].y;
-
-#if DEBUG_HACKS
-            LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
-#endif
-
-            // Check if a touch point is too close to another's coordinates
-            bool dropX = false, dropY = false;
-            for (uint32_t j = 0; j < pointerCount; j++) {
-                if (i == j) {
-                    continue;
-                }
-
-                if (abs(x - currentTouch.pointers[j].x) <= jumpyEpsilon) {
-                    dropX = true;
-                    break;
-                }
-
-                if (abs(y - currentTouch.pointers[j].y) <= jumpyEpsilon) {
-                    dropY = true;
-                    break;
-                }
-            }
-            if (! dropX && ! dropY) {
-                continue; // not jumpy
-            }
-
-            // Find a replacement candidate by comparing with older points on the
-            // complementary (non-jumpy) axis.
-            int32_t distance = INT_MIN; // distance to be corrected
-            int32_t replacementIndex = -1;
-
-            if (dropX) {
-                // X looks too close.  Find an older replacement point with a close Y.
-                int32_t smallestDeltaY = INT_MAX;
-                for (uint32_t j = 0; j < pointerCount; j++) {
-                    int32_t deltaY = abs(y - lastTouch.pointers[j].y);
-                    if (deltaY < smallestDeltaY) {
-                        smallestDeltaY = deltaY;
-                        replacementIndex = j;
-                    }
-                }
-                distance = abs(x - lastTouch.pointers[replacementIndex].x);
-            } else {
-                // Y looks too close.  Find an older replacement point with a close X.
-                int32_t smallestDeltaX = INT_MAX;
-                for (uint32_t j = 0; j < pointerCount; j++) {
-                    int32_t deltaX = abs(x - lastTouch.pointers[j].x);
-                    if (deltaX < smallestDeltaX) {
-                        smallestDeltaX = deltaX;
-                        replacementIndex = j;
-                    }
-                }
-                distance = abs(y - lastTouch.pointers[replacementIndex].y);
-            }
-
-            // If replacing this pointer would correct a worse error than the previous ones
-            // considered, then use this replacement instead.
-            if (distance > badPointerDistance) {
-                badPointerIndex = i;
-                badPointerReplacementIndex = replacementIndex;
-                badPointerDistance = distance;
-            }
-        }
-
-        // Correct the jumpy pointer if one was found.
-        if (badPointerIndex >= 0) {
-#if DEBUG_HACKS
-            LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
-                    badPointerIndex,
-                    lastTouch.pointers[badPointerReplacementIndex].x,
-                    lastTouch.pointers[badPointerReplacementIndex].y);
-#endif
-
-            currentTouch.pointers[badPointerIndex].x =
-                    lastTouch.pointers[badPointerReplacementIndex].x;
-            currentTouch.pointers[badPointerIndex].y =
-                    lastTouch.pointers[badPointerReplacementIndex].y;
-            jumpyTouchFilter.jumpyPointsDropped += 1;
-            return true;
-        }
-    }
-
-    jumpyTouchFilter.jumpyPointsDropped = 0;
-    return false;
-}
-
-/* Special hack for devices that have bad screen data: aggregate and
- * compute averages of the coordinate data, to reduce the amount of
- * jitter seen by applications. */
-void InputDevice::TouchScreenState::applyAveragingTouchFilter() {
-    for (uint32_t currentIndex = 0; currentIndex < currentTouch.pointerCount; currentIndex++) {
-        uint32_t id = currentTouch.pointers[currentIndex].id;
-        int32_t x = currentTouch.pointers[currentIndex].x;
-        int32_t y = currentTouch.pointers[currentIndex].y;
-        int32_t pressure = currentTouch.pointers[currentIndex].pressure;
-
-        if (lastTouch.idBits.hasBit(id)) {
-            // Pointer was down before and is still down now.
-            // Compute average over history trace.
-            uint32_t start = averagingTouchFilter.historyStart[id];
-            uint32_t end = averagingTouchFilter.historyEnd[id];
-
-            int64_t deltaX = x - averagingTouchFilter.historyData[end].pointers[id].x;
-            int64_t deltaY = y - averagingTouchFilter.historyData[end].pointers[id].y;
-            uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
-
-#if DEBUG_HACKS
-            LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
-                    id, distance);
-#endif
-
-            if (distance < AVERAGING_DISTANCE_LIMIT) {
-                // Increment end index in preparation for recording new historical data.
-                end += 1;
-                if (end > AVERAGING_HISTORY_SIZE) {
-                    end = 0;
-                }
-
-                // If the end index has looped back to the start index then we have filled
-                // the historical trace up to the desired size so we drop the historical
-                // data at the start of the trace.
-                if (end == start) {
-                    start += 1;
-                    if (start > AVERAGING_HISTORY_SIZE) {
-                        start = 0;
-                    }
-                }
-
-                // Add the raw data to the historical trace.
-                averagingTouchFilter.historyStart[id] = start;
-                averagingTouchFilter.historyEnd[id] = end;
-                averagingTouchFilter.historyData[end].pointers[id].x = x;
-                averagingTouchFilter.historyData[end].pointers[id].y = y;
-                averagingTouchFilter.historyData[end].pointers[id].pressure = pressure;
-
-                // Average over all historical positions in the trace by total pressure.
-                int32_t averagedX = 0;
-                int32_t averagedY = 0;
-                int32_t totalPressure = 0;
-                for (;;) {
-                    int32_t historicalX = averagingTouchFilter.historyData[start].pointers[id].x;
-                    int32_t historicalY = averagingTouchFilter.historyData[start].pointers[id].y;
-                    int32_t historicalPressure = averagingTouchFilter.historyData[start]
-                            .pointers[id].pressure;
-
-                    averagedX += historicalX * historicalPressure;
-                    averagedY += historicalY * historicalPressure;
-                    totalPressure += historicalPressure;
-
-                    if (start == end) {
-                        break;
-                    }
-
-                    start += 1;
-                    if (start > AVERAGING_HISTORY_SIZE) {
-                        start = 0;
-                    }
-                }
-
-                averagedX /= totalPressure;
-                averagedY /= totalPressure;
-
-#if DEBUG_HACKS
-                LOGD("AveragingTouchFilter: Pointer id %d - "
-                        "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
-                        averagedX, averagedY);
-#endif
-
-                currentTouch.pointers[currentIndex].x = averagedX;
-                currentTouch.pointers[currentIndex].y = averagedY;
-            } else {
-#if DEBUG_HACKS
-                LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
-#endif
-            }
-        } else {
-#if DEBUG_HACKS
-            LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
-#endif
-        }
-
-        // Reset pointer history.
-        averagingTouchFilter.historyStart[id] = 0;
-        averagingTouchFilter.historyEnd[id] = 0;
-        averagingTouchFilter.historyData[0].pointers[id].x = x;
-        averagingTouchFilter.historyData[0].pointers[id].y = y;
-        averagingTouchFilter.historyData[0].pointers[id].pressure = pressure;
-    }
-}
-
-bool InputDevice::TouchScreenState::isPointInsideDisplay(int32_t x, int32_t y) const {
-    if (! parameters.xAxis.valid || ! parameters.yAxis.valid) {
-        // Assume all points on a touch screen without valid axis parameters are
-        // inside the display.
-        return true;
-    }
-
-    return x >= parameters.xAxis.minValue
-        && x <= parameters.xAxis.maxValue
-        && y >= parameters.yAxis.minValue
-        && y <= parameters.yAxis.maxValue;
-}
-
-const InputDevice::VirtualKey* InputDevice::TouchScreenState::findVirtualKeyHit() const {
-    int32_t x = currentTouch.pointers[0].x;
-    int32_t y = currentTouch.pointers[0].y;
-    for (size_t i = 0; i < virtualKeys.size(); i++) {
-        const InputDevice::VirtualKey& virtualKey = virtualKeys[i];
-
-#if DEBUG_VIRTUAL_KEYS
-        LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
-                "left=%d, top=%d, right=%d, bottom=%d",
-                x, y,
-                virtualKey.keyCode, virtualKey.scanCode,
-                virtualKey.hitLeft, virtualKey.hitTop,
-                virtualKey.hitRight, virtualKey.hitBottom);
-#endif
-
-        if (virtualKey.isHit(x, y)) {
-            return & virtualKey;
-        }
-    }
-
-    return NULL;
-}
-
-
-// --- InputDevice::SingleTouchScreenState ---
-
-void InputDevice::SingleTouchScreenState::reset() {
-    accumulator.clear();
-    current.down = false;
-    current.x = 0;
-    current.y = 0;
-    current.pressure = 0;
-    current.size = 0;
-}
-
-
-// --- InputDevice::MultiTouchScreenState ---
-
-void InputDevice::MultiTouchScreenState::reset() {
-    accumulator.clear();
-}
-
-
 // --- InputReader ---
 
 InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -927,32 +253,30 @@
     bool down = rawEvent->value != 0;
     int32_t scanCode = rawEvent->scanCode;
 
-    if (device->isKeyboard() && (scanCode < BTN_FIRST || scanCode > BTN_LAST)) {
-        int32_t keyCode = rawEvent->keyCode;
-        onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
-    } else if (device->isSingleTouchScreen()) {
+    if (device->isSingleTouchScreen()) {
         switch (rawEvent->scanCode) {
         case BTN_TOUCH:
             device->singleTouchScreen.accumulator.fields |=
                     InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH;
             device->singleTouchScreen.accumulator.btnTouch = down;
-            break;
+            return;
         }
-    } else if (device->isTrackball()) {
+    }
+
+    if (device->isTrackball()) {
         switch (rawEvent->scanCode) {
         case BTN_MOUSE:
             device->trackball.accumulator.fields |=
                     InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
             device->trackball.accumulator.btnMouse = down;
-
-            // send the down immediately
-            // XXX this emulates the old behavior of KeyInputQueue, unclear whether it is
-            //     necessary or if we can wait until the next sync
-            onTrackballStateChanged(rawEvent->when, device);
-            device->trackball.accumulator.clear();
-            break;
+            return;
         }
     }
+
+    if (device->isKeyboard()) {
+        int32_t keyCode = rawEvent->keyCode;
+        onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
+    }
 }
 
 void InputReader::handleRelativeMotion(const RawEvent* rawEvent) {
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 25def3c..fc83e31 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -690,22 +690,3 @@
 }
 
 } // namespace android
-
-// --- AInputQueue ---
-
-using android::InputEvent;
-using android::InputChannel;
-using android::InputConsumer;
-using android::sp;
-using android::status_t;
-
-AInputQueue::AInputQueue(const sp<InputChannel>& channel) :
-        mConsumer(channel) {
-}
-
-AInputQueue::~AInputQueue() {
-}
-
-status_t AInputQueue::consume(InputEvent** event) {
-    return mConsumer.consume(&mInputEventFactory, event);
-}
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index 2d6b531..55504f2 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -76,7 +76,7 @@
     const int32_t nature = INPUT_EVENT_NATURE_KEY;
     const int32_t action = KEY_EVENT_ACTION_DOWN;
     const int32_t flags = KEY_EVENT_FLAG_FROM_SYSTEM;
-    const int32_t keyCode = KEYCODE_ENTER;
+    const int32_t keyCode = AKEYCODE_ENTER;
     const int32_t scanCode = 13;
     const int32_t metaState = META_ALT_LEFT_ON | META_ALT_ON;
     const int32_t repeatCount = 1;
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 2bb42ab..8bd5823 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -122,3 +122,13 @@
 include $(BUILD_STATIC_LIBRARY)
 endif
 endif
+
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
\ No newline at end of file
diff --git a/media/libeffects/EffectEqualizer.cpp b/media/libeffects/EffectEqualizer.cpp
index d19c6b9..af0c411 100644
--- a/media/libeffects/EffectEqualizer.cpp
+++ b/media/libeffects/EffectEqualizer.cpp
@@ -30,6 +30,12 @@
 // effect_interface_t interface implementation for equalizer effect
 extern "C" const struct effect_interface_s gEqualizerInterface;
 
+enum equalizer_state_e {
+    EQUALIZER_STATE_UNINITIALIZED,
+    EQUALIZER_STATE_INITIALIZED,
+    EQUALIZER_STATE_ACTIVE,
+};
+
 namespace android {
 namespace {
 
@@ -100,6 +106,7 @@
     effect_config_t config;
     FormatAdapter adapter;
     AudioEqualizer * pEqualizer;
+    uint32_t state;
 };
 
 //--- local function prototypes
@@ -151,6 +158,7 @@
 
     pContext->itfe = &gEqualizerInterface;
     pContext->pEqualizer = NULL;
+    pContext->state = EQUALIZER_STATE_UNINITIALIZED;
 
     ret = Equalizer_init(pContext);
     if (ret < 0) {
@@ -160,6 +168,7 @@
     }
 
     *pInterface = (effect_interface_t)pContext;
+    pContext->state = EQUALIZER_STATE_INITIALIZED;
 
     LOGV("EffectLibCreateEffect %p, size %d", pContext, AudioEqualizer::GetInstanceSize(kNumBands)+sizeof(EqualizerContext));
 
@@ -175,6 +184,7 @@
         return -EINVAL;
     }
 
+    pContext->state = EQUALIZER_STATE_UNINITIALIZED;
     pContext->pEqualizer->free();
     delete pContext;
 
@@ -528,6 +538,13 @@
         return -EINVAL;
     }
 
+    if (pContext->state == EQUALIZER_STATE_UNINITIALIZED) {
+        return -EINVAL;
+    }
+    if (pContext->state == EQUALIZER_STATE_INITIALIZED) {
+        return -ENODATA;
+    }
+
     pContext->adapter.process(inBuffer->raw, outBuffer->raw, outBuffer->frameCount);
 
     return 0;
@@ -539,7 +556,7 @@
     android::EqualizerContext * pContext = (android::EqualizerContext *) self;
     int retsize;
 
-    if (pContext == NULL) {
+    if (pContext == NULL || pContext->state == EQUALIZER_STATE_UNINITIALIZED) {
         return -EINVAL;
     }
 
@@ -594,10 +611,25 @@
                 p->data + p->psize);
         } break;
     case EFFECT_CMD_ENABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pContext->state != EQUALIZER_STATE_INITIALIZED) {
+            return -ENOSYS;
+        }
+        pContext->state = EQUALIZER_STATE_ACTIVE;
+        LOGV("EFFECT_CMD_ENABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
     case EFFECT_CMD_DISABLE:
         if (pReplyData == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
+        if (pContext->state != EQUALIZER_STATE_ACTIVE) {
+            return -ENOSYS;
+        }
+        pContext->state = EQUALIZER_STATE_INITIALIZED;
+        LOGV("EFFECT_CMD_DISABLE() OK");
         *(int *)pReplyData = 0;
         break;
     case EFFECT_CMD_SET_DEVICE:
diff --git a/media/libeffects/EffectReverb.c b/media/libeffects/EffectReverb.c
index 5c87f23..2ce7558 100644
--- a/media/libeffects/EffectReverb.c
+++ b/media/libeffects/EffectReverb.c
@@ -15,8 +15,7 @@
  */
 
 #define LOG_TAG "EffectReverb"
-//
-#define LOG_NDEBUG 0
+//#define LOG_NDEBUG 0
 #include <cutils/log.h>
 #include <stdlib.h>
 #include <string.h>
@@ -143,6 +142,8 @@
 
     module->itfe = &gReverbInterface;
 
+    module->context.mState = REVERB_STATE_UNINITIALIZED;
+
     if (memcmp(&desc->type, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
         preset = 1;
     }
@@ -158,6 +159,8 @@
 
     *pInterface = (effect_interface_t) module;
 
+    module->context.mState = REVERB_STATE_INITIALIZED;
+
     LOGV("EffectLibCreateEffect %p ,size %d", module, sizeof(reverb_module_t));
 
     return 0;
@@ -171,6 +174,8 @@
         return -EINVAL;
     }
 
+    pRvbModule->context.mState = REVERB_STATE_UNINITIALIZED;
+
     free(pRvbModule);
     return 0;
 }
@@ -195,6 +200,13 @@
 
     pReverb = (reverb_object_t*) &pRvbModule->context;
 
+    if (pReverb->mState == REVERB_STATE_UNINITIALIZED) {
+        return -EINVAL;
+    }
+    if (pReverb->mState == REVERB_STATE_INITIALIZED) {
+        return -ENODATA;
+    }
+
     //if bypassed or the preset forces the signal to be completely dry
     if (pReverb->m_bBypass != 0) {
         if (inBuffer->raw != outBuffer->raw) {
@@ -257,13 +269,15 @@
     return 0;
 }
 
+
 static int Reverb_Command(effect_interface_t self, int cmdCode, int cmdSize,
         void *pCmdData, int *replySize, void *pReplyData) {
     reverb_module_t *pRvbModule = (reverb_module_t *) self;
     reverb_object_t *pReverb;
     int retsize;
 
-    if (pRvbModule == NULL) {
+    if (pRvbModule == NULL ||
+            pRvbModule->context.mState == REVERB_STATE_UNINITIALIZED) {
         return -EINVAL;
     }
 
@@ -277,6 +291,9 @@
             return -EINVAL;
         }
         *(int *) pReplyData = Reverb_Init(pRvbModule, pReverb->m_Aux, pReverb->m_Preset);
+        if (*(int *) pReplyData == 0) {
+            pRvbModule->context.mState = REVERB_STATE_INITIALIZED;
+        }
         break;
     case EFFECT_CMD_CONFIGURE:
         if (pCmdData == NULL || cmdSize != sizeof(effect_config_t)
@@ -315,10 +332,25 @@
                 cmd->vsize, cmd->data + sizeof(int32_t));
         break;
     case EFFECT_CMD_ENABLE:
+        if (pReplyData == NULL || *replySize != sizeof(int)) {
+            return -EINVAL;
+        }
+        if (pReverb->mState != REVERB_STATE_INITIALIZED) {
+            return -ENOSYS;
+        }
+        pReverb->mState = REVERB_STATE_ACTIVE;
+        LOGV("EFFECT_CMD_ENABLE() OK");
+        *(int *)pReplyData = 0;
+        break;
     case EFFECT_CMD_DISABLE:
         if (pReplyData == NULL || *replySize != sizeof(int)) {
             return -EINVAL;
         }
+        if (pReverb->mState != REVERB_STATE_ACTIVE) {
+            return -ENOSYS;
+        }
+        pReverb->mState = REVERB_STATE_INITIALIZED;
+        LOGV("EFFECT_CMD_DISABLE() OK");
         *(int *)pReplyData = 0;
         break;
     case EFFECT_CMD_SET_DEVICE:
diff --git a/media/libeffects/EffectReverb.h b/media/libeffects/EffectReverb.h
index 5af316d..ee8e390 100644
--- a/media/libeffects/EffectReverb.h
+++ b/media/libeffects/EffectReverb.h
@@ -114,6 +114,12 @@
 #define AP1_GAIN_RANGE (int)(22936-6553)
 
 
+enum reverb_state_e {
+    REVERB_STATE_UNINITIALIZED,
+    REVERB_STATE_INITIALIZED,
+    REVERB_STATE_ACTIVE,
+};
+
 /* parameters for each allpass */
 typedef struct
 {
@@ -279,6 +285,7 @@
     uint16_t            m_Aux;                // if TRUE, is connected as auxiliary effect
     uint16_t            m_Preset;             // if TRUE, expose preset revert interface
 
+    uint32_t            mState;
 } reverb_object_t;
 
 
diff --git a/media/libeffects/EffectVisualizer.cpp b/media/libeffects/EffectVisualizer.cpp
index f27e296..bcda06e 100644
--- a/media/libeffects/EffectVisualizer.cpp
+++ b/media/libeffects/EffectVisualizer.cpp
@@ -231,7 +231,7 @@
         return -EINVAL;
     }
     if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
-        return -ENOSYS;
+        return -ENODATA;
     }
 
     if (inBuffer == NULL || inBuffer->raw == NULL ||
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 72061ad..cba5084 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -868,17 +868,19 @@
 
     sp<MetaData> meta = cameraSource->getFormat();
 
-    int32_t width, height, stride, sliceHeight;
+    int32_t width, height, stride, sliceHeight, colorFormat;
     CHECK(meta->findInt32(kKeyWidth, &width));
     CHECK(meta->findInt32(kKeyHeight, &height));
     CHECK(meta->findInt32(kKeyStride, &stride));
     CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));
+    CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));
 
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
     enc_meta->setInt32(kKeyIFramesInterval, mIFramesInterval);
     enc_meta->setInt32(kKeyStride, stride);
     enc_meta->setInt32(kKeySliceHeight, sliceHeight);
+    enc_meta->setInt32(kKeyColorFormat, colorFormat);
     if (mVideoEncoderProfile != -1) {
         enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 60d0233..49cf647 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -66,6 +66,7 @@
         libstagefright_amrwbdec \
         libstagefright_amrwbenc \
         libstagefright_avcdec \
+        libstagefright_avcenc \
         libstagefright_m4vh263dec \
         libstagefright_mp3dec \
         libstagefright_vorbisdec \
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index efaab5b..077e123 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -25,6 +25,7 @@
 #include "include/AMRWBDecoder.h"
 #include "include/AMRWBEncoder.h"
 #include "include/AVCDecoder.h"
+#include "include/AVCEncoder.h"
 #include "include/M4vH263Decoder.h"
 #include "include/MP3Decoder.h"
 #include "include/VorbisDecoder.h"
@@ -81,6 +82,7 @@
 FACTORY_CREATE_ENCODER(AMRNBEncoder)
 FACTORY_CREATE_ENCODER(AMRWBEncoder)
 FACTORY_CREATE_ENCODER(AACEncoder)
+FACTORY_CREATE_ENCODER(AVCEncoder)
 
 static sp<MediaSource> InstantiateSoftwareEncoder(
         const char *name, const sp<MediaSource> &source,
@@ -94,6 +96,7 @@
         FACTORY_REF(AMRNBEncoder)
         FACTORY_REF(AMRWBEncoder)
         FACTORY_REF(AACEncoder)
+        FACTORY_REF(AVCEncoder)
     };
     for (size_t i = 0;
          i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
@@ -186,6 +189,7 @@
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "AVCEncoder" },
 //    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
 
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
new file mode 100644
index 0000000..d5eb156
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -0,0 +1,492 @@
+/*
+ * 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 "AVCEncoder"
+#include <utils/Log.h>
+
+#include "AVCEncoder.h"
+
+#include "avcenc_api.h"
+#include "avcenc_int.h"
+#include "OMX_Video.h"
+
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+inline static void ConvertYUV420SemiPlanarToYUV420Planar(
+        uint8_t *inyuv, uint8_t* outyuv,
+        int32_t width, int32_t height) {
+
+    int32_t outYsize = width * height;
+    uint32_t *outy =  (uint32_t *) outyuv;
+    uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
+    uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
+
+    /* Y copying */
+    memcpy(outy, inyuv, outYsize);
+
+    /* U & V copying */
+    uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
+    for (int32_t i = height >> 1; i > 0; --i) {
+        for (int32_t j = width >> 2; j > 0; --j) {
+            uint32_t temp = *inyuv_4++;
+            uint32_t tempU = temp & 0xFF;
+            tempU = tempU | ((temp >> 8) & 0xFF00);
+
+            uint32_t tempV = (temp >> 8) & 0xFF;
+            tempV = tempV | ((temp >> 16) & 0xFF00);
+
+            // Flip U and V
+            *outcb++ = tempV;
+            *outcr++ = tempU;
+        }
+    }
+}
+
+static int32_t MallocWrapper(
+        void *userData, int32_t size, int32_t attrs) {
+    return reinterpret_cast<int32_t>(malloc(size));
+}
+
+static void FreeWrapper(void *userData, int32_t ptr) {
+    free(reinterpret_cast<void *>(ptr));
+}
+
+static int32_t DpbAllocWrapper(void *userData,
+        unsigned int sizeInMbs, unsigned int numBuffers) {
+    AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
+    CHECK(encoder != NULL);
+    return encoder->allocOutputBuffers(sizeInMbs, numBuffers);
+}
+
+static int32_t BindFrameWrapper(
+        void *userData, int32_t index, uint8_t **yuv) {
+    AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
+    CHECK(encoder != NULL);
+    return encoder->bindOutputBuffer(index, yuv);
+}
+
+static void UnbindFrameWrapper(void *userData, int32_t index) {
+    AVCEncoder *encoder = static_cast<AVCEncoder *>(userData);
+    CHECK(encoder != NULL);
+    return encoder->unbindOutputBuffer(index);
+}
+
+AVCEncoder::AVCEncoder(
+        const sp<MediaSource>& source,
+        const sp<MetaData>& meta)
+    : mSource(source),
+      mMeta(meta),
+      mNumInputFrames(-1),
+      mStarted(false),
+      mInputBuffer(NULL),
+      mInputFrameData(NULL),
+      mGroup(NULL) {
+
+    LOGV("Construct software AVCEncoder");
+
+    mHandle = new tagAVCHandle;
+    memset(mHandle, 0, sizeof(tagAVCHandle));
+    mHandle->AVCObject = NULL;
+    mHandle->userData = this;
+    mHandle->CBAVC_DPBAlloc = DpbAllocWrapper;
+    mHandle->CBAVC_FrameBind = BindFrameWrapper;
+    mHandle->CBAVC_FrameUnbind = UnbindFrameWrapper;
+    mHandle->CBAVC_Malloc = MallocWrapper;
+    mHandle->CBAVC_Free = FreeWrapper;
+
+    mInitCheck = initCheck(meta);
+}
+
+AVCEncoder::~AVCEncoder() {
+    LOGV("Destruct software AVCEncoder");
+    if (mStarted) {
+        stop();
+    }
+
+    delete mEncParams;
+    delete mHandle;
+}
+
+status_t AVCEncoder::initCheck(const sp<MetaData>& meta) {
+    LOGV("initCheck");
+    CHECK(meta->findInt32(kKeyWidth, &mVideoWidth));
+    CHECK(meta->findInt32(kKeyHeight, &mVideoHeight));
+    CHECK(meta->findInt32(kKeySampleRate, &mVideoFrameRate));
+    CHECK(meta->findInt32(kKeyBitRate, &mVideoBitRate));
+
+    // XXX: Add more color format support
+    CHECK(meta->findInt32(kKeyColorFormat, &mVideoColorFormat));
+    if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
+        if (mVideoColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) {
+            LOGE("Color format %d is not supported", mVideoColorFormat);
+            return BAD_VALUE;
+        }
+        // Allocate spare buffer only when color conversion is needed.
+        // Assume the color format is OMX_COLOR_FormatYUV420SemiPlanar.
+        mInputFrameData =
+            (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1);
+        CHECK(mInputFrameData);
+    }
+
+    // XXX: Remove this restriction
+    if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) {
+        LOGE("Video frame size %dx%d must be a multiple of 16",
+            mVideoWidth, mVideoHeight);
+        return BAD_VALUE;
+    }
+
+    mEncParams = new tagAVCEncParam;
+    memset(mEncParams, 0, sizeof(mEncParams));
+    mEncParams->width = mVideoWidth;
+    mEncParams->height = mVideoHeight;
+    mEncParams->frame_rate = 1000 * mVideoFrameRate;  // In frames/ms!
+    mEncParams->rate_control = AVC_ON;
+    mEncParams->bitrate = mVideoBitRate;
+    mEncParams->initQP = 0;
+    mEncParams->init_CBP_removal_delay = 1600;
+    mEncParams->CPB_size = (uint32_t) (mVideoBitRate >> 1);
+
+    mEncParams->intramb_refresh = 0;
+    mEncParams->auto_scd = AVC_ON;
+    mEncParams->out_of_band_param_set = AVC_ON;
+    mEncParams->poc_type = 2;
+    mEncParams->log2_max_poc_lsb_minus_4 = 12;
+    mEncParams->delta_poc_zero_flag = 0;
+    mEncParams->offset_poc_non_ref = 0;
+    mEncParams->offset_top_bottom = 0;
+    mEncParams->num_ref_in_cycle = 0;
+    mEncParams->offset_poc_ref = NULL;
+
+    mEncParams->num_ref_frame = 1;
+    mEncParams->num_slice_group = 1;
+    mEncParams->fmo_type = 0;
+
+    mEncParams->db_filter = AVC_ON;
+    mEncParams->disable_db_idc = 0;
+
+    mEncParams->alpha_offset = 0;
+    mEncParams->beta_offset = 0;
+    mEncParams->constrained_intra_pred = AVC_OFF;
+
+    mEncParams->data_par = AVC_OFF;
+    mEncParams->fullsearch = AVC_OFF;
+    mEncParams->search_range = 16;
+    mEncParams->sub_pel = AVC_OFF;
+    mEncParams->submb_pred = AVC_OFF;
+    mEncParams->rdopt_mode = AVC_OFF;
+    mEncParams->bidir_pred = AVC_OFF;
+    int32_t nMacroBlocks = ((((mVideoWidth + 15) >> 4) << 4) *
+            (((mVideoHeight + 15) >> 4) << 4)) >> 8;
+    uint32_t *sliceGroup = (uint32_t *) malloc(sizeof(uint32_t) * nMacroBlocks);
+    for (int ii = 0, idx = 0; ii < nMacroBlocks; ++ii) {
+        sliceGroup[ii] = idx++;
+        if (idx >= mEncParams->num_slice_group) {
+            idx = 0;
+        }
+    }
+    mEncParams->slice_group = sliceGroup;
+
+    mEncParams->use_overrun_buffer = AVC_OFF;
+
+    // Set IDR frame refresh interval
+    int32_t iFramesIntervalSec;
+    CHECK(meta->findInt32(kKeyIFramesInterval, &iFramesIntervalSec));
+    if (iFramesIntervalSec < 0) {
+        mEncParams->idr_period = -1;
+    } else if (iFramesIntervalSec == 0) {
+        mEncParams->idr_period = 1;  // All I frames
+    } else {
+        mEncParams->idr_period =
+            (iFramesIntervalSec * mVideoFrameRate);
+    }
+    LOGV("idr_period: %d, I-frames interval: %d seconds, and frame rate: %d",
+        mEncParams->idr_period, iFramesIntervalSec, mVideoFrameRate);
+
+    // Set profile and level
+    // If profile and level setting is not correct, failure
+    // is reported when the encoder is initialized.
+    mEncParams->profile = AVC_BASELINE;
+    mEncParams->level = AVC_LEVEL3_2;
+    int32_t profile, level;
+    if (meta->findInt32(kKeyVideoProfile, &profile)) {
+        mEncParams->profile = (AVCProfile) profile;
+    }
+    if (meta->findInt32(kKeyVideoLevel, &level)) {
+        mEncParams->level = (AVCLevel) level;
+    }
+
+
+    mFormat = new MetaData;
+    mFormat->setInt32(kKeyWidth, mVideoWidth);
+    mFormat->setInt32(kKeyHeight, mVideoHeight);
+    mFormat->setInt32(kKeyBitRate, mVideoBitRate);
+    mFormat->setInt32(kKeySampleRate, mVideoFrameRate);
+    mFormat->setInt32(kKeyColorFormat, mVideoColorFormat);
+    mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+    mFormat->setCString(kKeyDecoderComponent, "AVCEncoder");
+    return OK;
+}
+
+status_t AVCEncoder::start(MetaData *params) {
+    LOGV("start");
+    if (mInitCheck != OK) {
+        return mInitCheck;
+    }
+
+    if (mStarted) {
+        LOGW("Call start() when encoder already started");
+        return OK;
+    }
+
+    AVCEnc_Status err;
+    err = PVAVCEncInitialize(mHandle, mEncParams, NULL, NULL);
+    if (err != AVCENC_SUCCESS) {
+        LOGE("Failed to initialize the encoder: %d", err);
+        return UNKNOWN_ERROR;
+    }
+
+    mGroup = new MediaBufferGroup();
+    int32_t maxSize;
+    if (AVCENC_SUCCESS !=
+        PVAVCEncGetMaxOutputBufferSize(mHandle, &maxSize)) {
+        maxSize = 31584;  // Magic #
+    }
+    mGroup->add_buffer(new MediaBuffer(maxSize));
+
+    mSource->start(params);
+    mNumInputFrames = -2;  // 1st two buffers contain SPS and PPS
+    mStarted = true;
+    mSpsPpsHeaderReceived = false;
+    mReadyForNextFrame = true;
+    mIsIDRFrame = 0;
+
+    return OK;
+}
+
+status_t AVCEncoder::stop() {
+    LOGV("stop");
+    if (!mStarted) {
+        LOGW("Call stop() when encoder has not started");
+        return OK;
+    }
+
+    if (mInputBuffer) {
+        mInputBuffer->release();
+        mInputBuffer = NULL;
+    }
+
+    if (mGroup) {
+        delete mGroup;
+        mGroup = NULL;
+    }
+
+    if (mInputFrameData) {
+        delete mInputFrameData;
+        mInputFrameData = NULL;
+    }
+
+    PVAVCCleanUpEncoder(mHandle);
+    mSource->stop();
+    releaseOutputBuffers();
+    mStarted = false;
+
+    return OK;
+}
+
+void AVCEncoder::releaseOutputBuffers() {
+    LOGV("releaseOutputBuffers");
+    for (size_t i = 0; i < mOutputBuffers.size(); ++i) {
+        MediaBuffer *buffer = mOutputBuffers.editItemAt(i);
+        buffer->setObserver(NULL);
+        buffer->release();
+    }
+    mOutputBuffers.clear();
+}
+
+sp<MetaData> AVCEncoder::getFormat() {
+    LOGV("getFormat");
+    return mFormat;
+}
+
+status_t AVCEncoder::read(
+        MediaBuffer **out, const ReadOptions *options) {
+
+    CHECK(!options);
+    *out = NULL;
+
+    MediaBuffer *outputBuffer;
+    CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+    uint8_t *outPtr = (uint8_t *) outputBuffer->data();
+    uint32_t dataLength = outputBuffer->size();
+
+    int32_t type;
+    AVCEnc_Status encoderStatus = AVCENC_SUCCESS;
+
+    // Return SPS and PPS for the first two buffers
+    if (!mSpsPpsHeaderReceived) {
+        encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
+        if (encoderStatus == AVCENC_WRONG_STATE) {
+            mSpsPpsHeaderReceived = true;
+            CHECK_EQ(0, mNumInputFrames);  // 1st video frame is 0
+        } else {
+            switch (type) {
+                case AVC_NALTYPE_SPS:
+                case AVC_NALTYPE_PPS:
+                    LOGV("%s received",
+                            (type == AVC_NALTYPE_SPS)? "SPS": "PPS");
+                    ++mNumInputFrames;
+                    outputBuffer->set_range(0, dataLength);
+                    *out = outputBuffer;
+                    return OK;
+                default:
+                    LOGE("Nal type (%d) other than SPS/PPS is unexpected", type);
+                    return UNKNOWN_ERROR;
+            }
+        }
+    }
+
+    // Get next input video frame
+    if (mReadyForNextFrame) {
+        if (mInputBuffer) {
+            mInputBuffer->release();
+            mInputBuffer = NULL;
+        }
+        status_t err = mSource->read(&mInputBuffer, options);
+        if (err != OK) {
+            LOGE("Failed to read input video frame: %d", err);
+            outputBuffer->release();
+            return err;
+        }
+        int64_t timeUs;
+        CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+        outputBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+
+        AVCFrameIO videoInput;
+        memset(&videoInput, 0, sizeof(videoInput));
+        videoInput.height = ((mVideoHeight  + 15) >> 4) << 4;
+        videoInput.pitch = ((mVideoWidth + 15) >> 4) << 4;
+        videoInput.coding_timestamp = (timeUs + 500) / 1000;  // in ms
+        uint8_t *inputData = (uint8_t *) mInputBuffer->data();
+
+        if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) {
+            CHECK(mInputFrameData);
+            CHECK(mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar);
+            ConvertYUV420SemiPlanarToYUV420Planar(
+                inputData, mInputFrameData, mVideoWidth, mVideoHeight);
+            inputData = mInputFrameData;
+        }
+        CHECK(inputData != NULL);
+        videoInput.YCbCr[0] = inputData;
+        videoInput.YCbCr[1] = videoInput.YCbCr[0] + videoInput.height * videoInput.pitch;
+        videoInput.YCbCr[2] = videoInput.YCbCr[1] +
+            ((videoInput.height * videoInput.pitch) >> 2);
+        videoInput.disp_order = mNumInputFrames;
+
+        encoderStatus = PVAVCEncSetInput(mHandle, &videoInput);
+        if (encoderStatus == AVCENC_SUCCESS ||
+            encoderStatus == AVCENC_NEW_IDR) {
+            mReadyForNextFrame = false;
+            ++mNumInputFrames;
+            if (encoderStatus == AVCENC_NEW_IDR) {
+                mIsIDRFrame = 1;
+            }
+        } else {
+            if (encoderStatus < AVCENC_SUCCESS) {
+                outputBuffer->release();
+                return UNKNOWN_ERROR;
+            } else {
+                outputBuffer->set_range(0, 0);
+                *out = outputBuffer;
+                return OK;
+            }
+        }
+    }
+
+    // Encode an input video frame
+    CHECK(encoderStatus == AVCENC_SUCCESS ||
+          encoderStatus == AVCENC_NEW_IDR);
+    dataLength = outputBuffer->size();  // Reset the output buffer length
+    encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
+    if (encoderStatus == AVCENC_SUCCESS) {
+        outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
+        CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+    } else if (encoderStatus == AVCENC_PICTURE_READY) {
+        CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+        if (mIsIDRFrame) {
+            outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
+            mIsIDRFrame = 0;
+            LOGV("Output an IDR frame");
+        }
+        mReadyForNextFrame = true;
+        AVCFrameIO recon;
+        if (PVAVCEncGetRecon(mHandle, &recon) == AVCENC_SUCCESS) {
+            PVAVCEncReleaseRecon(mHandle, &recon);
+        }
+    } else {
+        dataLength = 0;
+        mReadyForNextFrame = true;
+    }
+    if (encoderStatus < AVCENC_SUCCESS) {
+        outputBuffer->release();
+        return UNKNOWN_ERROR;
+    }
+
+    outputBuffer->set_range(0, dataLength);
+    *out = outputBuffer;
+    return OK;
+}
+
+int32_t AVCEncoder::allocOutputBuffers(
+        unsigned int sizeInMbs, unsigned int numBuffers) {
+    CHECK(mOutputBuffers.isEmpty());
+    size_t frameSize = (sizeInMbs << 7) * 3;
+    for (unsigned int i = 0; i <  numBuffers; ++i) {
+        MediaBuffer *buffer = new MediaBuffer(frameSize);
+        buffer->setObserver(this);
+        mOutputBuffers.push(buffer);
+    }
+
+    return 1;
+}
+
+void AVCEncoder::unbindOutputBuffer(int32_t index) {
+    CHECK(index >= 0);
+}
+
+int32_t AVCEncoder::bindOutputBuffer(int32_t index, uint8_t **yuv) {
+    CHECK(index >= 0);
+    CHECK(index < (int32_t) mOutputBuffers.size());
+    int64_t timeUs;
+    CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+    mOutputBuffers[index]->meta_data()->setInt64(kKeyTime, timeUs);
+
+    *yuv = (uint8_t *) mOutputBuffers[index]->data();
+
+    return 1;
+}
+
+void AVCEncoder::signalBufferReturned(MediaBuffer *buffer) {
+}
+
+}  // namespace android
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
new file mode 100644
index 0000000..100f239
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    AVCEncoder.cpp \
+    src/avcenc_api.cpp \
+    src/bitstream_io.cpp \
+    src/block.cpp \
+    src/findhalfpel.cpp \
+    src/header.cpp \
+    src/init.cpp \
+    src/intra_est.cpp \
+    src/motion_comp.cpp \
+    src/motion_est.cpp \
+    src/rate_control.cpp \
+    src/residual.cpp \
+    src/sad.cpp \
+    src/sad_halfpel.cpp \
+    src/slice.cpp \
+    src/vlc_encode.cpp
+
+
+LOCAL_MODULE := libstagefright_avcenc
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/src \
+    $(LOCAL_PATH)/../common/include \
+    $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
+    $(TOP)/frameworks/base/media/libstagefright/include
+
+LOCAL_CFLAGS := \
+    -D__arm__ \
+    -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/codecs/avc/enc/src/avcenc_api.cpp b/media/libstagefright/codecs/avc/enc/src/avcenc_api.cpp
new file mode 100644
index 0000000..d39885d
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/avcenc_api.cpp
@@ -0,0 +1,744 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_api.h"
+#include "avcenc_lib.h"
+
+/* ======================================================================== */
+/*  Function : PVAVCGetNALType()                                            */
+/*  Date     : 11/4/2003                                                    */
+/*  Purpose  : Sniff NAL type from the bitstream                            */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS if succeed, AVCENC_FAIL if fail.              */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetNALType(unsigned char *bitstream, int size,
+        int *nal_type, int *nal_ref_idc)
+{
+    int forbidden_zero_bit;
+    if (size > 0)
+    {
+        forbidden_zero_bit = bitstream[0] >> 7;
+        if (forbidden_zero_bit != 0)
+            return AVCENC_FAIL;
+        *nal_ref_idc = (bitstream[0] & 0x60) >> 5;
+        *nal_type = bitstream[0] & 0x1F;
+        return AVCENC_SUCCESS;
+    }
+
+    return AVCENC_FAIL;
+}
+
+
+/* ======================================================================== */
+/*  Function : PVAVCEncInitialize()                                         */
+/*  Date     : 3/18/2004                                                    */
+/*  Purpose  : Initialize the encoder library, allocate memory and verify   */
+/*              the profile/level support/settings.                         */
+/*  In/out   : Encoding parameters.                                         */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncInitialize(AVCHandle *avcHandle, AVCEncParams *encParam,
+        void* extSPS, void* extPPS)
+{
+    AVCEnc_Status status;
+    AVCEncObject *encvid;
+    AVCCommonObj *video;
+    uint32 *userData = (uint32*) avcHandle->userData;
+    int framesize;
+
+    if (avcHandle->AVCObject != NULL)
+    {
+        return AVCENC_ALREADY_INITIALIZED; /* It's already initialized, need to cleanup first */
+    }
+
+    /* not initialized */
+
+    /* allocate videoObject */
+    avcHandle->AVCObject = (void*)avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncObject), DEFAULT_ATTR);
+    if (avcHandle->AVCObject == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    encvid = (AVCEncObject*) avcHandle->AVCObject;
+    memset(encvid, 0, sizeof(AVCEncObject)); /* reset everything */
+
+    encvid->enc_state = AVCEnc_Initializing;
+
+    encvid->avcHandle = avcHandle;
+
+    encvid->common = (AVCCommonObj*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCCommonObj), DEFAULT_ATTR);
+    if (encvid->common == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    video = encvid->common;
+    memset(video, 0, sizeof(AVCCommonObj));
+
+    /* allocate bitstream structure */
+    encvid->bitstream = (AVCEncBitstream*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncBitstream), DEFAULT_ATTR);
+    if (encvid->bitstream == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    encvid->bitstream->encvid = encvid; /* to point back for reallocation */
+
+    /* allocate sequence parameter set structure */
+    video->currSeqParams = (AVCSeqParamSet*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCSeqParamSet), DEFAULT_ATTR);
+    if (video->currSeqParams == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(video->currSeqParams, 0, sizeof(AVCSeqParamSet));
+
+    /* allocate picture parameter set structure */
+    video->currPicParams = (AVCPicParamSet*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCPicParamSet), DEFAULT_ATTR);
+    if (video->currPicParams == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(video->currPicParams, 0, sizeof(AVCPicParamSet));
+
+    /* allocate slice header structure */
+    video->sliceHdr = (AVCSliceHeader*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCSliceHeader), DEFAULT_ATTR);
+    if (video->sliceHdr == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(video->sliceHdr, 0, sizeof(AVCSliceHeader));
+
+    /* allocate encoded picture buffer structure*/
+    video->decPicBuf = (AVCDecPicBuffer*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCDecPicBuffer), DEFAULT_ATTR);
+    if (video->decPicBuf == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(video->decPicBuf, 0, sizeof(AVCDecPicBuffer));
+
+    /* allocate rate control structure */
+    encvid->rateCtrl = (AVCRateControl*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCRateControl), DEFAULT_ATTR);
+    if (encvid->rateCtrl == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(encvid->rateCtrl, 0, sizeof(AVCRateControl));
+
+    /* reset frame list, not really needed */
+    video->currPic = NULL;
+    video->currFS = NULL;
+    encvid->currInput = NULL;
+    video->prevRefPic = NULL;
+
+    /* now read encParams, and allocate dimension-dependent variables */
+    /* such as mblock */
+    status = SetEncodeParam(avcHandle, encParam, extSPS, extPPS); /* initialized variables to be used in SPS*/
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if (encParam->use_overrun_buffer == AVC_ON)
+    {
+        /* allocate overrun buffer */
+        encvid->oBSize = encvid->rateCtrl->cpbSize;
+        if (encvid->oBSize > DEFAULT_OVERRUN_BUFFER_SIZE)
+        {
+            encvid->oBSize = DEFAULT_OVERRUN_BUFFER_SIZE;
+        }
+        encvid->overrunBuffer = (uint8*) avcHandle->CBAVC_Malloc(userData, encvid->oBSize, DEFAULT_ATTR);
+        if (encvid->overrunBuffer == NULL)
+        {
+            return AVCENC_MEMORY_FAIL;
+        }
+    }
+    else
+    {
+        encvid->oBSize = 0;
+        encvid->overrunBuffer = NULL;
+    }
+
+    /* allocate frame size dependent structures */
+    framesize = video->FrameHeightInMbs * video->PicWidthInMbs;
+
+    video->mblock = (AVCMacroblock*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMacroblock) * framesize, DEFAULT_ATTR);
+    if (video->mblock == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    video->MbToSliceGroupMap = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits * 2, DEFAULT_ATTR);
+    if (video->MbToSliceGroupMap == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    encvid->mot16x16 = (AVCMV*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCMV) * framesize, DEFAULT_ATTR);
+    if (encvid->mot16x16 == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    memset(encvid->mot16x16, 0, sizeof(AVCMV)*framesize);
+
+    encvid->intraSearch = (uint8*) avcHandle->CBAVC_Malloc(userData, sizeof(uint8) * framesize, DEFAULT_ATTR);
+    if (encvid->intraSearch == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    encvid->min_cost = (int*) avcHandle->CBAVC_Malloc(userData, sizeof(int) * framesize, DEFAULT_ATTR);
+    if (encvid->min_cost == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    /* initialize motion search related memory */
+    if (AVCENC_SUCCESS != InitMotionSearchModule(avcHandle))
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    if (AVCENC_SUCCESS != InitRateControlModule(avcHandle))
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    /* intialize function pointers */
+    encvid->functionPointer = (AVCEncFuncPtr*) avcHandle->CBAVC_Malloc(userData, sizeof(AVCEncFuncPtr), DEFAULT_ATTR);
+    if (encvid->functionPointer == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+    encvid->functionPointer->SAD_Macroblock = &AVCSAD_Macroblock_C;
+    encvid->functionPointer->SAD_MB_HalfPel[0] = NULL;
+    encvid->functionPointer->SAD_MB_HalfPel[1] = &AVCSAD_MB_HalfPel_Cxh;
+    encvid->functionPointer->SAD_MB_HalfPel[2] = &AVCSAD_MB_HalfPel_Cyh;
+    encvid->functionPointer->SAD_MB_HalfPel[3] = &AVCSAD_MB_HalfPel_Cxhyh;
+
+    /* initialize timing control */
+    encvid->modTimeRef = 0;     /* ALWAYS ASSUME THAT TIMESTAMP START FROM 0 !!!*/
+    video->prevFrameNum = 0;
+    encvid->prevCodedFrameNum = 0;
+    encvid->dispOrdPOCRef = 0;
+
+    if (encvid->outOfBandParamSet == TRUE)
+    {
+        encvid->enc_state = AVCEnc_Encoding_SPS;
+    }
+    else
+    {
+        encvid->enc_state = AVCEnc_Analyzing_Frame;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCEncGetMaxOutputSize()                                   */
+/*  Date     : 11/29/2008                                                   */
+/*  Purpose  : Return max output buffer size that apps should allocate for  */
+/*              output buffer.                                              */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :   size                                                       */
+/* ======================================================================== */
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetMaxOutputBufferSize(AVCHandle *avcHandle, int* size)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+
+    if (encvid == NULL)
+    {
+        return AVCENC_UNINITIALIZED;
+    }
+
+    *size = encvid->rateCtrl->cpbSize;
+
+    return AVCENC_SUCCESS;
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCEncSetInput()                                           */
+/*  Date     : 4/18/2004                                                    */
+/*  Purpose  : To feed an unencoded original frame to the encoder library.  */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncSetInput(AVCHandle *avcHandle, AVCFrameIO *input)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+
+    AVCEnc_Status status;
+    uint frameNum;
+
+    if (encvid == NULL)
+    {
+        return AVCENC_UNINITIALIZED;
+    }
+
+    if (encvid->enc_state == AVCEnc_WaitingForBuffer)
+    {
+        goto RECALL_INITFRAME;
+    }
+    else if (encvid->enc_state != AVCEnc_Analyzing_Frame)
+    {
+        return AVCENC_FAIL;
+    }
+
+    if (input->pitch > 0xFFFF)
+    {
+        return AVCENC_NOT_SUPPORTED; // we use 2-bytes for pitch
+    }
+
+    /***********************************/
+
+    /* Let's rate control decide whether to encode this frame or not */
+    /* Also set video->nal_unit_type, sliceHdr->slice_type, video->slice_type */
+    if (AVCENC_SUCCESS != RCDetermineFrameNum(encvid, rateCtrl, input->coding_timestamp, &frameNum))
+    {
+        return AVCENC_SKIPPED_PICTURE; /* not time to encode, thus skipping */
+    }
+
+    /* we may not need this line */
+    //nextFrmModTime = (uint32)((((frameNum+1)*1000)/rateCtrl->frame_rate) + modTimeRef); /* rec. time */
+    //encvid->nextModTime = nextFrmModTime - (encvid->frameInterval>>1) - 1; /* between current and next frame */
+
+    encvid->currInput = input;
+    encvid->currInput->coding_order = frameNum;
+
+RECALL_INITFRAME:
+    /* initialize and analyze the frame */
+    status = InitFrame(encvid);
+
+    if (status == AVCENC_SUCCESS)
+    {
+        encvid->enc_state = AVCEnc_Encoding_Frame;
+    }
+    else if (status == AVCENC_NEW_IDR)
+    {
+        if (encvid->outOfBandParamSet == TRUE)
+        {
+            encvid->enc_state = AVCEnc_Encoding_Frame;
+        }
+        else // assuming that in-band paramset keeps sending new SPS and PPS.
+        {
+            encvid->enc_state = AVCEnc_Encoding_SPS;
+            //video->currSeqParams->seq_parameter_set_id++;
+            //if(video->currSeqParams->seq_parameter_set_id > 31) // range check
+            {
+                video->currSeqParams->seq_parameter_set_id = 0;  // reset
+            }
+        }
+
+        video->sliceHdr->idr_pic_id++;
+        if (video->sliceHdr->idr_pic_id > 65535) // range check
+        {
+            video->sliceHdr->idr_pic_id = 0;  // reset
+        }
+    }
+    /* the following logics need to be revisited */
+    else if (status == AVCENC_PICTURE_READY) // no buffers returned back to the encoder
+    {
+        encvid->enc_state = AVCEnc_WaitingForBuffer; // Input accepted but can't continue
+        // need to free up some memory before proceeding with Encode
+    }
+
+    return status; // return status, including the AVCENC_FAIL case and all 3 above.
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCEncodeNAL()                                             */
+/*  Date     : 4/29/2004                                                    */
+/*  Purpose  : To encode one NAL/slice.                                     */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncodeNAL(AVCHandle *avcHandle, unsigned char *buffer, unsigned int *buf_nal_size, int *nal_type)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCEncBitstream *bitstream = encvid->bitstream;
+    AVCEnc_Status status;
+
+    if (encvid == NULL)
+    {
+        return AVCENC_UNINITIALIZED;
+    }
+
+    switch (encvid->enc_state)
+    {
+        case AVCEnc_Initializing:
+            return AVCENC_UNINITIALIZED;
+        case AVCEnc_Encoding_SPS:
+            /* initialized the structure */
+            BitstreamEncInit(bitstream, buffer, *buf_nal_size, NULL, 0);
+            BitstreamWriteBits(bitstream, 8, (1 << 5) | AVC_NALTYPE_SPS);
+
+            /* encode SPS */
+            status = EncodeSPS(encvid, bitstream);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+
+            /* closing the NAL with trailing bits */
+            status = BitstreamTrailingBits(bitstream, buf_nal_size);
+            if (status == AVCENC_SUCCESS)
+            {
+                encvid->enc_state = AVCEnc_Encoding_PPS;
+                video->currPicParams->seq_parameter_set_id = video->currSeqParams->seq_parameter_set_id;
+                video->currPicParams->pic_parameter_set_id++;
+                *nal_type = AVC_NALTYPE_SPS;
+                *buf_nal_size = bitstream->write_pos;
+            }
+            break;
+        case AVCEnc_Encoding_PPS:
+            /* initialized the structure */
+            BitstreamEncInit(bitstream, buffer, *buf_nal_size, NULL, 0);
+            BitstreamWriteBits(bitstream, 8, (1 << 5) | AVC_NALTYPE_PPS);
+
+            /* encode PPS */
+            status = EncodePPS(encvid, bitstream);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+
+            /* closing the NAL with trailing bits */
+            status = BitstreamTrailingBits(bitstream, buf_nal_size);
+            if (status == AVCENC_SUCCESS)
+            {
+                if (encvid->outOfBandParamSet == TRUE) // already extract PPS, SPS
+                {
+                    encvid->enc_state = AVCEnc_Analyzing_Frame;
+                }
+                else    // SetInput has been called before SPS and PPS.
+                {
+                    encvid->enc_state = AVCEnc_Encoding_Frame;
+                }
+
+                *nal_type = AVC_NALTYPE_PPS;
+                *buf_nal_size = bitstream->write_pos;
+            }
+            break;
+
+        case AVCEnc_Encoding_Frame:
+            /* initialized the structure */
+            BitstreamEncInit(bitstream, buffer, *buf_nal_size, encvid->overrunBuffer, encvid->oBSize);
+            BitstreamWriteBits(bitstream, 8, (video->nal_ref_idc << 5) | (video->nal_unit_type));
+
+            /* Re-order the reference list according to the ref_pic_list_reordering() */
+            /* We don't have to reorder the list for the encoder here. This can only be done
+            after we encode this slice. We can run thru a second-pass to see if new ordering
+            would save more bits. Too much delay !! */
+            /* status = ReOrderList(video);*/
+            status = InitSlice(encvid);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+
+            /* when we have everything, we encode the slice header */
+            status = EncodeSliceHeader(encvid, bitstream);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+
+            status = AVCEncodeSlice(encvid);
+
+            video->slice_id++;
+
+            /* closing the NAL with trailing bits */
+            BitstreamTrailingBits(bitstream, buf_nal_size);
+
+            *buf_nal_size = bitstream->write_pos;
+
+            encvid->rateCtrl->numFrameBits += ((*buf_nal_size) << 3);
+
+            *nal_type = video->nal_unit_type;
+
+            if (status == AVCENC_PICTURE_READY)
+            {
+                status = RCUpdateFrame(encvid);
+                if (status == AVCENC_SKIPPED_PICTURE) /* skip current frame */
+                {
+                    DPBReleaseCurrentFrame(avcHandle, video);
+                    encvid->enc_state = AVCEnc_Analyzing_Frame;
+
+                    return status;
+                }
+
+                /* perform loop-filtering on the entire frame */
+                DeblockPicture(video);
+
+                /* update the original frame array */
+                encvid->prevCodedFrameNum = encvid->currInput->coding_order;
+
+                /* store the encoded picture in the DPB buffer */
+                StorePictureInDPB(avcHandle, video);
+
+                if (video->currPic->isReference)
+                {
+                    video->PrevRefFrameNum = video->sliceHdr->frame_num;
+                }
+
+                /* update POC related variables */
+                PostPOC(video);
+
+                encvid->enc_state = AVCEnc_Analyzing_Frame;
+                status = AVCENC_PICTURE_READY;
+
+            }
+            break;
+        default:
+            status = AVCENC_WRONG_STATE;
+    }
+
+    return status;
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCEncGetOverrunBuffer()                                   */
+/*  Purpose  : To retrieve the overrun buffer. Check whether overrun buffer */
+/*              is used or not before returning                             */
+/*  In/out   :                                                              */
+/*  Return   : Pointer to the internal overrun buffer.                      */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF uint8* PVAVCEncGetOverrunBuffer(AVCHandle* avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+    AVCEncBitstream *bitstream = encvid->bitstream;
+
+    if (bitstream->overrunBuffer == bitstream->bitstreamBuffer) /* OB is used */
+    {
+        return encvid->overrunBuffer;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+
+/* ======================================================================== */
+/*  Function : PVAVCEncGetRecon()                                           */
+/*  Date     : 4/29/2004                                                    */
+/*  Purpose  : To retrieve the most recently encoded frame.                 */
+/*              assume that user will make a copy if they want to hold on   */
+/*              to it. Otherwise, it is not guaranteed to be reserved.      */
+/*              Most applications prefer to see original frame rather than  */
+/*              reconstructed frame. So, we are staying aware from complex  */
+/*              buffering mechanism. If needed, can be added later.         */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncGetRecon(AVCHandle *avcHandle, AVCFrameIO *recon)
+{
+    AVCEncObject *encvid = (AVCEncObject*)avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCFrameStore *currFS = video->currFS;
+
+    if (encvid == NULL)
+    {
+        return AVCENC_UNINITIALIZED;
+    }
+
+    recon->YCbCr[0] = currFS->frame.Sl;
+    recon->YCbCr[1] = currFS->frame.Scb;
+    recon->YCbCr[2] = currFS->frame.Scr;
+    recon->height = currFS->frame.height;
+    recon->pitch = currFS->frame.pitch;
+    recon->disp_order = currFS->PicOrderCnt;
+    recon->coding_order = currFS->FrameNum;
+    recon->id = (uint32) currFS->base_dpb; /* use the pointer as the id */
+
+    currFS->IsOutputted |= 1;
+
+    return AVCENC_SUCCESS;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncReleaseRecon(AVCHandle *avcHandle, AVCFrameIO *recon)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(recon);
+
+    return AVCENC_SUCCESS; //for now
+}
+
+/* ======================================================================== */
+/*  Function : PVAVCCleanUpEncoder()                                        */
+/*  Date     : 4/18/2004                                                    */
+/*  Purpose  : To clean up memories allocated by PVAVCEncInitialize()       */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS for success.                                  */
+/*  Modified :                                                              */
+/* ======================================================================== */
+OSCL_EXPORT_REF void    PVAVCCleanUpEncoder(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCCommonObj *video;
+    uint32 *userData = (uint32*) avcHandle->userData;
+
+    if (encvid != NULL)
+    {
+        CleanMotionSearchModule(avcHandle);
+
+        CleanupRateControlModule(avcHandle);
+
+        if (encvid->functionPointer != NULL)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->functionPointer);
+        }
+
+        if (encvid->min_cost)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->min_cost);
+        }
+
+        if (encvid->intraSearch)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->intraSearch);
+        }
+
+        if (encvid->mot16x16)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->mot16x16);
+        }
+
+        if (encvid->rateCtrl)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->rateCtrl);
+        }
+
+        if (encvid->overrunBuffer)
+        {
+            avcHandle->CBAVC_Free(userData, (int)encvid->overrunBuffer);
+        }
+
+        video = encvid->common;
+        if (video != NULL)
+        {
+            if (video->MbToSliceGroupMap)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video->MbToSliceGroupMap);
+            }
+            if (video->mblock != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video->mblock);
+            }
+            if (video->decPicBuf != NULL)
+            {
+                CleanUpDPB(avcHandle, video);
+                avcHandle->CBAVC_Free(userData, (int)video->decPicBuf);
+            }
+            if (video->sliceHdr != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video->sliceHdr);
+            }
+            if (video->currPicParams != NULL)
+            {
+                if (video->currPicParams->slice_group_id)
+                {
+                    avcHandle->CBAVC_Free(userData, (int)video->currPicParams->slice_group_id);
+                }
+
+                avcHandle->CBAVC_Free(userData, (int)video->currPicParams);
+            }
+            if (video->currSeqParams != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video->currSeqParams);
+            }
+            if (encvid->bitstream != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)encvid->bitstream);
+            }
+            if (video != NULL)
+            {
+                avcHandle->CBAVC_Free(userData, (int)video);
+            }
+        }
+
+        avcHandle->CBAVC_Free(userData, (int)encvid);
+
+        avcHandle->AVCObject = NULL;
+    }
+
+    return ;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateBitRate(AVCHandle *avcHandle, uint32 bitrate)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(bitrate);
+
+    return AVCENC_FAIL;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateFrameRate(AVCHandle *avcHandle, uint32 num, uint32 denom)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(num);
+    OSCL_UNUSED_ARG(denom);
+
+    return AVCENC_FAIL;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateIDRInterval(AVCHandle *avcHandle, int IDRInterval)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(IDRInterval);
+
+    return AVCENC_FAIL;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncIDRRequest(AVCHandle *avcHandle)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+
+    return AVCENC_FAIL;
+}
+
+OSCL_EXPORT_REF AVCEnc_Status PVAVCEncUpdateIMBRefresh(AVCHandle *avcHandle, int numMB)
+{
+    OSCL_UNUSED_ARG(avcHandle);
+    OSCL_UNUSED_ARG(numMB);
+
+    return AVCENC_FAIL;
+}
+
+void PVAVCEncGetFrameStats(AVCHandle *avcHandle, AVCEncFrameStats *avcStats)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+
+    avcStats->avgFrameQP = GetAvgFrameQP(rateCtrl);
+    avcStats->numIntraMBs = encvid->numIntraMB;
+
+    return ;
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/avcenc_api.h b/media/libstagefright/codecs/avc/enc/src/avcenc_api.h
new file mode 100644
index 0000000..6841ec3
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/avcenc_api.h
@@ -0,0 +1,323 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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.
+ * -------------------------------------------------------------------
+ */
+/**
+This file contains application function interfaces to the AVC encoder library
+and necessary type defitionitions and enumerations.
+@publishedAll
+*/
+
+#ifndef AVCENC_API_H_INCLUDED
+#define AVCENC_API_H_INCLUDED
+
+#ifndef AVCAPI_COMMON_H_INCLUDED
+#include "avcapi_common.h"
+#endif
+
+// For memset, etc
+#include <string.h>
+
+/**
+ This enumeration is used for the status returned from the library interface.
+*/
+typedef enum
+{
+    /**
+    Fail information, need to add more error code for more specific info
+    */
+    AVCENC_TRAILINGONES_FAIL = -35,
+    AVCENC_SLICE_EMPTY = -34,
+    AVCENC_POC_FAIL = -33,
+    AVCENC_CONSECUTIVE_NONREF = -32,
+    AVCENC_CABAC_FAIL = -31,
+    AVCENC_PRED_WEIGHT_TAB_FAIL = -30,
+    AVCENC_DEC_REF_PIC_MARK_FAIL = -29,
+    AVCENC_SPS_FAIL = -28,
+    AVCENC_BITSTREAM_BUFFER_FULL    = -27,
+    AVCENC_BITSTREAM_INIT_FAIL = -26,
+    AVCENC_CHROMA_QP_FAIL = -25,
+    AVCENC_INIT_QS_FAIL = -24,
+    AVCENC_INIT_QP_FAIL = -23,
+    AVCENC_WEIGHTED_BIPRED_FAIL = -22,
+    AVCENC_INVALID_INTRA_PERIOD = -21,
+    AVCENC_INVALID_CHANGE_RATE = -20,
+    AVCENC_INVALID_BETA_OFFSET = -19,
+    AVCENC_INVALID_ALPHA_OFFSET = -18,
+    AVCENC_INVALID_DEBLOCK_IDC = -17,
+    AVCENC_INVALID_REDUNDANT_PIC = -16,
+    AVCENC_INVALID_FRAMERATE = -15,
+    AVCENC_INVALID_NUM_SLICEGROUP = -14,
+    AVCENC_INVALID_POC_LSB = -13,
+    AVCENC_INVALID_NUM_REF = -12,
+    AVCENC_INVALID_FMO_TYPE = -11,
+    AVCENC_ENCPARAM_MEM_FAIL = -10,
+    AVCENC_LEVEL_NOT_SUPPORTED = -9,
+    AVCENC_LEVEL_FAIL = -8,
+    AVCENC_PROFILE_NOT_SUPPORTED = -7,
+    AVCENC_TOOLS_NOT_SUPPORTED = -6,
+    AVCENC_WRONG_STATE = -5,
+    AVCENC_UNINITIALIZED = -4,
+    AVCENC_ALREADY_INITIALIZED = -3,
+    AVCENC_NOT_SUPPORTED = -2,
+    AVCENC_MEMORY_FAIL = AVC_MEMORY_FAIL,
+    AVCENC_FAIL = AVC_FAIL,
+    /**
+    Generic success value
+    */
+    AVCENC_SUCCESS = AVC_SUCCESS,
+    AVCENC_PICTURE_READY = 2,
+    AVCENC_NEW_IDR = 3, /* upon getting this, users have to call PVAVCEncodeSPS and PVAVCEncodePPS to get a new SPS and PPS*/
+    AVCENC_SKIPPED_PICTURE = 4 /* continuable error message */
+
+} AVCEnc_Status;
+
+#define MAX_NUM_SLICE_GROUP  8      /* maximum for all the profiles */
+
+/**
+This structure contains the encoding parameters.
+*/
+typedef struct tagAVCEncParam
+{
+    /* if profile/level is set to zero, encoder will choose the closest one for you */
+    AVCProfile profile; /* profile of the bitstream to be compliant with*/
+    AVCLevel   level;   /* level of the bitstream to be compliant with*/
+
+    int width;      /* width of an input frame in pixel */
+    int height;     /* height of an input frame in pixel */
+
+    int poc_type; /* picture order count mode, 0,1 or 2 */
+    /* for poc_type == 0 */
+    uint log2_max_poc_lsb_minus_4; /* specify maximum value of POC Lsb, range 0..12*/
+    /* for poc_type == 1 */
+    uint delta_poc_zero_flag; /* delta POC always zero */
+    int offset_poc_non_ref; /* offset for non-reference pic */
+    int offset_top_bottom; /* offset between top and bottom field */
+    uint num_ref_in_cycle; /* number of reference frame in one cycle */
+    int *offset_poc_ref; /* array of offset for ref pic, dimension [num_ref_in_cycle] */
+
+    int num_ref_frame;  /* number of reference frame used */
+    int num_slice_group;  /* number of slice group */
+    int fmo_type;   /* 0: interleave, 1: dispersed, 2: foreground with left-over
+                    3: box-out, 4:raster scan, 5:wipe, 6:explicit */
+    /* for fmo_type == 0 */
+    uint run_length_minus1[MAX_NUM_SLICE_GROUP];   /* array of size num_slice_group, in round robin fasion */
+    /* fmo_type == 2*/
+    uint top_left[MAX_NUM_SLICE_GROUP-1];           /* array of co-ordinates of each slice_group */
+    uint bottom_right[MAX_NUM_SLICE_GROUP-1];       /* except the last one which is the background. */
+    /* fmo_type == 3,4,5 */
+    AVCFlag change_dir_flag;  /* slice group change direction flag */
+    uint change_rate_minus1;
+    /* fmo_type == 6 */
+    uint *slice_group; /* array of size MBWidth*MBHeight */
+
+    AVCFlag db_filter;  /* enable deblocking loop filter */
+    int disable_db_idc;  /* 0: filter everywhere, 1: no filter, 2: no filter across slice boundary */
+    int alpha_offset;   /* alpha offset range -6,...,6 */
+    int beta_offset;    /* beta offset range -6,...,6 */
+
+    AVCFlag constrained_intra_pred; /* constrained intra prediction flag */
+
+    AVCFlag auto_scd;   /* scene change detection on or off */
+    int idr_period; /* idr frame refresh rate in number of target encoded frame (no concept of actual time).*/
+    int intramb_refresh;    /* minimum number of intra MB per frame */
+    AVCFlag data_par;   /* enable data partitioning */
+
+    AVCFlag fullsearch; /* enable full-pel full-search mode */
+    int search_range;   /* search range for motion vector in (-search_range,+search_range) pixels */
+    AVCFlag sub_pel;    /* enable sub pel prediction */
+    AVCFlag submb_pred; /* enable sub MB partition mode */
+    AVCFlag rdopt_mode; /* RD optimal mode selection */
+    AVCFlag bidir_pred; /* enable bi-directional for B-slice, this flag forces the encoder to encode
+                        any frame with POC less than the previously encoded frame as a B-frame.
+                        If it's off, then such frames will remain P-frame. */
+
+    AVCFlag rate_control; /* rate control enable, on: RC on, off: constant QP */
+    int initQP;     /* initial QP */
+    uint32 bitrate;    /* target encoding bit rate in bits/second */
+    uint32 CPB_size;  /* coded picture buffer in number of bits */
+    uint32 init_CBP_removal_delay; /* initial CBP removal delay in msec */
+
+    uint32 frame_rate;  /* frame rate in the unit of frames per 1000 second */
+    /* note, frame rate is only needed by the rate control, AVC is timestamp agnostic. */
+
+    AVCFlag out_of_band_param_set; /* flag to set whether param sets are to be retrieved up front or not */
+
+    AVCFlag use_overrun_buffer;  /* do not throw away the frame if output buffer is not big enough.
+                                    copy excess bits to the overrun buffer */
+} AVCEncParams;
+
+
+/**
+This structure contains current frame encoding statistics for debugging purpose.
+*/
+typedef struct tagAVCEncFrameStats
+{
+    int avgFrameQP;   /* average frame QP */
+    int numIntraMBs;  /* number of intra MBs */
+    int numFalseAlarm;
+    int numMisDetected;
+    int numDetected;
+
+} AVCEncFrameStats;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+    /** THE FOLLOWINGS ARE APIS */
+    /**
+    This function initializes the encoder library. It verifies the validity of the
+    encoding parameters against the specified profile/level and the list of supported
+    tools by this library. It allocates necessary memories required to perform encoding.
+    For re-encoding application, if users want to setup encoder in a more precise way,
+    users can give the external SPS and PPS to the encoder to follow.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "encParam"   "Pointer to the encoding parameter structure."
+    \param "extSPS"     "External SPS used for re-encoding purpose. NULL if not present"
+    \param "extPPS"     "External PPS used for re-encoding purpose. NULL if not present"
+    \return "AVCENC_SUCCESS for success,
+             AVCENC_NOT_SUPPORTED for the use of unsupported tools,
+             AVCENC_MEMORY_FAIL for memory allocation failure,
+             AVCENC_FAIL for generic failure."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncInitialize(AVCHandle *avcHandle, AVCEncParams *encParam, void* extSPS, void* extPPS);
+
+
+    /**
+    Since the output buffer size is not known prior to encoding a frame, users need to
+    allocate big enough buffer otherwise, that frame will be dropped. This function returns
+    the size of the output buffer to be allocated by the users that guarantees to hold one frame.
+    It follows the CPB spec for a particular level.  However, when the users set use_overrun_buffer
+    flag, this API is useless as excess output bits are saved in the overrun buffer waiting to be
+    copied out in small chunks, i.e. users can allocate any size of output buffer.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "size"   "Pointer to the size to be modified."
+    \return "AVCENC_SUCCESS for success, AVCENC_UNINITIALIZED when level is not known.
+    */
+
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetMaxOutputBufferSize(AVCHandle *avcHandle, int* size);
+
+    /**
+    Users call this function to provide an input structure to the encoder library which will keep
+    a list of input structures it receives in case the users call this function many time before
+    calling PVAVCEncodeSlice. The encoder library will encode them according to the frame_num order.
+    Users should not modify the content of a particular frame until this frame is encoded and
+    returned thru CBAVCEnc_ReturnInput() callback function.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "input"      "Pointer to the input structure."
+    \return "AVCENC_SUCCESS for success,
+            AVCENC_FAIL if the encoder is not in the right state to take a new input frame.
+            AVCENC_NEW_IDR for the detection or determination of a new IDR, with this status,
+            the returned NAL is an SPS NAL,
+            AVCENC_NO_PICTURE if the input frame coding timestamp is too early, users must
+            get next frame or adjust the coding timestamp."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncSetInput(AVCHandle *avcHandle, AVCFrameIO *input);
+
+    /**
+    This function is called to encode a NAL unit which can be an SPS NAL, a PPS NAL or
+    a VCL (video coding layer) NAL which contains one slice of data. It could be a
+    fixed number of macroblocks, as specified in the encoder parameters set, or the
+    maximum number of macroblocks fitted into the given input argument "buffer". The
+    input frame is taken from the oldest unencoded input frame retrieved by users by
+    PVAVCEncGetInput API.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "buffer"     "Pointer to the output AVC bitstream buffer, the format will be EBSP,
+                         not RBSP."
+    \param "buf_nal_size"   "As input, the size of the buffer in bytes.
+                        This is the physical limitation of the buffer. As output, the size of the EBSP."
+    \param "nal_type"   "Pointer to the NAL type of the returned buffer."
+    \return "AVCENC_SUCCESS for success of encoding one slice,
+             AVCENC_PICTURE_READY for the completion of a frame encoding,
+             AVCENC_FAIL for failure (this should not occur, though)."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncodeNAL(AVCHandle *avcHandle, uint8 *buffer, uint *buf_nal_size, int *nal_type);
+
+    /**
+    This function sniffs the nal_unit_type such that users can call corresponding APIs.
+    This function is identical to PVAVCDecGetNALType() in the decoder.
+    \param "bitstream"  "Pointer to the beginning of a NAL unit (start with forbidden_zero_bit, etc.)."
+    \param "size"       "size of the bitstream (NumBytesInNALunit + 1)."
+    \param "nal_unit_type" "Pointer to the return value of nal unit type."
+    \return "AVCENC_SUCCESS if success, AVCENC_FAIL otherwise."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetNALType(uint8 *bitstream, int size, int *nal_type, int *nal_ref_idc);
+
+    /**
+    This function returns the pointer to internal overrun buffer. Users can call this to query
+    whether the overrun buffer has been used to encode the current NAL.
+    \param "avcHandle"  "Pointer to the handle."
+    \return "Pointer to overrun buffer if it is used, otherwise, NULL."
+    */
+    OSCL_IMPORT_REF uint8* PVAVCEncGetOverrunBuffer(AVCHandle* avcHandle);
+
+    /**
+    This function returns the reconstructed frame of the most recently encoded frame.
+    Note that this frame is not returned to the users yet. Users should only read the
+    content of this frame.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "output"     "Pointer to the input structure."
+    \return "AVCENC_SUCCESS for success, AVCENC_NO_PICTURE if no picture to be outputted."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncGetRecon(AVCHandle *avcHandle, AVCFrameIO *recon);
+
+    /**
+    This function is used to return the recontructed frame back to the AVC encoder library
+    in order to be re-used for encoding operation. If users want the content of it to remain
+    unchanged for a long time, they should make a copy of it and release the memory back to
+    the encoder. The encoder relies on the id element in the AVCFrameIO structure,
+    thus users should not change the id value.
+    \param "avcHandle"  "Handle to the AVC decoder library object."
+    \param "output"      "Pointer to the AVCFrameIO structure."
+    \return "AVCENC_SUCCESS for success, AVCENC_FAIL for fail for id not found."
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncReleaseRecon(AVCHandle *avcHandle, AVCFrameIO *recon);
+
+    /**
+    This function performs clean up operation including memory deallocation.
+    The encoder will also clear the list of input structures it has not released.
+    This implies that users must keep track of the number of input structure they have allocated
+    and free them accordingly.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    */
+    OSCL_IMPORT_REF void    PVAVCCleanUpEncoder(AVCHandle *avcHandle);
+
+    /**
+    This function extracts statistics of the current frame. If the encoder has not finished
+    with the current frame, the result is not accurate.
+    \param "avcHandle"  "Handle to the AVC encoder library object."
+    \param "avcStats"   "Pointer to AVCEncFrameStats structure."
+    \return "void."
+    */
+    void PVAVCEncGetFrameStats(AVCHandle *avcHandle, AVCEncFrameStats *avcStats);
+
+    /**
+    These functions are used for the modification of encoding parameters.
+    To be polished.
+    */
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateBitRate(AVCHandle *avcHandle, uint32 bitrate);
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateFrameRate(AVCHandle *avcHandle, uint32 num, uint32 denom);
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateIDRInterval(AVCHandle *avcHandle, int IDRInterval);
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncIDRRequest(AVCHandle *avcHandle);
+    OSCL_IMPORT_REF AVCEnc_Status PVAVCEncUpdateIMBRefresh(AVCHandle *avcHandle, int numMB);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif  /* _AVCENC_API_H_ */
+
diff --git a/media/libstagefright/codecs/avc/enc/src/avcenc_int.h b/media/libstagefright/codecs/avc/enc/src/avcenc_int.h
new file mode 100644
index 0000000..3fe08a1
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/avcenc_int.h
@@ -0,0 +1,471 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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.
+ * -------------------------------------------------------------------
+ */
+/**
+This file contains application function interfaces to the AVC encoder library
+and necessary type defitionitions and enumerations.
+@publishedAll
+*/
+
+#ifndef AVCENC_INT_H_INCLUDED
+#define AVCENC_INT_H_INCLUDED
+
+#ifndef AVCINT_COMMON_H_INCLUDED
+#include "avcint_common.h"
+#endif
+#ifndef AVCENC_API_H_INCLUDED
+#include "avcenc_api.h"
+#endif
+
+typedef float OsclFloat;
+
+/* Definition for the structures below */
+#define DEFAULT_ATTR    0 /* default memory attribute */
+#define MAX_INPUT_FRAME 30 /* some arbitrary number, it can be much higher than this. */
+#define MAX_REF_FRAME  16 /* max size of the RefPicList0 and RefPicList1 */
+#define MAX_REF_PIC_LIST 33
+
+#define MIN_QP          0
+#define MAX_QP          51
+#define SHIFT_QP        12
+#define  LAMBDA_ACCURACY_BITS         16
+#define  LAMBDA_FACTOR(lambda)        ((int)((double)(1<<LAMBDA_ACCURACY_BITS)*lambda+0.5))
+
+
+#define DISABLE_THRESHOLDING  0
+// for better R-D performance
+#define _LUMA_COEFF_COST_       4 //!< threshold for luma coeffs
+#define _CHROMA_COEFF_COST_     4 //!< threshold for chroma coeffs, used to be 7
+#define _LUMA_MB_COEFF_COST_    5 //!< threshold for luma coeffs of inter Macroblocks
+#define _LUMA_8x8_COEFF_COST_   5 //!< threshold for luma coeffs of 8x8 Inter Partition
+#define MAX_VALUE       999999   //!< used for start value for some variables
+
+#define  WEIGHTED_COST(factor,bits)   (((factor)*(bits))>>LAMBDA_ACCURACY_BITS)
+#define  MV_COST(f,s,cx,cy,px,py)     (WEIGHTED_COST(f,mvbits[((cx)<<(s))-px]+mvbits[((cy)<<(s))-py]))
+#define  MV_COST_S(f,cx,cy,px,py)     (WEIGHTED_COST(f,mvbits[cx-px]+mvbits[cy-py]))
+
+/* for sub-pel search and interpolation */
+#define SUBPEL_PRED_BLK_SIZE 576 // 24x24
+#define REF_CENTER 75
+#define V2Q_H0Q 1
+#define V0Q_H2Q 2
+#define V2Q_H2Q 3
+
+/*
+#define V3Q_H0Q 1
+#define V3Q_H1Q 2
+#define V0Q_H1Q 3
+#define V1Q_H1Q 4
+#define V1Q_H0Q 5
+#define V1Q_H3Q 6
+#define V0Q_H3Q 7
+#define V3Q_H3Q 8
+#define V2Q_H3Q 9
+#define V2Q_H0Q 10
+#define V2Q_H1Q 11
+#define V2Q_H2Q 12
+#define V3Q_H2Q 13
+#define V0Q_H2Q 14
+#define V1Q_H2Q 15
+*/
+
+
+#define DEFAULT_OVERRUN_BUFFER_SIZE 1000
+
+// associated with the above cost model
+const uint8 COEFF_COST[2][16] =
+{
+    {3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+    {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}
+};
+
+
+
+//! convert from H.263 QP to H.264 quant given by: quant=pow(2,QP/6)
+const int QP2QUANT[40] =
+{
+    1, 1, 1, 1, 2, 2, 2, 2,
+    3, 3, 3, 4, 4, 4, 5, 6,
+    6, 7, 8, 9, 10, 11, 13, 14,
+    16, 18, 20, 23, 25, 29, 32, 36,
+    40, 45, 51, 57, 64, 72, 81, 91
+};
+
+
+/**
+This enumeration keeps track of the internal status of the encoder whether it is doing
+something. The encoding flow follows the order in which these states are.
+@publishedAll
+*/
+typedef enum
+{
+    AVCEnc_Initializing = 0,
+    AVCEnc_Encoding_SPS,
+    AVCEnc_Encoding_PPS,
+    AVCEnc_Analyzing_Frame,
+    AVCEnc_WaitingForBuffer,  // pending state
+    AVCEnc_Encoding_Frame,
+} AVCEnc_State ;
+
+/**
+Bitstream structure contains bitstream related parameters such as the pointer
+to the buffer, the current byte position and bit position. The content of the
+bitstreamBuffer will be in EBSP format as the emulation prevention codes are
+automatically inserted as the RBSP is recorded.
+@publishedAll
+*/
+typedef struct tagEncBitstream
+{
+    uint8 *bitstreamBuffer; /* pointer to buffer memory   */
+    int buf_size;       /* size of the buffer memory */
+    int write_pos;      /* next position to write to bitstreamBuffer  */
+    int count_zeros;   /* count number of consecutive zero */
+    uint current_word;  /* byte-swapped (MSB left) current word to write to buffer */
+    int bit_left;      /* number of bit left in current_word */
+    uint8   *overrunBuffer;  /* extra output buffer to prevent current skip due to output buffer overrun*/
+    int     oBSize;     /* size of allocated overrun buffer */
+    void   *encvid; /* pointer to the main object */
+
+} AVCEncBitstream;
+
+/**
+This structure is used for rate control purpose and other performance related control
+variables such as, RD cost, statistics, motion search stuffs, etc.
+should be in this structure.
+@publishedAll
+*/
+
+
+typedef struct tagRDInfo
+{
+    int QP;
+    int actual_bits;
+    OsclFloat mad;
+    OsclFloat R_D;
+} RDInfo;
+
+typedef struct tagMultiPass
+{
+    /* multipass rate control data */
+    int target_bits;    /* target bits for current frame, = rc->T */
+    int actual_bits;    /* actual bits for current frame obtained after encoding, = rc->Rc*/
+    int QP;             /* quantization level for current frame, = rc->Qc*/
+    int prev_QP;        /* quantization level for previous frame */
+    int prev_prev_QP;   /* quantization level for previous frame before last*/
+    OsclFloat mad;          /* mad for current frame, = video->avgMAD*/
+    int bitrate;        /* bitrate for current frame */
+    OsclFloat framerate;    /* framerate for current frame*/
+
+    int nRe_Quantized;  /* control variable for multipass encoding, */
+    /* 0 : first pass */
+    /* 1 : intermediate pass(quantization and VLC loop only) */
+    /* 2 : final pass(de-quantization, idct, etc) */
+    /* 3 : macroblock level rate control */
+
+    int encoded_frames;     /* counter for all encoded frames */
+    int re_encoded_frames;  /* counter for all multipass encoded frames*/
+    int re_encoded_times;   /* counter for all times of multipass frame encoding */
+
+    /* Multiple frame prediction*/
+    RDInfo **pRDSamples;        /* pRDSamples[30][32], 30->30fps, 32 -> 5 bit quantizer, 32 candidates*/
+    int framePos;               /* specific position in previous multiple frames*/
+    int frameRange;             /* number of overall previous multiple frames */
+    int samplesPerFrame[30];    /* number of samples per frame, 30->30fps */
+
+    /* Bit allocation for scene change frames and high motion frames */
+    OsclFloat sum_mad;
+    int counter_BTsrc;  /* BT = Bit Transfer, bit transfer from low motion frames or less complicatedly compressed frames */
+    int counter_BTdst;  /* BT = Bit Transfer, bit transfer to scene change frames or high motion frames or more complicatedly compressed frames */
+    OsclFloat sum_QP;
+    int diff_counter;   /* diff_counter = -diff_counter_BTdst, or diff_counter_BTsrc */
+
+    /* For target bitrate or framerate update */
+    OsclFloat target_bits_per_frame;        /* = C = bitrate/framerate */
+    OsclFloat target_bits_per_frame_prev;   /* previous C */
+    OsclFloat aver_mad;                     /* so-far average mad could replace sum_mad */
+    OsclFloat aver_mad_prev;                /* previous average mad */
+    int   overlapped_win_size;          /* transition period of time */
+    int   encoded_frames_prev;          /* previous encoded_frames */
+} MultiPass;
+
+
+typedef struct tagdataPointArray
+{
+    int Qp;
+    int Rp;
+    OsclFloat Mp;   /* for MB-based RC */
+    struct tagdataPointArray *next;
+    struct tagdataPointArray *prev;
+} dataPointArray;
+
+typedef struct tagAVCRateControl
+{
+
+    /* these parameters are initialized by the users AVCEncParams */
+    /* bitrate-robustness tradeoff */
+    uint scdEnable; /* enable scene change detection */
+    int idrPeriod;  /* IDR period in number of frames */
+    int intraMBRate;   /* intra MB refresh rate per frame */
+    uint dpEnable;  /* enable data partitioning */
+
+    /* quality-complexity tradeoff */
+    uint subPelEnable;  /* enable quarter pel search */
+    int mvRange;    /* motion vector search range in +/- pixel */
+    uint subMBEnable;  /* enable sub MB prediction mode (4x4, 4x8, 8x4) */
+    uint rdOptEnable;  /* enable RD-opt mode selection */
+    uint twoPass; /* flag for 2 pass encoding ( for future )*/
+    uint bidirPred; /* bi-directional prediction for B-frame. */
+
+    uint rcEnable;  /* enable rate control, '1' on, '0' const QP */
+    int initQP; /* initial QP */
+
+    /* note the following 3 params are for HRD, these triplets can be a series
+    of triplets as the generalized HRD allows. SEI message must be generated in this case. */
+    /* We no longer have to differentiate between CBR and VBR. The users to the
+    AVC encoder lib will do the mapping from CBR/VBR to these parameters. */
+    int32 bitRate;  /* target bit rate for the overall clip in bits/second*/
+    int32 cpbSize;  /* coded picture buffer size in bytes */
+    int32 initDelayOffset; /* initial CBP removal delay in bits */
+
+    OsclFloat frame_rate; /* frame rate */
+    int srcInterval; /* source frame rate in msec */
+    int basicUnit;  /* number of macroblocks per BU */
+
+    /* Then internal parameters for the operation */
+    uint first_frame; /* a flag for the first frame */
+    int lambda_mf; /* for example */
+    int totalSAD;    /* SAD of current frame */
+
+    /*******************************************/
+    /* this part comes from MPEG4 rate control */
+    int alpha;  /* weight for I frame */
+    int Rs;     /*bit rate for the sequence (or segment) e.g., 24000 bits/sec */
+    int Rc;     /*bits used for the current frame. It is the bit count obtained after encoding. */
+    int Rp;     /*bits to be removed from the buffer per picture. */
+    /*? is this the average one, or just the bits coded for the previous frame */
+    int Rps;    /*bit to be removed from buffer per src frame */
+    OsclFloat Ts;   /*number of seconds for the sequence  (or segment). e.g., 10 sec */
+    OsclFloat Ep;
+    OsclFloat Ec;   /*mean absolute difference for the current frame after motion compensation.*/
+    /*If the macroblock is intra coded, the original spatial pixel values are summed.*/
+    int Qc;     /*quantization level used for the current frame. */
+    int Nr;     /*number of P frames remaining for encoding.*/
+    int Rr; /*number of bits remaining for encoding this sequence (or segment).*/
+    int Rr_Old;
+    int T;      /*target bit to be used for the current frame.*/
+    int S;      /*number of bits used for encoding the previous frame.*/
+    int Hc; /*header and motion vector bits used in the current frame. It includes all the  information except to the residual information.*/
+    int Hp; /*header and motion vector bits used in the previous frame. It includes all the     information except to the residual information.*/
+    int Ql; /*quantization level used in the previous frame */
+    int Bs; /*buffer size e.g., R/2 */
+    int B;      /*current buffer level e.g., R/4 - start from the middle of the buffer */
+    OsclFloat X1;
+    OsclFloat X2;
+    OsclFloat X11;
+    OsclFloat M;            /*safe margin for the buffer */
+    OsclFloat smTick;    /*ratio of src versus enc frame rate */
+    double remnant;  /*remainder frame of src/enc frame for fine frame skipping */
+    int timeIncRes; /* vol->timeIncrementResolution */
+
+    dataPointArray   *end; /*quantization levels for the past (20) frames */
+
+    int     frameNumber; /* ranging from 0 to 20 nodes*/
+    int     w;
+    int     Nr_Original;
+    int     Nr_Old, Nr_Old2;
+    int     skip_next_frame;
+    int     Qdep;       /* smooth Q adjustment */
+    int     VBR_Enabled;
+
+    int totalFrameNumber; /* total coded frames, for debugging!!*/
+
+    char    oFirstTime;
+
+    int numFrameBits; /* keep track of number of bits of the current frame */
+    int NumberofHeaderBits;
+    int NumberofTextureBits;
+    int numMBHeaderBits;
+    int numMBTextureBits;
+    double *MADofMB;
+    int32 bitsPerFrame;
+
+    /* BX rate control, something like TMN8 rate control*/
+
+    MultiPass *pMP;
+
+    int     TMN_W;
+    int     TMN_TH;
+    int     VBV_fullness;
+    int     max_BitVariance_num; /* the number of the maximum bit variance within the given buffer with the unit of 10% of bitrate/framerate*/
+    int     encoded_frames; /* counter for all encoded frames */
+    int     low_bound;              /* bound for underflow detection, usually low_bound=-Bs/2, but could be changed in H.263 mode */
+    int     VBV_fullness_offset;    /* offset of VBV_fullness, usually is zero, but can be changed in H.263 mode*/
+    /* End BX */
+
+} AVCRateControl;
+
+
+/**
+This structure is for the motion vector information. */
+typedef struct tagMV
+{
+    int x;
+    int y;
+    uint sad;
+} AVCMV;
+
+/**
+This structure contains function pointers for different platform dependent implementation of
+functions. */
+typedef struct tagAVCEncFuncPtr
+{
+
+    int (*SAD_MB_HalfPel[4])(uint8*, uint8*, int, void *);
+    int (*SAD_Macroblock)(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+
+} AVCEncFuncPtr;
+
+/**
+This structure contains information necessary for correct padding.
+*/
+typedef struct tagPadInfo
+{
+    int i;
+    int width;
+    int j;
+    int height;
+} AVCPadInfo;
+
+
+#ifdef HTFM
+typedef struct tagHTFM_Stat
+{
+    int abs_dif_mad_avg;
+    uint countbreak;
+    int offsetArray[16];
+    int offsetRef[16];
+} HTFM_Stat;
+#endif
+
+
+/**
+This structure is the main object for AVC encoder library providing access to all
+global variables. It is allocated at PVAVCInitEncoder and freed at PVAVCCleanUpEncoder.
+@publishedAll
+*/
+typedef struct tagEncObject
+{
+
+    AVCCommonObj *common;
+
+    AVCEncBitstream     *bitstream; /* for current NAL */
+    uint8   *overrunBuffer;  /* extra output buffer to prevent current skip due to output buffer overrun*/
+    int     oBSize;     /* size of allocated overrun buffer */
+
+    /* rate control */
+    AVCRateControl      *rateCtrl; /* pointer to the rate control structure */
+
+    /* encoding operation */
+    AVCEnc_State        enc_state; /* encoding state */
+
+    AVCFrameIO          *currInput; /* pointer to the current input frame */
+
+    int                 currSliceGroup; /* currently encoded slice group id */
+
+    int     level[24][16], run[24][16]; /* scratch memory */
+    int     leveldc[16], rundc[16]; /* for DC component */
+    int     levelcdc[16], runcdc[16]; /* for chroma DC component */
+    int     numcoefcdc[2]; /* number of coefficient for chroma DC */
+    int     numcoefdc;      /* number of coefficients for DC component */
+
+    int     qp_const;
+    int     qp_const_c;
+    /********* intra prediction scratch memory **********************/
+    uint8   pred_i16[AVCNumI16PredMode][256]; /* save prediction for MB */
+    uint8   pred_i4[AVCNumI4PredMode][16];  /* save prediction for blk */
+    uint8   pred_ic[AVCNumIChromaMode][128];  /* for 2 chroma */
+
+    int     mostProbableI4Mode[16]; /* in raster scan order */
+    /********* motion compensation related variables ****************/
+    AVCMV   *mot16x16;          /* Saved motion vectors for 16x16 block*/
+    AVCMV(*mot16x8)[2];     /* Saved motion vectors for 16x8 block*/
+    AVCMV(*mot8x16)[2];     /* Saved motion vectors for 8x16 block*/
+    AVCMV(*mot8x8)[4];      /* Saved motion vectors for 8x8 block*/
+
+    /********* subpel position **************************************/
+    uint32  subpel_pred[SUBPEL_PRED_BLK_SIZE/*<<2*/]; /* all 16 sub-pel positions  */
+    uint8   *hpel_cand[9];      /* pointer to half-pel position */
+    int     best_hpel_pos;          /* best position */
+    uint8   qpel_cand[8][24*16];        /* pointer to quarter-pel position */
+    int     best_qpel_pos;
+    uint8   *bilin_base[9][4];    /* pointer to 4 position at top left of bilinear quarter-pel */
+
+    /* need for intra refresh rate */
+    uint8   *intraSearch;       /* Intra Array for MBs to be intra searched */
+    uint    firstIntraRefreshMBIndx; /* keep track for intra refresh */
+
+    int     i4_sad;             /* temporary for i4 mode SAD */
+    int     *min_cost;          /* Minimum cost for the all MBs */
+    int     lambda_mode;        /* Lagrange parameter for mode selection */
+    int     lambda_motion;      /* Lagrange parameter for MV selection */
+
+    uint8   *mvbits_array;      /* Table for bits spent in the cost funciton */
+    uint8   *mvbits;            /* An offset to the above array. */
+
+    /* to speedup the SAD calculation */
+    void *sad_extra_info;
+    uint8 currYMB[256];     /* interleaved current macroblock in HTFM order */
+
+#ifdef HTFM
+    int nrmlz_th[48];       /* Threshold for fast SAD calculation using HTFM */
+    HTFM_Stat htfm_stat;    /* For statistics collection */
+#endif
+
+    /* statistics */
+    int numIntraMB;         /* keep track of number of intra MB */
+
+    /* encoding complexity control */
+    uint fullsearch_enable; /* flag to enable full-pel full-search */
+
+    /* misc.*/
+    bool outOfBandParamSet; /* flag to enable out-of-band param set */
+
+    AVCSeqParamSet extSPS; /* for external SPS */
+    AVCPicParamSet extPPS; /* for external PPS */
+
+    /* time control */
+    uint32  prevFrameNum;   /* previous frame number starting from modTimeRef */
+    uint32  modTimeRef;     /* Reference modTime update every I-Vop*/
+    uint32  wrapModTime;    /* Offset to modTime Ref, rarely used */
+
+    uint    prevProcFrameNum;  /* previously processed frame number, could be skipped */
+    uint    prevCodedFrameNum;  /* previously encoded frame number */
+    /* POC related variables */
+    uint32  dispOrdPOCRef;      /* reference POC is displayer order unit. */
+
+    /* Function pointers */
+    AVCEncFuncPtr *functionPointer; /* store pointers to platform specific functions */
+
+    /* Application control data */
+    AVCHandle *avcHandle;
+
+
+} AVCEncObject;
+
+
+#endif /*AVCENC_INT_H_INCLUDED*/
+
diff --git a/media/libstagefright/codecs/avc/enc/src/avcenc_lib.h b/media/libstagefright/codecs/avc/enc/src/avcenc_lib.h
new file mode 100644
index 0000000..17e28ef
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/avcenc_lib.h
@@ -0,0 +1,1020 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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.
+ * -------------------------------------------------------------------
+ */
+/**
+This file contains declarations of internal functions for AVC decoder library.
+@publishedAll
+*/
+#ifndef AVCENC_LIB_H_INCLUDED
+#define AVCENC_LIB_H_INCLUDED
+
+#ifndef AVCLIB_COMMON_H_INCLUDED
+#include "avclib_common.h"
+#endif
+#ifndef AVCENC_INT_H_INCLUDED
+#include "avcenc_int.h"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+    /*------------- block.c -------------------------*/
+
+    /**
+    This function perform residue calculation, transform, quantize, inverse quantize,
+    inverse transform and residue compensation on a 4x4 block.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "blkidx"  "raster scan block index of the current 4x4 block."
+    \param "cur"    "Pointer to the reconstructed block."
+    \param "org"    "Pointer to the original block."
+    \param "coef_cost"  "Pointer to the coefficient cost to be filled in and returned."
+    \return "Number of non-zero coefficients."
+    */
+    int dct_luma(AVCEncObject *encvid, int blkidx, uint8 *cur, uint8 *org, int *coef_cost);
+
+    /**
+    This function performs IDCT on an INTER macroblock.
+    \param "video"  "Pointer to AVCCommonObj."
+    \param "curL"   "Pointer to the origin of the macroblock on the current frame."
+    \param "currMB" "Pointer to the AVCMacroblock structure."
+    \param "picPitch" "Pitch of the current frame."
+    \return "void".
+    */
+    void MBInterIdct(AVCCommonObj *video, uint8 *curL, AVCMacroblock *currMB, int picPitch);
+
+    /**
+    This function perform residue calculation, transform, quantize, inverse quantize,
+    inverse transform and residue compensation on a macroblock.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "curL"   "Pointer to the reconstructed MB."
+    \param "orgL"    "Pointer to the original MB."
+    \return "void"
+    */
+    void dct_luma_16x16(AVCEncObject *encvid, uint8 *curL, uint8 *orgL);
+
+    /**
+    This function perform residue calculation, transform, quantize, inverse quantize,
+    inverse transform and residue compensation for chroma components of an MB.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "curC"   "Pointer to the reconstructed MB."
+    \param "orgC"    "Pointer to the original MB."
+    \param "cr"     "Flag whether it is Cr or not."
+    \return "void"
+    */
+    void dct_chroma(AVCEncObject *encvid, uint8 *curC, uint8 *orgC, int cr);
+
+    /*----------- init.c ------------------*/
+    /**
+    This function interprets the encoding parameters provided by users in encParam.
+    The results are kept in AVCEncObject, AVCSeqParamSet, AVCPicParamSet and AVCSliceHeader.
+    \param "encvid"     "Pointer to AVCEncObject."
+    \param "encParam"   "Pointer to AVCEncParam."
+    \param "extSPS"     "External SPS template to be followed. NULL if not present."
+    \param "extPPS"     "External PPS template to be followed. NULL if not present."
+    \return "see AVCEnc_Status."
+    */
+    AVCEnc_Status  SetEncodeParam(AVCHandle *avcHandle, AVCEncParams *encParam,
+                                  void *extSPS, void *extPPS);
+
+    /**
+    This function verifies the encoding parameters whether they meet the set of supported
+    tool by a specific profile. If the profile is not set, it will just find the closest
+    profile instead of verifying it.
+    \param "video"  "Pointer to AVCEncObject."
+    \param "seqParam"   "Pointer to AVCSeqParamSet."
+    \param "picParam"   "Pointer to AVCPicParamSet."
+    \return "AVCENC_SUCCESS if success,
+            AVCENC_PROFILE_NOT_SUPPORTED if the specified profile
+                is not supported by this version of the library,
+            AVCENC_TOOLS_NOT_SUPPORTED if any of the specified encoding tools are
+            not supported by the user-selected profile."
+    */
+    AVCEnc_Status VerifyProfile(AVCEncObject *video, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam);
+
+    /**
+    This function verifies the encoding parameters whether they meet the requirement
+    for a specific level. If the level is not set, it will just find the closest
+    level instead of verifying it.
+    \param "video"  "Pointer to AVCEncObject."
+    \param "seqParam"   "Pointer to AVCSeqParamSet."
+    \param "picParam"   "Pointer to AVCPicParamSet."
+    \return "AVCENC_SUCCESS if success,
+            AVCENC_LEVEL_NOT_SUPPORTED if the specified level
+                is not supported by this version of the library,
+            AVCENC_LEVEL_FAIL if any of the encoding parameters exceed
+            the range of the user-selected level."
+    */
+    AVCEnc_Status VerifyLevel(AVCEncObject *video, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam);
+
+    /**
+    This funciton initializes the frame encoding by setting poc/frame_num related parameters. it
+    also performs motion estimation.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \return "AVCENC_SUCCESS if success, AVCENC_NO_PICTURE if there is no input picture
+            in the queue to encode, AVCENC_POC_FAIL or AVCENC_CONSECUTIVE_NONREF for POC
+            related errors, AVCENC_NEW_IDR if new IDR is detected."
+    */
+    AVCEnc_Status InitFrame(AVCEncObject *encvid);
+
+    /**
+    This function initializes slice header related variables and other variables necessary
+    for decoding one slice.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \return "AVCENC_SUCCESS if success."
+    */
+    AVCEnc_Status InitSlice(AVCEncObject *encvid);
+
+    /*----------- header.c ----------------*/
+    /**
+    This function performs bitstream encoding of the sequence parameter set NAL.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \return "AVCENC_SUCCESS if success or AVCENC_SPS_FAIL or others for unexpected failure which
+    should not occur. The SPS parameters should all be verified before this function is called."
+    */
+    AVCEnc_Status EncodeSPS(AVCEncObject *encvid, AVCEncBitstream *stream);
+
+    /**
+    This function encodes the VUI parameters into the sequence parameter set bitstream.
+    \param "stream" "Pointer to AVCEncBitstream."
+    \param "vui"    "Pointer to AVCVUIParams."
+    \return "nothing."
+    */
+    void EncodeVUI(AVCEncBitstream* stream, AVCVUIParams* vui);
+
+    /**
+    This function encodes HRD parameters into the sequence parameter set bitstream
+    \param "stream" "Pointer to AVCEncBitstream."
+    \param "hrd"    "Pointer to AVCHRDParams."
+    \return "nothing."
+    */
+    void EncodeHRD(AVCEncBitstream* stream, AVCHRDParams* hrd);
+
+
+    /**
+    This function performs bitstream encoding of the picture parameter set NAL.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \return "AVCENC_SUCCESS if success or AVCENC_PPS_FAIL or others for unexpected failure which
+    should not occur. The SPS parameters should all be verified before this function is called."
+    */
+    AVCEnc_Status EncodePPS(AVCEncObject *encvid, AVCEncBitstream *stream);
+
+    /**
+    This function encodes slice header information which has been initialized or fabricated
+    prior to entering this funciton.
+    \param "encvid" "Pointer to the AVCEncObject."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \return "AVCENC_SUCCESS if success or bitstream fail statuses."
+    */
+    AVCEnc_Status EncodeSliceHeader(AVCEncObject *encvid, AVCEncBitstream *stream);
+
+    /**
+    This function encodes reference picture list reordering relted syntax.
+    \param "video" "Pointer to AVCCommonObj."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \param "sliceHdr" "Pointer to AVCSliceHdr."
+    \param "slice_type" "Value of slice_type - 5 if greater than 5."
+    \return "AVCENC_SUCCESS for success and AVCENC_FAIL otherwise."
+    */
+    AVCEnc_Status ref_pic_list_reordering(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr, int slice_type);
+
+    /**
+    This function encodes dec_ref_pic_marking related syntax.
+    \param "video" "Pointer to AVCCommonObj."
+    \param "stream" "Pointer to AVCEncBitstream."
+    \param "sliceHdr" "Pointer to AVCSliceHdr."
+    \return "AVCENC_SUCCESS for success and AVCENC_FAIL otherwise."
+    */
+    AVCEnc_Status dec_ref_pic_marking(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr);
+
+    /**
+    This function initializes the POC related variables and the POC syntax to be encoded
+    to the slice header derived from the disp_order and is_reference flag of the original
+    input frame to be encoded.
+    \param "video"  "Pointer to the AVCEncObject."
+    \return "AVCENC_SUCCESS if success,
+            AVCENC_POC_FAIL if the poc type is undefined or
+            AVCENC_CONSECUTIVE_NONREF if there are consecutive non-reference frame for POC type 2."
+    */
+    AVCEnc_Status InitPOC(AVCEncObject *video);
+
+    /**
+    This function performs POC related operation after a picture is decoded.
+    \param "video" "Pointer to AVCCommonObj."
+    \return "AVCENC_SUCCESS"
+    */
+    AVCEnc_Status PostPOC(AVCCommonObj *video);
+
+    /*----------- bitstream_io.c ----------------*/
+    /**
+    This function initializes the bitstream structure with the information given by
+    the users.
+    \param "bitstream"  "Pointer to the AVCEncBitstream structure."
+    \param "buffer"     "Pointer to the unsigned char buffer for output."
+    \param "buf_size"   "The size of the buffer in bytes."
+    \param "overrunBuffer"  "Pointer to extra overrun buffer."
+    \param "oBSize"     "Size of overrun buffer in bytes."
+    \return "AVCENC_SUCCESS if success, AVCENC_BITSTREAM_INIT_FAIL if fail"
+    */
+    AVCEnc_Status BitstreamEncInit(AVCEncBitstream *bitstream, uint8 *buffer, int buf_size,
+                                   uint8 *overrunBuffer, int oBSize);
+
+    /**
+    This function writes the data from the cache into the bitstream buffer. It also adds the
+    emulation prevention code if necessary.
+    \param "stream"     "Pointer to the AVCEncBitstream structure."
+    \return "AVCENC_SUCCESS if success or AVCENC_BITSTREAM_BUFFER_FULL if fail."
+    */
+    AVCEnc_Status AVCBitstreamSaveWord(AVCEncBitstream *stream);
+
+    /**
+    This function writes the codeword into the cache which will eventually be written to
+    the bitstream buffer.
+    \param "stream"     "Pointer to the AVCEncBitstream structure."
+    \param "nBits"      "Number of bits in the codeword."
+    \param "code"       "The codeword."
+    \return "AVCENC_SUCCESS if success or AVCENC_BITSTREAM_BUFFER_FULL if fail."
+    */
+    AVCEnc_Status BitstreamWriteBits(AVCEncBitstream *stream, int nBits, uint code);
+
+    /**
+    This function writes one bit of data into the cache which will eventually be written
+    to the bitstream buffer.
+    \param "stream"     "Pointer to the AVCEncBitstream structure."
+    \param "code"       "The codeword."
+    \return "AVCENC_SUCCESS if success or AVCENC_BITSTREAM_BUFFER_FULL if fail."
+    */
+    AVCEnc_Status BitstreamWrite1Bit(AVCEncBitstream *stream, uint code);
+
+    /**
+    This function adds trailing bits to the bitstream and reports back the final EBSP size.
+    \param "stream"     "Pointer to the AVCEncBitstream structure."
+    \param "nal_size"   "Output the final NAL size."
+    \return "AVCENC_SUCCESS if success or AVCENC_BITSTREAM_BUFFER_FULL if fail."
+    */
+    AVCEnc_Status BitstreamTrailingBits(AVCEncBitstream *bitstream, uint *nal_size);
+
+    /**
+    This function checks whether the current bit position is byte-aligned or not.
+    \param "stream" "Pointer to the bitstream structure."
+    \return "true if byte-aligned, false otherwise."
+    */
+    bool byte_aligned(AVCEncBitstream *stream);
+
+
+    /**
+    This function checks the availability of overrun buffer and switches to use it when
+    normal bufffer is not big enough.
+    \param "stream" "Pointer to the bitstream structure."
+    \param "numExtraBytes" "Number of extra byte needed."
+    \return "AVCENC_SUCCESS or AVCENC_FAIL."
+    */
+    AVCEnc_Status AVCBitstreamUseOverrunBuffer(AVCEncBitstream* stream, int numExtraBytes);
+
+
+    /*-------------- intra_est.c ---------------*/
+
+    /** This function performs intra/inter decision based on ABE.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "min_cost"   "Best inter cost."
+    \param "curL"   "Pointer to the current MB origin in reconstructed frame."
+    \param "picPitch" "Pitch of the reconstructed frame."
+    \return "Boolean for intra mode."
+    */
+
+//bool IntraDecisionABE(AVCEncObject *encvid, int min_cost, uint8 *curL, int picPitch);
+    bool IntraDecision(int *min_cost, uint8 *cur, int pitch, bool ave);
+
+    /**
+    This function performs intra prediction mode search.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "mbnum"  "Current MB number."
+    \param "curL"   "Pointer to the current MB origin in reconstructed frame."
+    \param "picPitch" "Pitch of the reconstructed frame."
+    \return "void."
+    */
+    void MBIntraSearch(AVCEncObject *encvid, int mbnum, uint8 *curL, int picPitch);
+
+    /**
+    This function generates all the I16 prediction modes for an MB and keep it in
+    encvid->pred_i16.
+    \param "encvid" "Pointer to AVCEncObject."
+    \return "void"
+    */
+    void intrapred_luma_16x16(AVCEncObject *encvid);
+
+    /**
+    This function calculate the cost of all I16 modes and compare them to get the minimum.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "orgY"   "Pointer to the original luma MB."
+    \param "min_cost" "Pointer to the minimal cost so-far."
+    \return "void"
+    */
+    void find_cost_16x16(AVCEncObject *encvid, uint8 *orgY, int *min_cost);
+
+    /**
+    This function calculates the cost of each I16 mode.
+    \param "org"    "Pointer to the original luma MB."
+    \param "org_pitch" "Stride size of the original frame."
+    \param "pred"   "Pointer to the prediction values."
+    \param "min_cost" "Minimal cost so-far."
+    \return "Cost"
+    */
+
+    int cost_i16(uint8 *org, int org_pitch, uint8 *pred, int min_cost);
+
+    /**
+    This function generates all the I4 prediction modes and select the best one
+    for all the blocks inside a macroblock.It also calls dct_luma to generate the reconstructed
+    MB, and transform coefficients to be encoded.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "min_cost" "Pointer to the minimal cost so-far."
+    \return "void"
+    */
+    void mb_intra4x4_search(AVCEncObject *encvid, int *min_cost);
+
+    /**
+    This function calculates the most probable I4 mode of a given 4x4 block
+    from neighboring informationaccording to AVC/H.264 standard.
+    \param "video"  "Pointer to AVCCommonObj."
+    \param "blkidx" "The current block index."
+    \return "Most probable mode."
+    */
+    int FindMostProbableI4Mode(AVCCommonObj *video, int blkidx);
+
+    /**
+    This function is where a lot of actions take place in the 4x4 block level inside
+    mb_intra4x4_search.
+    \param "encvid" "Pointer to AVCEncObject."
+    \param "blkidx" "The current 4x4 block index."
+    \param "cur"    "Pointer to the reconstructed block."
+    \param "org"    "Pointer to the original block."
+    \return "Minimal cost, also set currMB->i4Mode"
+    */
+    int blk_intra4x4_search(AVCEncObject *encvid, int blkidx, uint8 *cur, uint8 *org);
+
+    /**
+    This function calculates the cost of a given I4 prediction mode.
+    \param "org"    "Pointer to the original block."
+    \param "org_pitch"  "Stride size of the original frame."
+    \param "pred"   "Pointer to the prediction block. (encvid->pred_i4)"
+    \param "cost"   "Pointer to the minimal cost (to be updated)."
+    \return "void"
+    */
+    void cost_i4(uint8 *org, int org_pitch, uint8 *pred, uint16 *cost);
+
+    /**
+    This function performs chroma intra search. Each mode is saved in encvid->pred_ic.
+    \param "encvid" "Pointer to AVCEncObject."
+    \return "void"
+    */
+    void chroma_intra_search(AVCEncObject *encvid);
+
+    /**
+    This function calculates the cost of a chroma prediction mode.
+    \param "orgCb"  "Pointer to the original Cb block."
+    \param "orgCr"  "Pointer to the original Cr block."
+    \param "org_pitch"  "Stride size of the original frame."
+    \param "pred"   "Pointer to the prediction block (encvid->pred_ic)"
+    \param "mincost"    "Minimal cost so far."
+    \return "Cost."
+    */
+
+    int SATDChroma(uint8 *orgCb, uint8 *orgCr, int org_pitch, uint8 *pred, int mincost);
+
+    /*-------------- motion_comp.c ---------------*/
+
+    /**
+    This is a main function to peform inter prediction.
+    \param "encvid"     "Pointer to AVCEncObject."
+    \param "video"      "Pointer to AVCCommonObj."
+    \return "void".
+    */
+    void AVCMBMotionComp(AVCEncObject *encvid, AVCCommonObj *video);
+
+
+    /**
+    This function is called for luma motion compensation.
+    \param "ref"    "Pointer to the origin of a reference luma."
+    \param "picwidth"   "Width of the picture."
+    \param "picheight"  "Height of the picture."
+    \param "x_pos"  "X-coordinate of the predicted block in quarter pel resolution."
+    \param "y_pos"  "Y-coordinate of the predicted block in quarter pel resolution."
+    \param "pred"   "Pointer to the output predicted block."
+    \param "pred_pitch" "Width of pred."
+    \param "blkwidth"   "Width of the current partition."
+    \param "blkheight"  "Height of the current partition."
+    \return "void"
+    */
+    void eLumaMotionComp(uint8 *ref, int picwidth, int picheight,
+                         int x_pos, int y_pos,
+                         uint8 *pred, int pred_pitch,
+                         int blkwidth, int blkheight);
+
+    void eFullPelMC(uint8 *in, int inwidth, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight);
+
+    void eHorzInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                        int blkwidth, int blkheight, int dx);
+
+    void eHorzInterp2MC(int *in, int inpitch, uint8 *out, int outpitch,
+                        int blkwidth, int blkheight, int dx);
+
+    void eHorzInterp3MC(uint8 *in, int inpitch, int *out, int outpitch,
+                        int blkwidth, int blkheight);
+
+    void eVertInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                        int blkwidth, int blkheight, int dy);
+
+    void eVertInterp2MC(uint8 *in, int inpitch, int *out, int outpitch,
+                        int blkwidth, int blkheight);
+
+    void eVertInterp3MC(int *in, int inpitch, uint8 *out, int outpitch,
+                        int blkwidth, int blkheight, int dy);
+
+    void eDiagonalInterpMC(uint8 *in1, uint8 *in2, int inpitch,
+                           uint8 *out, int outpitch,
+                           int blkwidth, int blkheight);
+
+    void eChromaMotionComp(uint8 *ref, int picwidth, int picheight,
+                           int x_pos, int y_pos, uint8 *pred, int pred_pitch,
+                           int blkwidth, int blkheight);
+
+    void eChromaDiagonalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaHorizontalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                  uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaVerticalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaFullMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                            uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaVerticalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                 uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaHorizontalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                   uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+    void eChromaDiagonalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                                 uint8 *pOut, int predPitch, int blkwidth, int blkheight);
+
+
+    /*-------------- motion_est.c ---------------*/
+
+    /**
+    Allocate and initialize arrays necessary for motion search algorithm.
+    \param "envid" "Pointer to AVCEncObject."
+    \return "AVC_SUCCESS or AVC_MEMORY_FAIL."
+    */
+    AVCEnc_Status InitMotionSearchModule(AVCHandle *avcHandle);
+
+    /**
+    Clean up memory allocated in InitMotionSearchModule.
+    \param "envid" "Pointer to AVCEncObject."
+    \return "void."
+    */
+    void CleanMotionSearchModule(AVCHandle *avcHandle);
+
+
+    /**
+    This function performs motion estimation of all macroblocks in a frame during the InitFrame.
+    The goal is to find the best MB partition for inter and find out if intra search is needed for
+    any MBs. This intra MB tendency can be used for scene change detection.
+    \param "encvid" "Pointer to AVCEncObject."
+    \return "void"
+    */
+    void AVCMotionEstimation(AVCEncObject *encvid);
+
+    /**
+    This function performs repetitive edge padding to the reference picture by adding 16 pixels
+    around the luma and 8 pixels around the chromas.
+    \param "refPic" "Pointer to the reference picture."
+    \return "void"
+    */
+    void  AVCPaddingEdge(AVCPictureData *refPic);
+
+    /**
+    This function keeps track of intra refresh macroblock locations.
+    \param "encvid" "Pointer to the global array structure AVCEncObject."
+    \param "mblock" "Pointer to the array of AVCMacroblock structures."
+    \param "totalMB" "Total number of MBs in a frame."
+    \param "numRefresh" "Number of MB to be intra refresh in a single frame."
+    \return "void"
+    */
+    void AVCRasterIntraUpdate(AVCEncObject *encvid, AVCMacroblock *mblock, int totalMB, int numRefresh);
+
+#ifdef HTFM
+    void InitHTFM(VideoEncData *encvid, HTFM_Stat *htfm_stat, double *newvar, int *collect);
+    void UpdateHTFM(AVCEncObject *encvid, double *newvar, double *exp_lamda, HTFM_Stat *htfm_stat);
+    void CalcThreshold(double pf, double exp_lamda[], int nrmlz_th[]);
+    void    HTFMPrepareCurMB_AVC(AVCEncObject *encvid, HTFM_Stat *htfm_stat, uint8 *cur, int pitch);
+#endif
+
+    /**
+    This function reads the input MB into a smaller faster memory space to minimize the cache miss.
+    \param "encvid" "Pointer to the global AVCEncObject."
+    \param "cur"    "Pointer to the original input macroblock."
+    \param "pitch"  "Stride size of the input frame (luma)."
+    \return "void"
+    */
+    void    AVCPrepareCurMB(AVCEncObject *encvid, uint8 *cur, int pitch);
+
+    /**
+    Performs motion vector search for a macroblock.
+    \param "encvid" "Pointer to AVCEncObject structure."
+    \param "cur"    "Pointer to the current macroblock in the input frame."
+    \param "best_cand" "Array of best candidates (to be filled in and returned)."
+    \param "i0"     "X-coordinate of the macroblock."
+    \param "j0"     "Y-coordinate of the macroblock."
+    \param "type_pred" "Indicates the type of operations."
+    \param "FS_en"      "Flag for fullsearch enable."
+    \param "hp_guess"   "Guess for half-pel search."
+    \return "void"
+    */
+    void AVCMBMotionSearch(AVCEncObject *encvid, uint8 *cur, uint8 *best_cand[],
+                           int i0, int j0, int type_pred, int FS_en, int *hp_guess);
+
+//AVCEnc_Status AVCMBMotionSearch(AVCEncObject *encvid, AVCMacroblock *currMB, int mbNum,
+//                           int num_pass);
+
+    /**
+    Perform full-pel exhaustive search around the predicted MV.
+    \param "encvid" "Pointer to AVCEncObject structure."
+    \param "prev"   "Pointer to the reference frame."
+    \param "cur"    "Pointer to the input macroblock."
+    \param "imin"   "Pointer to minimal mv (x)."
+    \param "jmin"   "Pointer to minimal mv (y)."
+    \param "ilow, ihigh, jlow, jhigh"   "Lower bound on search range."
+    \param "cmvx, cmvy" "Predicted MV value."
+
+    \return "The cost function of the best candidate."
+    */
+    int AVCFullSearch(AVCEncObject *encvid, uint8 *prev, uint8 *cur,
+                      int *imin, int *jmin, int ilow, int ihigh, int jlow, int jhigh,
+                      int cmvx, int cmvy);
+
+    /**
+    Select candidates from neighboring blocks according to the type of the
+    prediction selection.
+    \param "mvx"    "Pointer to the candidate, x-coordinate."
+    \param "mvy"    "Pointer to the candidate, y-coordinate."
+    \param "num_can"    "Pointer to the number of candidates returned."
+    \param "imb"    "The MB index x-coordinate."
+    \param "jmb"    "The MB index y-coordinate."
+    \param "type_pred"  "Type of the prediction."
+    \param "cmvx, cmvy" "Pointer to predicted MV (modified version)."
+    \return "void."
+    */
+    void AVCCandidateSelection(int *mvx, int *mvy, int *num_can, int imb, int jmb,
+                               AVCEncObject *encvid, int type_pred, int *cmvx, int *cmvy);
+
+    /**
+    Utility function to move the values in the array dn according to the new
+    location to avoid redundant calculation.
+    \param "dn" "Array of integer of size 9."
+    \param "new_loc"    "New location index."
+    \return "void."
+    */
+    void AVCMoveNeighborSAD(int dn[], int new_loc);
+
+    /**
+    Find minimum index of dn.
+    \param "dn" "Array of integer of size 9."
+    \return "The index of dn with the smallest dn[] value."
+    */
+    int AVCFindMin(int dn[]);
+
+
+    /*------------- findhalfpel.c -------------------*/
+
+    /**
+    Search for the best half-pel resolution MV around the full-pel MV.
+    \param "encvid" "Pointer to the global AVCEncObject structure."
+    \param "cur"    "Pointer to the current macroblock."
+    \param "mot"    "Pointer to the AVCMV array of the frame."
+    \param "ncand"  "Pointer to the origin of the fullsearch result."
+    \param "xpos"   "The current MB position in x."
+    \param "ypos"   "The current MB position in y."
+    \param "hp_guess"   "Input to help speedup the search."
+    \param "cmvx, cmvy" "Predicted motion vector use for mvcost."
+    \return "Minimal cost (SATD) without MV cost. (for rate control purpose)"
+    */
+    int AVCFindHalfPelMB(AVCEncObject *encvid, uint8 *cur, AVCMV *mot, uint8 *ncand,
+                         int xpos, int ypos, int hp_guess, int cmvx, int cmvy);
+
+    /**
+    This function generates sub-pel pixels required to do subpel MV search.
+    \param "subpel_pred" "Pointer to 2-D array, each array for each position."
+    \param "ncand" "Pointer to the full-pel center position in ref frame."
+    \param "lx" "Pitch of the ref frame."
+    \return "void"
+     */
+    void GenerateHalfPelPred(uint8 *subpel_pred, uint8 *ncand, int lx);
+
+    /**
+    This function calculate vertical interpolation at half-point of size 4x17.
+    \param "dst" "Pointer to destination."
+    \param "ref" "Pointer to the starting reference pixel."
+    \return "void."
+    */
+    void VertInterpWClip(uint8 *dst, uint8 *ref);
+
+    /**
+    This function generates quarter-pel pixels around the best half-pel result
+    during the sub-pel MV search.
+    \param "bilin_base"  "Array of pointers to be used as basis for q-pel interp."
+    \param "qpel_pred"  "Array of pointers pointing to quarter-pel candidates."
+    \param "hpel_pos" "Best half-pel position at the center."
+    \return "void"
+    */
+    void GenerateQuartPelPred(uint8 **bilin_base, uint8 *qpel_pred, int hpel_pos);
+
+    /**
+    This function calculates the SATD of a subpel candidate.
+    \param "cand"   "Pointer to a candidate."
+    \param "cur"    "Pointer to the current block."
+    \param "dmin"   "Min-so-far SATD."
+    \return "Sum of Absolute Transformed Difference."
+    */
+    int SATD_MB(uint8 *cand, uint8 *cur, int dmin);
+
+    /*------------- rate_control.c -------------------*/
+
+    /** This function is a utility function. It returns average QP of the previously encoded frame.
+    \param "rateCtrl" "Pointer to AVCRateControl structure."
+    \return "Average QP."
+    */
+    int GetAvgFrameQP(AVCRateControl *rateCtrl);
+
+    /**
+    This function takes the timestamp of the input and determine whether it should be encoded
+    or skipped.
+    \param "encvid" "Pointer to the AVCEncObject structure."
+    \param "rateCtrl"   "Pointer to the AVCRateControl structure."
+    \param "modTime"    "The 32 bit timestamp of the input frame."
+    \param "frameNum"   "Pointer to the frame number if to be encoded."
+    \return "AVC_SUCCESS or else."
+    */
+    AVCEnc_Status RCDetermineFrameNum(AVCEncObject *encvid, AVCRateControl *rateCtrl, uint32 modTime, uint *frameNum);
+
+    /**
+    This function updates the buffer fullness when frames are dropped either by the
+    rate control algorithm or by the users to make sure that target bit rate is still met.
+    \param "video" "Pointer to the common object structure."
+    \param "rateCtrl" "Pointer to rate control structure."
+    \param "frameInc" "Difference of the current frame number and previous frame number."
+    \return "void."
+    */
+    void RCUpdateBuffer(AVCCommonObj *video, AVCRateControl *rateCtrl, int frameInc);
+
+    /**
+    This function initializes rate control module and allocates necessary bufferes to do the job.
+    \param "avcHandle" "Pointer to the encoder handle."
+    \return "AVCENC_SUCCESS or AVCENC_MEMORY_FAIL."
+    */
+    AVCEnc_Status InitRateControlModule(AVCHandle *avcHandle);
+
+    /**
+    This function frees buffers allocated in InitRateControlModule.
+    \param "avcHandle" "Pointer to the encoder handle."
+    \return "void."
+    */
+    void CleanupRateControlModule(AVCHandle *avcHandle);
+
+    /**
+    This function is called at the beginning of each GOP or the first IDR frame. It calculates
+    target bits for a GOP.
+    \param "encvid" "Pointer to the encoder object."
+    \return "void."
+    */
+    void RCInitGOP(AVCEncObject *encvid);
+
+    /**
+    This function calculates target bits for a particular frame.
+    \param "video"  "Pointer to the AVCEncObject structure."
+    \return "void"
+    */
+    void RCInitFrameQP(AVCEncObject *video);
+
+    /**
+    This function calculates QP for the upcoming frame or basic unit.
+    \param "encvid" "Pointer to the encoder object."
+    \param "rateCtrl" "Pointer to the rate control object."
+    \return "QP value ranging from 0-51."
+    */
+    int  RCCalculateQP(AVCEncObject *encvid, AVCRateControl *rateCtrl);
+
+    /**
+    This function translates the luma QP to chroma QP and calculates lambda based on QP.
+    \param "video"  "Pointer to the AVCEncObject structure."
+    \return "void"
+    */
+    void RCInitChromaQP(AVCEncObject *encvid);
+
+    /**
+    This function is called before encoding each macroblock.
+    \param "encvid" "Pointer to the encoder object."
+    \return "void."
+    */
+    void RCInitMBQP(AVCEncObject *encvid);
+
+    /**
+    This function updates bits usage stats after encoding an macroblock.
+    \param "video" "Pointer to AVCCommonObj."
+    \param "rateCtrl" "Pointer to AVCRateControl."
+    \param "num_header_bits" "Number of bits used for MB header."
+    \param "num_texture_bits" "Number of bits used for MB texture."
+    \return "void"
+    */
+    void RCPostMB(AVCCommonObj *video, AVCRateControl *rateCtrl, int num_header_bits, int num_texture_bits);
+
+    /**
+    This function calculates the difference between prediction and original MB.
+    \param "encvid" "Pointer to the encoder object."
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "orgL" "Pointer to the original MB."
+    \param "orgPitch" "Pointer to the original picture pitch."
+    \return "void."
+    */
+    void RCCalculateMAD(AVCEncObject *encvid, AVCMacroblock *currMB, uint8 *orgL, int orgPitch);
+
+    /**
+    Restore QP related parameters of previous MB when current MB is skipped.
+    \param "currMB" "Pointer to the current macroblock."
+    \param "video"  "Pointer to the common video structure."
+    \param "encvid" "Pointer to the global encoding structure."
+    \return "void"
+    */
+    void RCRestoreQP(AVCMacroblock *currMB, AVCCommonObj *video, AVCEncObject *encvid);
+
+    /**
+    This function is called after done with a frame.
+    \param "encvid" "Pointer to the encoder object."
+    \return "AVCENC_SUCCESS or AVCENC_SKIPPED_PICTURE when bufer overflow (need to discard current frame)."
+    */
+    AVCEnc_Status RCUpdateFrame(AVCEncObject *encvid);
+
+    /*--------- residual.c -------------------*/
+
+    /**
+    This function encodes the intra pcm data and fill it in the corresponding location
+    on the current picture.
+    \param "video"  "Pointer to AVCEncObject."
+    \return "AVCENC_SUCCESS if success, or else for bitstream errors."
+    */
+    AVCEnc_Status EncodeIntraPCM(AVCEncObject *video);
+
+    /**
+    This function performs CAVLC syntax encoding on the run and level information of the coefficients.
+    The level and run arrays are elements in AVCEncObject structure, populated by TransQuantZZ,
+    TransQuantIntraDC and TransQuantChromaDC functions.
+    \param "video"  "Pointer to AVCEncObject."
+    \param "type"   "One of AVCResidualType for a particular 4x4 block."
+    \param "bindx"  "Block index or number of nonzero coefficients for AVC_Intra16DC and AVC_ChromaDC mode."
+    \param "currMB" "Pointer to the current macroblock structure."
+    \return "AVCENC_SUCCESS for success."
+    \Note   "This function has 32-bit machine specific instruction!!!!"
+    */
+    AVCEnc_Status enc_residual_block(AVCEncObject *encvid, AVCResidualType type, int bindx, AVCMacroblock *currMB);
+
+
+    /*------------- sad.c ---------------------------*/
+
+
+    int AVCSAD_MB_HalfPel_Cxhyh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HalfPel_Cyh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HalfPel_Cxh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_Macroblock_C(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+
+#ifdef HTFM /*  3/2/1, Hypothesis Testing Fast Matching */
+    int AVCSAD_MB_HP_HTFM_Collectxhyh(uint8 *ref, uint8 *blk, int dmin_x, void *extra_info);
+    int AVCSAD_MB_HP_HTFM_Collectyh(uint8 *ref, uint8 *blk, int dmin_x, void *extra_info);
+    int AVCSAD_MB_HP_HTFM_Collectxh(uint8 *ref, uint8 *blk, int dmin_x, void *extra_info);
+    int AVCSAD_MB_HP_HTFMxhyh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HP_HTFMyh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HP_HTFMxh(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HTFM_Collect(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+    int AVCSAD_MB_HTFM(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info);
+#endif
+
+
+    /*------------- slice.c -------------------------*/
+
+    /**
+    This function performs the main encoding loop for a slice.
+    \param "encvid" "Pointer to AVCEncObject."
+    \return "AVCENC_SUCCESS for success, AVCENC_PICTURE_READY for end-of-picture and
+             AVCENC_FAIL or AVCENC_SLICE_EMPTY otherwise."
+    */
+    AVCEnc_Status AVCEncodeSlice(AVCEncObject *encvid);
+
+    /**
+    This function performs the main encoding operation for one macroblock.
+    \param "video" "pointer to AVCEncObject."
+    \return "AVCENC_SUCCESS for success, or other bitstream related failure status."
+    */
+    AVCEnc_Status EncodeMB(AVCEncObject *video);
+
+    /**
+    This function calls prediction INTRA/INTER functions, transform,
+    quantization and zigzag scanning to get the run-level symbols.
+    \param "encvid" "pointer to AVCEncObject."
+    \param "curL"   "pointer to Luma component of the current frame.
+    \param "curCb"  "pointer to Cb component of the current frame.
+    \param "curCr"  "pointer to Cr component of the current frame.
+    \return "void for now."
+     */
+    void MBPredTransQuantZZ(AVCEncObject *encvid, uint8 *curL, uint8 *curCb, uint8 *curCr);
+
+    /**
+    This function copies the content of the prediction MB into the reconstructed YUV
+    frame directly.
+    \param "curL"   "Pointer to the destination Y component."
+    \param "curCb"  "Pointer to the destination Cb component."
+    \param "curCr"  "Pointer to the destination Cr component."
+    \param "predBlock"  "Pointer to the prediction MB."
+    \param "picWidth"   "The width of the frame."
+    \return "None."
+    */
+    void Copy_MB(uint8 *curL, uint8 *curCb, uint8 *curCr, uint8 *predBlock, int picWidth);
+
+    /**
+    This function encodes the mb_type, CBP, prediction mode, ref idx and MV.
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "video" "Pointer to the AVCEncObject structure."
+    \return "AVCENC_SUCCESS for success or else for fail."
+    */
+    AVCEnc_Status EncodeMBHeader(AVCMacroblock *currMB, AVCEncObject *video);
+
+    /**
+    This function finds the right mb_type for a macroblock given the mbMode, CBP,
+    NumPart, PredPartMode.
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "slice_type" "Value of the slice_type."
+    \return "mb_type."
+    */
+    uint InterpretMBType(AVCMacroblock *currMB, int slice_type);
+
+    /**
+    This function encodes the mb_pred part of the macroblock data.
+    \param "video"  "Pointer to the AVCCommonObj structure."
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "stream" "Pointer to the AVCEncBitstream structure."
+    \return "AVCENC_SUCCESS for success or bitstream fail status."
+    */
+    AVCEnc_Status mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream);
+
+    /**
+    This function encodes the sub_mb_pred part of the macroblock data.
+    \param "video"  "Pointer to the AVCCommonObj structure."
+    \param "currMB" "Pointer to the current macroblock structure."
+    \param "stream" "Pointer to the AVCEncBitstream structure."
+    \return "AVCENC_SUCCESS for success or bitstream fail status."
+    */
+    AVCEnc_Status sub_mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream);
+
+    /**
+    This function interprets the sub_mb_type and sets necessary information
+    when the slice type is AVC_P_SLICE.
+    in the macroblock structure.
+    \param "mblock" "Pointer to current AVCMacroblock."
+    \param "sub_mb_type" "From the syntax bitstream."
+    \return "void"
+    */
+    void InterpretSubMBTypeP(AVCMacroblock *mblock, uint *sub_mb_type);
+
+    /**
+    This function interprets the sub_mb_type and sets necessary information
+    when the slice type is AVC_B_SLICE.
+    in the macroblock structure.
+    \param "mblock" "Pointer to current AVCMacroblock."
+    \param "sub_mb_type" "From the syntax bitstream."
+    \return "void"
+    */
+    void InterpretSubMBTypeB(AVCMacroblock *mblock, uint *sub_mb_type);
+
+    /**
+    This function encodes intra 4x4 mode. It calculates the predicted I4x4 mode and the
+    remnant to be encoded.
+    \param "video"  "Pointer to AVCEncObject structure."
+    \param "currMB" "Pointer to the AVCMacroblock structure."
+    \param "stream" "Pointer to AVCEncBitstream sructure."
+    \return "AVCENC_SUCCESS for success."
+    */
+    AVCEnc_Status EncodeIntra4x4Mode(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream);
+
+    /*------------- vlc_encode.c -----------------------*/
+    /**
+    This function encodes and writes a value into an Exp-Golomb codeword.
+    \param "bitstream" "Pointer to AVCEncBitstream."
+    \param "codeNum" "Pointer to the value of the codeNum."
+    \return "AVCENC_SUCCESS for success or bitstream error messages for fail."
+    */
+    AVCEnc_Status ue_v(AVCEncBitstream *bitstream, uint codeNum);
+
+    /**
+    This function maps and encodes signed Exp-Golomb codes.
+    \param "bitstream" "Pointer to AVCEncBitstream."
+    \param "value"  "Pointer to syntax element value."
+    \return "AVCENC_SUCCESS or AVCENC_FAIL."
+    */
+    AVCEnc_Status  se_v(AVCEncBitstream *bitstream, int value);
+
+    /**
+    This function maps and encodes truncated Exp-Golomb codes.
+    \param "bitstream" "Pointer to AVCEncBitstream."
+    \param "value"  "Pointer to syntax element value."
+    \param "range"  "Range of the value as input to determine the algorithm."
+    \return "AVCENC_SUCCESS or AVCENC_FAIL."
+    */
+    AVCEnc_Status te_v(AVCEncBitstream *bitstream, uint value, uint range);
+
+    /**
+    This function creates Exp-Golomb codeword from codeNum.
+    \param "bitstream" "Pointer to AVCEncBitstream."
+    \param "codeNum" "Pointer to the codeNum value."
+    \return "AVCENC_SUCCESS for success or bitstream error messages for fail."
+    */
+    AVCEnc_Status SetEGBitstring(AVCEncBitstream *bitstream, uint codeNum);
+
+    /**
+    This function performs CAVLC encoding of the CBP (coded block pattern) of a macroblock
+    by calling ue_v() and then mapping the CBP to the corresponding VLC codeNum.
+    \param "currMB"  "Pointer to the current AVCMacroblock structure."
+    \param "stream"  "Pointer to the AVCEncBitstream."
+    \return "void"
+    */
+    AVCEnc_Status EncodeCBP(AVCMacroblock *currMB, AVCEncBitstream *stream);
+
+    /**
+    This function encodes trailing ones and total coefficient.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "TrailingOnes"   "The trailing one variable output."
+    \param "TotalCoeff" "The total coefficient variable output."
+    \param "nC" "Context for number of nonzero coefficient (prediction context)."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_TotalCoeffTrailingOnes(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff, int nC);
+
+    /**
+    This function encodes trailing ones and total coefficient for chroma DC block.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "TrailingOnes"   "The trailing one variable output."
+    \param "TotalCoeff" "The total coefficient variable output."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_TotalCoeffTrailingOnesChromaDC(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff);
+
+    /**
+    This function encodes total_zeros value as in Table 9-7 and 9-8.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "TotalZeros" "The total_zeros value."
+    \param "TotalCoeff" "The total coefficient variable output."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_TotalZeros(AVCEncBitstream *stream, int total_zeros, int TotalCoeff);
+
+    /**
+    This function encodes total_zeros VLC syntax for chroma DC as in Table 9-9.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "TotalZeros" "The total_zeros value."
+    \param "TotalCoeff" "The total coefficient variable output."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_TotalZerosChromaDC(AVCEncBitstream *stream, int total_zeros, int TotalCoeff);
+
+    /**
+    This function encodes run_before VLC syntax as in Table 9-10.
+    \param "stream" "Pointer to the AVCEncBitstream."
+    \param "run_before" "The run_before value."
+    \param "zerosLeft"  "The context for number of zeros left."
+    \return "AVCENC_SUCCESS for success or else for bitstream failure."
+    */
+    AVCEnc_Status ce_RunBefore(AVCEncBitstream *stream, int run_before, int zerosLeft);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _AVCENC_LIB_H_ */
+
diff --git a/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp b/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
new file mode 100644
index 0000000..75ab514
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
@@ -0,0 +1,336 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+
+#define WORD_SIZE 32
+
+/* array for trailing bit pattern as function of number of bits */
+/* the first one is unused. */
+const static uint8 trailing_bits[9] = {0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
+
+/* ======================================================================== */
+/*  Function : BitstreamInit()                                              */
+/*  Date     : 11/4/2003                                                    */
+/*  Purpose  : Populate bitstream structure with bitstream buffer and size  */
+/*             it also initializes internal data                            */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_FAIL if failed.              */
+/*  Modified :                                                              */
+/* ======================================================================== */
+/* |--------|--------|----~~~~~-----|---------|---------|---------|
+   ^                                          ^write_pos          ^buf_size
+   bitstreamBuffer                  <--------->
+                                    current_word
+
+   |-----xxxxxxxxxxxxx|  = current_word 32 or 16 bits
+    <---->
+     bit_left
+ ======================================================================== */
+
+AVCEnc_Status BitstreamEncInit(AVCEncBitstream *stream, uint8 *buffer, int buf_size,
+                               uint8 *overrunBuffer, int oBSize)
+{
+    if (stream == NULL || buffer == NULL || buf_size <= 0)
+    {
+        return AVCENC_BITSTREAM_INIT_FAIL;
+    }
+
+    stream->bitstreamBuffer = buffer;
+
+    stream->buf_size = buf_size;
+
+    stream->write_pos = 0;
+
+    stream->count_zeros = 0;
+
+    stream->current_word = 0;
+
+    stream->bit_left = WORD_SIZE;
+
+    stream->overrunBuffer = overrunBuffer;
+
+    stream->oBSize = oBSize;
+
+    return AVCENC_SUCCESS;
+}
+
+/* ======================================================================== */
+/*  Function : AVCBitstreamSaveWord()                                           */
+/*  Date     : 3/29/2004                                                    */
+/*  Purpose  : Save the current_word into the buffer, byte-swap, and        */
+/*              add emulation prevention insertion.                         */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is  */
+/*              full.                                                       */
+/*  Modified :                                                              */
+/* ======================================================================== */
+AVCEnc_Status AVCBitstreamSaveWord(AVCEncBitstream *stream)
+{
+    int num_bits;
+    uint8 *write_pnt, byte;
+    uint current_word;
+
+    /* check number of bytes in current_word, must always be byte-aligned!!!! */
+    num_bits = WORD_SIZE - stream->bit_left; /* must be multiple of 8 !!*/
+
+    if (stream->buf_size - stream->write_pos <= (num_bits >> 3) + 2) /* 2 more bytes for possible EPBS */
+    {
+        if (AVCENC_SUCCESS != AVCBitstreamUseOverrunBuffer(stream, (num_bits >> 3) + 2))
+        {
+            return AVCENC_BITSTREAM_BUFFER_FULL;
+        }
+    }
+
+    /* write word, byte-by-byte */
+    write_pnt = stream->bitstreamBuffer + stream->write_pos;
+    current_word = stream->current_word;
+    while (num_bits) /* no need to check stream->buf_size and stream->write_pos, taken care already */
+    {
+        num_bits -= 8;
+        byte = (current_word >> num_bits) & 0xFF;
+        if (byte != 0)
+        {
+            *write_pnt++ = byte;
+            stream->write_pos++;
+            stream->count_zeros = 0;
+        }
+        else
+        {
+            stream->count_zeros++;
+            *write_pnt++ = byte;
+            stream->write_pos++;
+            if (stream->count_zeros == 2)
+            {   /* for num_bits = 32, this can add 2 more bytes extra for EPBS */
+                *write_pnt++ = 0x3;
+                stream->write_pos++;
+                stream->count_zeros = 0;
+            }
+        }
+    }
+
+    /* reset current_word and bit_left */
+    stream->current_word = 0;
+    stream->bit_left = WORD_SIZE;
+
+    return AVCENC_SUCCESS;
+}
+
+/* ======================================================================== */
+/*  Function : BitstreamWriteBits()                                         */
+/*  Date     : 3/29/2004                                                    */
+/*  Purpose  : Write up to machine word.                                    */
+/*  In/out   : Unused bits in 'code' must be all zeros.                     */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is  */
+/*              full.                                                       */
+/*  Modified :                                                              */
+/* ======================================================================== */
+AVCEnc_Status BitstreamWriteBits(AVCEncBitstream *stream, int nBits, uint code)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    int bit_left = stream->bit_left;
+    uint current_word = stream->current_word;
+
+    //DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"BitstreamWriteBits",nBits,-1);
+
+    if (nBits > WORD_SIZE) /* has to be taken care of specially */
+    {
+        return AVCENC_FAIL; /* for now */
+        /* otherwise, break it down to 2 write of less than 16 bits at a time. */
+    }
+
+    if (nBits <= bit_left) /* more bits left in current_word */
+    {
+        stream->current_word = (current_word << nBits) | code;
+        stream->bit_left -= nBits;
+        if (stream->bit_left == 0) /* prepare for the next word */
+        {
+            status = AVCBitstreamSaveWord(stream);
+            return status;
+        }
+    }
+    else
+    {
+        stream->current_word = (current_word << bit_left) | (code >> (nBits - bit_left));
+
+        nBits -= bit_left;
+
+        stream->bit_left = 0;
+
+        status = AVCBitstreamSaveWord(stream); /* save current word */
+
+        stream->bit_left = WORD_SIZE - nBits;
+
+        stream->current_word = code; /* no extra masking for code, must be handled before saving */
+    }
+
+    return status;
+}
+
+
+/* ======================================================================== */
+/*  Function : BitstreamWrite1Bit()                                         */
+/*  Date     : 3/30/2004                                                    */
+/*  Purpose  : Write 1 bit                                                  */
+/*  In/out   : Unused bits in 'code' must be all zeros.                     */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is  */
+/*              full.                                                       */
+/*  Modified :                                                              */
+/* ======================================================================== */
+AVCEnc_Status BitstreamWrite1Bit(AVCEncBitstream *stream, uint code)
+{
+    AVCEnc_Status status;
+    uint current_word = stream->current_word;
+
+    //DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"BitstreamWrite1Bit",code,-1);
+
+    //if(1 <= bit_left) /* more bits left in current_word */
+    /* we can assume that there always be positive bit_left in the current word */
+    stream->current_word = (current_word << 1) | code;
+    stream->bit_left--;
+    if (stream->bit_left == 0) /* prepare for the next word */
+    {
+        status = AVCBitstreamSaveWord(stream);
+        return status;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+
+/* ======================================================================== */
+/*  Function : BitstreamTrailingBits()                                      */
+/*  Date     : 3/31/2004                                                    */
+/*  Purpose  : Add trailing bits and report the final EBSP size.            */
+/*  In/out   :                                                              */
+/*  Return   : AVCENC_SUCCESS if successed, AVCENC_WRITE_FAIL if buffer is  */
+/*              full.                                                       */
+/*  Modified :                                                              */
+/* ======================================================================== */
+AVCEnc_Status BitstreamTrailingBits(AVCEncBitstream *bitstream, uint *nal_size)
+{
+    (void)(nal_size);
+
+    AVCEnc_Status status;
+    int bit_left = bitstream->bit_left;
+
+    bit_left &= 0x7; /* modulo by 8 */
+    if (bit_left == 0) bit_left = 8;
+    /* bitstream->bit_left == 0 cannot happen here since it would have been Saved already */
+
+    status = BitstreamWriteBits(bitstream, bit_left, trailing_bits[bit_left]);
+
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    /* if it's not saved, save it. */
+    //if(bitstream->bit_left<(WORD_SIZE<<3)) /* in fact, no need to check */
+    {
+        status = AVCBitstreamSaveWord(bitstream);
+    }
+
+    return status;
+}
+
+/* check whether it's byte-aligned */
+bool byte_aligned(AVCEncBitstream *stream)
+{
+    if (stream->bit_left % 8)
+        return false;
+    else
+        return true;
+}
+
+
+/* determine whether overrun buffer can be used or not */
+AVCEnc_Status AVCBitstreamUseOverrunBuffer(AVCEncBitstream* stream, int numExtraBytes)
+{
+    AVCEncObject *encvid = (AVCEncObject*)stream->encvid;
+
+    if (stream->overrunBuffer != NULL) // overrunBuffer is set
+    {
+        if (stream->bitstreamBuffer != stream->overrunBuffer) // not already used
+        {
+            if (stream->write_pos + numExtraBytes >= stream->oBSize)
+            {
+                stream->oBSize = stream->write_pos + numExtraBytes + 100;
+                stream->oBSize &= (~0x3); // make it multiple of 4
+
+                // allocate new overrun Buffer
+                if (encvid->overrunBuffer)
+                {
+                    encvid->avcHandle->CBAVC_Free((uint32*)encvid->avcHandle->userData,
+                                                  (int)encvid->overrunBuffer);
+                }
+
+                encvid->oBSize = stream->oBSize;
+                encvid->overrunBuffer = (uint8*) encvid->avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
+                                        stream->oBSize, DEFAULT_ATTR);
+
+                stream->overrunBuffer = encvid->overrunBuffer;
+                if (stream->overrunBuffer == NULL)
+                {
+                    return AVCENC_FAIL;
+                }
+            }
+
+            // copy everything to overrun buffer and start using it.
+            memcpy(stream->overrunBuffer, stream->bitstreamBuffer, stream->write_pos);
+            stream->bitstreamBuffer = stream->overrunBuffer;
+            stream->buf_size = stream->oBSize;
+        }
+        else // overrun buffer is already used
+        {
+            stream->oBSize = stream->write_pos + numExtraBytes + 100;
+            stream->oBSize &= (~0x3); // make it multiple of 4
+
+            // allocate new overrun buffer
+            encvid->oBSize = stream->oBSize;
+            encvid->overrunBuffer = (uint8*) encvid->avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
+                                    stream->oBSize, DEFAULT_ATTR);
+
+            if (encvid->overrunBuffer == NULL)
+            {
+                return AVCENC_FAIL;
+            }
+
+
+            // copy from the old buffer to new buffer
+            memcpy(encvid->overrunBuffer, stream->overrunBuffer, stream->write_pos);
+            // free old buffer
+            encvid->avcHandle->CBAVC_Free((uint32*)encvid->avcHandle->userData,
+                                          (int)stream->overrunBuffer);
+
+            // assign pointer to new buffer
+            stream->overrunBuffer = encvid->overrunBuffer;
+            stream->bitstreamBuffer = stream->overrunBuffer;
+            stream->buf_size = stream->oBSize;
+        }
+
+        return AVCENC_SUCCESS;
+    }
+    else // overrunBuffer is not enable.
+    {
+        return AVCENC_FAIL;
+    }
+
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/block.cpp b/media/libstagefright/codecs/avc/enc/src/block.cpp
new file mode 100644
index 0000000..01e26a6
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/block.cpp
@@ -0,0 +1,1283 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+
+/* subtract with the prediction and do transformation */
+void trans(uint8 *cur, int pitch, uint8 *predBlock, int16 *dataBlock)
+{
+    int16 *ptr = dataBlock;
+    int r0, r1, r2, r3, j;
+    int curpitch = (uint)pitch >> 16;
+    int predpitch = (pitch & 0xFFFF);
+
+    /* horizontal */
+    j = 4;
+    while (j > 0)
+    {
+        /* calculate the residue first */
+        r0 = cur[0] - predBlock[0];
+        r1 = cur[1] - predBlock[1];
+        r2 = cur[2] - predBlock[2];
+        r3 = cur[3] - predBlock[3];
+
+        r0 += r3;           //ptr[0] + ptr[3];
+        r3 = r0 - (r3 << 1);    //ptr[0] - ptr[3];
+        r1 += r2;           //ptr[1] + ptr[2];
+        r2 = r1 - (r2 << 1);    //ptr[1] - ptr[2];
+
+        ptr[0] = r0 + r1;
+        ptr[2] = r0 - r1;
+        ptr[1] = (r3 << 1) + r2;
+        ptr[3] = r3 - (r2 << 1);
+
+        ptr += 16;
+        predBlock += predpitch;
+        cur += curpitch;
+        j--;
+    }
+    /* vertical */
+    ptr = dataBlock;
+    j = 4;
+    while (j > 0)
+    {
+        r0 = ptr[0] + ptr[48];
+        r3 = ptr[0] - ptr[48];
+        r1 = ptr[16] + ptr[32];
+        r2 = ptr[16] - ptr[32];
+
+        ptr[0] = r0 + r1;
+        ptr[32] = r0 - r1;
+        ptr[16] = (r3 << 1) + r2;
+        ptr[48] = r3 - (r2 << 1);
+
+        ptr++;
+        j--;
+    }
+
+    return ;
+}
+
+
+/* do residue transform quant invquant, invtrans and write output out */
+int dct_luma(AVCEncObject *encvid, int blkidx, uint8 *cur, uint8 *org, int *coef_cost)
+{
+    AVCCommonObj *video = encvid->common;
+    int org_pitch = encvid->currInput->pitch;
+    int pitch = video->currPic->pitch;
+    int16 *coef = video->block;
+    uint8 *pred = video->pred_block; // size 16 for a 4x4 block
+    int pred_pitch = video->pred_pitch;
+    int r0, r1, r2, r3, j, k, idx;
+    int *level, *run;
+    int Qq, Rq, q_bits, qp_const, quant;
+    int data, lev, zero_run;
+    int numcoeff;
+
+    coef += ((blkidx & 0x3) << 2) + ((blkidx >> 2) << 6); /* point to the 4x4 block */
+
+    /* first take a 4x4 transform */
+    /* horizontal */
+    j = 4;
+    while (j > 0)
+    {
+        /* calculate the residue first */
+        r0 = org[0] - pred[0];   /* OPTIMIZEABLE */
+        r1 = org[1] - pred[1];
+        r2 = org[2] - pred[2];
+        r3 = org[3] - pred[3];
+
+        r0 += r3;           //ptr[0] + ptr[3];
+        r3 = r0 - (r3 << 1);    //ptr[0] - ptr[3];
+        r1 += r2;           //ptr[1] + ptr[2];
+        r2 = r1 - (r2 << 1);    //ptr[1] - ptr[2];
+
+        coef[0] = r0 + r1;
+        coef[2] = r0 - r1;
+        coef[1] = (r3 << 1) + r2;
+        coef[3] = r3 - (r2 << 1);
+
+        coef += 16;
+        org += org_pitch;
+        pred += pred_pitch;
+        j--;
+    }
+    /* vertical */
+    coef -= 64;
+    pred -= (pred_pitch << 2);
+    j = 4;
+    while (j > 0)   /* OPTIMIZABLE */
+    {
+        r0 = coef[0] + coef[48];
+        r3 = coef[0] - coef[48];
+        r1 = coef[16] + coef[32];
+        r2 = coef[16] - coef[32];
+
+        coef[0] = r0 + r1;
+        coef[32] = r0 - r1;
+        coef[16] = (r3 << 1) + r2;
+        coef[48] = r3 - (r2 << 1);
+
+        coef++;
+        j--;
+    }
+
+    coef -= 4;
+
+    /* quant */
+    level = encvid->level[ras2dec[blkidx]];
+    run = encvid->run[ras2dec[blkidx]];
+
+    Rq = video->QPy_mod_6;
+    Qq = video->QPy_div_6;
+    qp_const = encvid->qp_const;
+    q_bits = 15 + Qq;
+
+    zero_run = 0;
+    numcoeff = 0;
+    for (k = 0; k < 16; k++)
+    {
+        idx = ZZ_SCAN_BLOCK[k]; /* map back to raster scan order */
+        data = coef[idx];
+        quant = quant_coef[Rq][k];
+        if (data > 0)
+        {
+            lev = data * quant + qp_const;
+        }
+        else
+        {
+            lev = -data * quant + qp_const;
+        }
+        lev >>= q_bits;
+        if (lev)
+        {
+            *coef_cost += ((lev > 1) ? MAX_VALUE : COEFF_COST[DISABLE_THRESHOLDING][zero_run]);
+
+            /* dequant */
+            quant = dequant_coefres[Rq][k];
+            if (data > 0)
+            {
+                level[numcoeff] = lev;
+                coef[idx] = (lev * quant) << Qq;
+            }
+            else
+            {
+                level[numcoeff] = -lev;
+                coef[idx] = (-lev * quant) << Qq;
+            }
+            run[numcoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            coef[idx] = 0;
+        }
+    }
+
+    if (video->currMB->mb_intra) // only do inverse transform with intra block
+    {
+        if (numcoeff) /* then do inverse transform */
+        {
+            for (j = 4; j > 0; j--) /* horizontal */
+            {
+                r0 = coef[0] + coef[2];
+                r1 = coef[0] - coef[2];
+                r2 = (coef[1] >> 1) - coef[3];
+                r3 = coef[1] + (coef[3] >> 1);
+
+                coef[0] = r0 + r3;
+                coef[1] = r1 + r2;
+                coef[2] = r1 - r2;
+                coef[3] = r0 - r3;
+
+                coef += 16;
+            }
+
+            coef -= 64;
+            for (j = 4; j > 0; j--) /* vertical, has to be done after horizontal */
+            {
+                r0 = coef[0] + coef[32];
+                r1 = coef[0] - coef[32];
+                r2 = (coef[16] >> 1) - coef[48];
+                r3 = coef[16] + (coef[48] >> 1);
+                r0 += r3;
+                r3 = (r0 - (r3 << 1)); /* r0-r3 */
+                r1 += r2;
+                r2 = (r1 - (r2 << 1)); /* r1-r2 */
+                r0 += 32;
+                r1 += 32;
+                r2 += 32;
+                r3 += 32;
+
+                r0 = pred[0] + (r0 >> 6);
+                if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                r1 = *(pred += pred_pitch) + (r1 >> 6);
+                if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                r2 = *(pred += pred_pitch) + (r2 >> 6);
+                if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                r3 = pred[pred_pitch] + (r3 >> 6);
+                if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+
+                *cur = r0;
+                *(cur += pitch) = r1;
+                *(cur += pitch) = r2;
+                cur[pitch] = r3;
+                cur -= (pitch << 1);
+                cur++;
+                pred -= (pred_pitch << 1);
+                pred++;
+                coef++;
+            }
+        }
+        else  // copy from pred to cur
+        {
+            *((uint32*)cur) = *((uint32*)pred);
+            *((uint32*)(cur += pitch)) = *((uint32*)(pred += pred_pitch));
+            *((uint32*)(cur += pitch)) = *((uint32*)(pred += pred_pitch));
+            *((uint32*)(cur += pitch)) = *((uint32*)(pred += pred_pitch));
+        }
+    }
+
+    return numcoeff;
+}
+
+
+void MBInterIdct(AVCCommonObj *video, uint8 *curL, AVCMacroblock *currMB, int picPitch)
+{
+    int16 *coef, *coef8 = video->block;
+    uint8 *cur;  // the same as curL
+    int b8, b4;
+    int r0, r1, r2, r3, j, blkidx;
+
+    for (b8 = 0; b8 < 4; b8++)
+    {
+        cur = curL;
+        coef = coef8;
+
+        if (currMB->CBP&(1 << b8))
+        {
+            for (b4 = 0; b4 < 4; b4++)
+            {
+                blkidx = blkIdx2blkXY[b8][b4];
+                /* do IDCT */
+                if (currMB->nz_coeff[blkidx])
+                {
+                    for (j = 4; j > 0; j--) /* horizontal */
+                    {
+                        r0 = coef[0] + coef[2];
+                        r1 = coef[0] - coef[2];
+                        r2 = (coef[1] >> 1) - coef[3];
+                        r3 = coef[1] + (coef[3] >> 1);
+
+                        coef[0] = r0 + r3;
+                        coef[1] = r1 + r2;
+                        coef[2] = r1 - r2;
+                        coef[3] = r0 - r3;
+
+                        coef += 16;
+                    }
+
+                    coef -= 64;
+                    for (j = 4; j > 0; j--) /* vertical, has to be done after horizontal */
+                    {
+                        r0 = coef[0] + coef[32];
+                        r1 = coef[0] - coef[32];
+                        r2 = (coef[16] >> 1) - coef[48];
+                        r3 = coef[16] + (coef[48] >> 1);
+                        r0 += r3;
+                        r3 = (r0 - (r3 << 1)); /* r0-r3 */
+                        r1 += r2;
+                        r2 = (r1 - (r2 << 1)); /* r1-r2 */
+                        r0 += 32;
+                        r1 += 32;
+                        r2 += 32;
+                        r3 += 32;
+
+                        r0 = cur[0] + (r0 >> 6);
+                        if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                        *cur = r0;
+                        r1 = *(cur += picPitch) + (r1 >> 6);
+                        if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                        *cur = r1;
+                        r2 = *(cur += picPitch) + (r2 >> 6);
+                        if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                        *cur = r2;
+                        r3 = cur[picPitch] + (r3 >> 6);
+                        if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                        cur[picPitch] = r3;
+
+                        cur -= (picPitch << 1);
+                        cur++;
+                        coef++;
+                    }
+                    cur -= 4;
+                    coef -= 4;
+                }
+                if (b4&1)
+                {
+                    cur += ((picPitch << 2) - 4);
+                    coef += 60;
+                }
+                else
+                {
+                    cur += 4;
+                    coef += 4;
+                }
+            }
+        }
+
+        if (b8&1)
+        {
+            curL += ((picPitch << 3) - 8);
+            coef8 += 120;
+        }
+        else
+        {
+            curL += 8;
+            coef8 += 8;
+        }
+    }
+
+    return ;
+}
+
+/* performa dct, quant, iquant, idct for the entire MB */
+void dct_luma_16x16(AVCEncObject *encvid, uint8 *curL, uint8 *orgL)
+{
+    AVCCommonObj *video = encvid->common;
+    int pitch = video->currPic->pitch;
+    int org_pitch = encvid->currInput->pitch;
+    AVCMacroblock *currMB = video->currMB;
+    int16 *coef = video->block;
+    uint8 *pred = encvid->pred_i16[currMB->i16Mode];
+    int blk_x, blk_y, j, k, idx, b8, b4;
+    int r0, r1, r2, r3, m0, m1, m2 , m3;
+    int data, lev;
+    int *level, *run, zero_run, ncoeff;
+    int Rq, Qq, quant, q_bits, qp_const;
+    int offset_cur[4], offset_pred[4], offset;
+
+    /* horizontal */
+    for (j = 16; j > 0; j--)
+    {
+        for (blk_x = 4; blk_x > 0; blk_x--)
+        {
+            /* calculate the residue first */
+            r0 = *orgL++ - *pred++;
+            r1 = *orgL++ - *pred++;
+            r2 = *orgL++ - *pred++;
+            r3 = *orgL++ - *pred++;
+
+            r0 += r3;           //ptr[0] + ptr[3];
+            r3 = r0 - (r3 << 1);    //ptr[0] - ptr[3];
+            r1 += r2;           //ptr[1] + ptr[2];
+            r2 = r1 - (r2 << 1);    //ptr[1] - ptr[2];
+
+            *coef++ = r0 + r1;
+            *coef++ = (r3 << 1) + r2;
+            *coef++ = r0 - r1;
+            *coef++ = r3 - (r2 << 1);
+        }
+        orgL += (org_pitch - 16);
+    }
+    pred -= 256;
+    coef -= 256;
+    /* vertical */
+    for (blk_y = 4; blk_y > 0; blk_y--)
+    {
+        for (j = 16; j > 0; j--)
+        {
+            r0 = coef[0] + coef[48];
+            r3 = coef[0] - coef[48];
+            r1 = coef[16] + coef[32];
+            r2 = coef[16] - coef[32];
+
+            coef[0] = r0 + r1;
+            coef[32] = r0 - r1;
+            coef[16] = (r3 << 1) + r2;
+            coef[48] = r3 - (r2 << 1);
+
+            coef++;
+        }
+        coef += 48;
+    }
+
+    /* then perform DC transform */
+    coef -= 256;
+    for (j = 4; j > 0; j--)
+    {
+        r0 = coef[0] + coef[12];
+        r3 = coef[0] - coef[12];
+        r1 = coef[4] + coef[8];
+        r2 = coef[4] - coef[8];
+
+        coef[0] = r0 + r1;
+        coef[8] = r0 - r1;
+        coef[4] = r3 + r2;
+        coef[12] = r3 - r2;
+        coef += 64;
+    }
+    coef -= 256;
+    for (j = 4; j > 0; j--)
+    {
+        r0 = coef[0] + coef[192];
+        r3 = coef[0] - coef[192];
+        r1 = coef[64] + coef[128];
+        r2 = coef[64] - coef[128];
+
+        coef[0] = (r0 + r1) >> 1;
+        coef[128] = (r0 - r1) >> 1;
+        coef[64] = (r3 + r2) >> 1;
+        coef[192] = (r3 - r2) >> 1;
+        coef += 4;
+    }
+
+    coef -= 16;
+    // then quantize DC
+    level = encvid->leveldc;
+    run = encvid->rundc;
+
+    Rq = video->QPy_mod_6;
+    Qq = video->QPy_div_6;
+    quant = quant_coef[Rq][0];
+    q_bits = 15 + Qq;
+    qp_const = encvid->qp_const;
+
+    zero_run = 0;
+    ncoeff = 0;
+    for (k = 0; k < 16; k++) /* in zigzag scan order */
+    {
+        idx = ZIGZAG2RASTERDC[k];
+        data = coef[idx];
+        if (data > 0)   // quant
+        {
+            lev = data * quant + (qp_const << 1);
+        }
+        else
+        {
+            lev = -data * quant + (qp_const << 1);
+        }
+        lev >>= (q_bits + 1);
+        if (lev) // dequant
+        {
+            if (data > 0)
+            {
+                level[ncoeff] = lev;
+                coef[idx] = lev;
+            }
+            else
+            {
+                level[ncoeff] = -lev;
+                coef[idx] = -lev;
+            }
+            run[ncoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            coef[idx] = 0;
+        }
+    }
+
+    /* inverse transform DC */
+    encvid->numcoefdc = ncoeff;
+    if (ncoeff)
+    {
+        quant = dequant_coefres[Rq][0];
+
+        for (j = 0; j < 4; j++)
+        {
+            m0 = coef[0] + coef[4];
+            m1 = coef[0] - coef[4];
+            m2 = coef[8] + coef[12];
+            m3 = coef[8] - coef[12];
+
+
+            coef[0] = m0 + m2;
+            coef[4] = m0 - m2;
+            coef[8] = m1 - m3;
+            coef[12] = m1 + m3;
+            coef += 64;
+        }
+
+        coef -= 256;
+
+        if (Qq >= 2)  /* this way should be faster than JM */
+        {           /* they use (((m4*scale)<<(QPy/6))+2)>>2 for both cases. */
+            Qq -= 2;
+            for (j = 0; j < 4; j++)
+            {
+                m0 = coef[0] + coef[64];
+                m1 = coef[0] - coef[64];
+                m2 = coef[128] + coef[192];
+                m3 = coef[128] - coef[192];
+
+                coef[0] = ((m0 + m2) * quant) << Qq;
+                coef[64] = ((m0 - m2) * quant) << Qq;
+                coef[128] = ((m1 - m3) * quant) << Qq;
+                coef[192] = ((m1 + m3) * quant) << Qq;
+                coef += 4;
+            }
+            Qq += 2; /* restore the value */
+        }
+        else
+        {
+            Qq = 2 - Qq;
+            offset = 1 << (Qq - 1);
+
+            for (j = 0; j < 4; j++)
+            {
+                m0 = coef[0] + coef[64];
+                m1 = coef[0] - coef[64];
+                m2 = coef[128] + coef[192];
+                m3 = coef[128] - coef[192];
+
+                coef[0] = (((m0 + m2) * quant + offset) >> Qq);
+                coef[64] = (((m0 - m2) * quant + offset) >> Qq);
+                coef[128] = (((m1 - m3) * quant + offset) >> Qq);
+                coef[192] = (((m1 + m3) * quant + offset) >> Qq);
+                coef += 4;
+            }
+            Qq = 2 - Qq; /* restore the value */
+        }
+        coef -= 16; /* back to the origin */
+    }
+
+    /* now zigzag scan ac coefs, quant, iquant and itrans */
+    run = encvid->run[0];
+    level = encvid->level[0];
+
+    /* offset btw 4x4 block */
+    offset_cur[0] = 0;
+    offset_cur[1] = (pitch << 2) - 8;
+
+    /* offset btw 8x8 block */
+    offset_cur[2] = 8 - (pitch << 3);
+    offset_cur[3] = -8;
+
+    /* similarly for pred */
+    offset_pred[0] = 0;
+    offset_pred[1] = 56;
+    offset_pred[2] = -120;
+    offset_pred[3] = -8;
+
+    currMB->CBP = 0;
+
+    for (b8 = 0; b8 < 4; b8++)
+    {
+        for (b4 = 0; b4 < 4; b4++)
+        {
+
+            zero_run = 0;
+            ncoeff = 0;
+
+            for (k = 1; k < 16; k++)
+            {
+                idx = ZZ_SCAN_BLOCK[k]; /* map back to raster scan order */
+                data = coef[idx];
+                quant = quant_coef[Rq][k];
+                if (data > 0)
+                {
+                    lev = data * quant + qp_const;
+                }
+                else
+                {
+                    lev = -data * quant + qp_const;
+                }
+                lev >>= q_bits;
+                if (lev)
+                {   /* dequant */
+                    quant = dequant_coefres[Rq][k];
+                    if (data > 0)
+                    {
+                        level[ncoeff] = lev;
+                        coef[idx] = (lev * quant) << Qq;
+                    }
+                    else
+                    {
+                        level[ncoeff] = -lev;
+                        coef[idx] = (-lev * quant) << Qq;
+                    }
+                    run[ncoeff++] = zero_run;
+                    zero_run = 0;
+                }
+                else
+                {
+                    zero_run++;
+                    coef[idx] = 0;
+                }
+            }
+
+            currMB->nz_coeff[blkIdx2blkXY[b8][b4]] = ncoeff; /* in raster scan !!! */
+            if (ncoeff)
+            {
+                currMB->CBP |= (1 << b8);
+
+                // do inverse transform here
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = coef[0] + coef[2];
+                    r1 = coef[0] - coef[2];
+                    r2 = (coef[1] >> 1) - coef[3];
+                    r3 = coef[1] + (coef[3] >> 1);
+
+                    coef[0] = r0 + r3;
+                    coef[1] = r1 + r2;
+                    coef[2] = r1 - r2;
+                    coef[3] = r0 - r3;
+
+                    coef += 16;
+                }
+                coef -= 64;
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = coef[0] + coef[32];
+                    r1 = coef[0] - coef[32];
+                    r2 = (coef[16] >> 1) - coef[48];
+                    r3 = coef[16] + (coef[48] >> 1);
+
+                    r0 += r3;
+                    r3 = (r0 - (r3 << 1)); /* r0-r3 */
+                    r1 += r2;
+                    r2 = (r1 - (r2 << 1)); /* r1-r2 */
+                    r0 += 32;
+                    r1 += 32;
+                    r2 += 32;
+                    r3 += 32;
+                    r0 = pred[0] + (r0 >> 6);
+                    if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                    r1 = pred[16] + (r1 >> 6);
+                    if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                    r2 = pred[32] + (r2 >> 6);
+                    if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                    r3 = pred[48] + (r3 >> 6);
+                    if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                    *curL = r0;
+                    *(curL += pitch) = r1;
+                    *(curL += pitch) = r2;
+                    curL[pitch] = r3;
+                    curL -= (pitch << 1);
+                    curL++;
+                    pred++;
+                    coef++;
+                }
+            }
+            else  // do DC-only inverse
+            {
+                m0 = coef[0] + 32;
+
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = pred[0] + (m0 >> 6);
+                    if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                    r1 = pred[16] + (m0 >> 6);
+                    if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                    r2 = pred[32] + (m0 >> 6);
+                    if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                    r3 = pred[48] + (m0 >> 6);
+                    if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                    *curL = r0;
+                    *(curL += pitch) = r1;
+                    *(curL += pitch) = r2;
+                    curL[pitch] = r3;
+                    curL -= (pitch << 1);
+                    curL++;
+                    pred++;
+                }
+                coef += 4;
+            }
+
+            run += 16;  // follow coding order
+            level += 16;
+            curL += offset_cur[b4&1];
+            pred += offset_pred[b4&1];
+            coef += offset_pred[b4&1];
+        }
+
+        curL += offset_cur[2 + (b8&1)];
+        pred += offset_pred[2 + (b8&1)];
+        coef += offset_pred[2 + (b8&1)];
+    }
+
+    return ;
+}
+
+
+void dct_chroma(AVCEncObject *encvid, uint8 *curC, uint8 *orgC, int cr)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+    int org_pitch = (encvid->currInput->pitch) >> 1;
+    int pitch = (video->currPic->pitch) >> 1;
+    int pred_pitch = 16;
+    int16 *coef = video->block + 256;
+    uint8 *pred = video->pred_block;
+    int j, blk_x, blk_y, k, idx, b4;
+    int r0, r1, r2, r3, m0;
+    int Qq, Rq, qp_const, q_bits, quant;
+    int *level, *run, zero_run, ncoeff;
+    int data, lev;
+    int offset_cur[2], offset_pred[2], offset_coef[2];
+    uint8 nz_temp[4];
+    int  coeff_cost;
+
+    if (cr)
+    {
+        coef += 8;
+        pred += 8;
+    }
+
+    if (currMB->mb_intra == 0) // inter mode
+    {
+        pred = curC;
+        pred_pitch = pitch;
+    }
+
+    /* do 4x4 transform */
+    /* horizontal */
+    for (j = 8; j > 0; j--)
+    {
+        for (blk_x = 2; blk_x > 0; blk_x--)
+        {
+            /* calculate the residue first */
+            r0 = *orgC++ - *pred++;
+            r1 = *orgC++ - *pred++;
+            r2 = *orgC++ - *pred++;
+            r3 = *orgC++ - *pred++;
+
+            r0 += r3;           //ptr[0] + ptr[3];
+            r3 = r0 - (r3 << 1);    //ptr[0] - ptr[3];
+            r1 += r2;           //ptr[1] + ptr[2];
+            r2 = r1 - (r2 << 1);    //ptr[1] - ptr[2];
+
+            *coef++ = r0 + r1;
+            *coef++ = (r3 << 1) + r2;
+            *coef++ = r0 - r1;
+            *coef++ = r3 - (r2 << 1);
+
+        }
+        coef += 8; // coef pitch is 16
+        pred += (pred_pitch - 8); // pred_pitch is 16
+        orgC += (org_pitch - 8);
+    }
+    pred -= (pred_pitch << 3);
+    coef -= 128;
+    /* vertical */
+    for (blk_y = 2; blk_y > 0; blk_y--)
+    {
+        for (j = 8; j > 0; j--)
+        {
+            r0 = coef[0] + coef[48];
+            r3 = coef[0] - coef[48];
+            r1 = coef[16] + coef[32];
+            r2 = coef[16] - coef[32];
+
+            coef[0] = r0 + r1;
+            coef[32] = r0 - r1;
+            coef[16] = (r3 << 1) + r2;
+            coef[48] = r3 - (r2 << 1);
+
+            coef++;
+        }
+        coef += 56;
+    }
+    /* then perform DC transform */
+    coef -= 128;
+
+    /* 2x2 transform of DC components*/
+    r0 = coef[0];
+    r1 = coef[4];
+    r2 = coef[64];
+    r3 = coef[68];
+
+    coef[0] = r0 + r1 + r2 + r3;
+    coef[4] = r0 - r1 + r2 - r3;
+    coef[64] = r0 + r1 - r2 - r3;
+    coef[68] = r0 - r1 - r2 + r3;
+
+    Qq    = video->QPc_div_6;
+    Rq    = video->QPc_mod_6;
+    quant = quant_coef[Rq][0];
+    q_bits    = 15 + Qq;
+    qp_const = encvid->qp_const_c;
+
+    zero_run = 0;
+    ncoeff = 0;
+    run = encvid->runcdc + (cr << 2);
+    level = encvid->levelcdc + (cr << 2);
+
+    /* in zigzag scan order */
+    for (k = 0; k < 4; k++)
+    {
+        idx = ((k >> 1) << 6) + ((k & 1) << 2);
+        data = coef[idx];
+        if (data > 0)
+        {
+            lev = data * quant + (qp_const << 1);
+        }
+        else
+        {
+            lev = -data * quant + (qp_const << 1);
+        }
+        lev >>= (q_bits + 1);
+        if (lev)
+        {
+            if (data > 0)
+            {
+                level[ncoeff] = lev;
+                coef[idx] = lev;
+            }
+            else
+            {
+                level[ncoeff] = -lev;
+                coef[idx] = -lev;
+            }
+            run[ncoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            coef[idx] = 0;
+        }
+    }
+
+    encvid->numcoefcdc[cr] = ncoeff;
+
+    if (ncoeff)
+    {
+        currMB->CBP |= (1 << 4); // DC present
+        // do inverse transform
+        quant = dequant_coefres[Rq][0];
+
+        r0 = coef[0] + coef[4];
+        r1 = coef[0] - coef[4];
+        r2 = coef[64] + coef[68];
+        r3 = coef[64] - coef[68];
+
+        r0 += r2;
+        r2 = r0 - (r2 << 1);
+        r1 += r3;
+        r3 = r1 - (r3 << 1);
+
+        if (Qq >= 1)
+        {
+            Qq -= 1;
+            coef[0] = (r0 * quant) << Qq;
+            coef[4] = (r1 * quant) << Qq;
+            coef[64] = (r2 * quant) << Qq;
+            coef[68] = (r3 * quant) << Qq;
+            Qq++;
+        }
+        else
+        {
+            coef[0] = (r0 * quant) >> 1;
+            coef[4] = (r1 * quant) >> 1;
+            coef[64] = (r2 * quant) >> 1;
+            coef[68] = (r3 * quant) >> 1;
+        }
+    }
+
+    /* now do AC zigzag scan, quant, iquant and itrans */
+    if (cr)
+    {
+        run = encvid->run[20];
+        level = encvid->level[20];
+    }
+    else
+    {
+        run = encvid->run[16];
+        level = encvid->level[16];
+    }
+
+    /* offset btw 4x4 block */
+    offset_cur[0] = 0;
+    offset_cur[1] = (pitch << 2) - 8;
+    offset_pred[0] = 0;
+    offset_pred[1] = (pred_pitch << 2) - 8;
+    offset_coef[0] = 0;
+    offset_coef[1] = 56;
+
+    coeff_cost = 0;
+
+    for (b4 = 0; b4 < 4; b4++)
+    {
+        zero_run = 0;
+        ncoeff = 0;
+        for (k = 1; k < 16; k++) /* in zigzag scan order */
+        {
+            idx = ZZ_SCAN_BLOCK[k]; /* map back to raster scan order */
+            data = coef[idx];
+            quant = quant_coef[Rq][k];
+            if (data > 0)
+            {
+                lev = data * quant + qp_const;
+            }
+            else
+            {
+                lev = -data * quant + qp_const;
+            }
+            lev >>= q_bits;
+            if (lev)
+            {
+                /* for RD performance*/
+                if (lev > 1)
+                    coeff_cost += MAX_VALUE;                // set high cost, shall not be discarded
+                else
+                    coeff_cost += COEFF_COST[DISABLE_THRESHOLDING][zero_run];
+
+                /* dequant */
+                quant = dequant_coefres[Rq][k];
+                if (data > 0)
+                {
+                    level[ncoeff] = lev;
+                    coef[idx] = (lev * quant) << Qq;
+                }
+                else
+                {
+                    level[ncoeff] = -lev;
+                    coef[idx] = (-lev * quant) << Qq;
+                }
+                run[ncoeff++] = zero_run;
+                zero_run = 0;
+            }
+            else
+            {
+                zero_run++;
+                coef[idx] = 0;
+            }
+        }
+
+        nz_temp[b4] = ncoeff; // raster scan
+
+        // just advance the pointers for now, do IDCT later
+        coef += 4;
+        run += 16;
+        level += 16;
+        coef += offset_coef[b4&1];
+    }
+
+    /* rewind the pointers */
+    coef -= 128;
+
+    if (coeff_cost < _CHROMA_COEFF_COST_)
+    {
+        /* if it's not efficient to encode any blocks.
+        Just do DC only */
+        /* We can reset level and run also, but setting nz to zero should be enough. */
+        currMB->nz_coeff[16+(cr<<1)] = 0;
+        currMB->nz_coeff[17+(cr<<1)] = 0;
+        currMB->nz_coeff[20+(cr<<1)] = 0;
+        currMB->nz_coeff[21+(cr<<1)] = 0;
+
+        for (b4 = 0; b4 < 4; b4++)
+        {
+            // do DC-only inverse
+            m0 = coef[0] + 32;
+
+            for (j = 4; j > 0; j--)
+            {
+                r0 = pred[0] + (m0 >> 6);
+                if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                r1 = *(pred += pred_pitch) + (m0 >> 6);
+                if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                r2 = pred[pred_pitch] + (m0 >> 6);
+                if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                r3 = pred[pred_pitch<<1] + (m0 >> 6);
+                if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                *curC = r0;
+                *(curC += pitch) = r1;
+                *(curC += pitch) = r2;
+                curC[pitch] = r3;
+                curC -= (pitch << 1);
+                curC++;
+                pred += (1 - pred_pitch);
+            }
+            coef += 4;
+            curC += offset_cur[b4&1];
+            pred += offset_pred[b4&1];
+            coef += offset_coef[b4&1];
+        }
+    }
+    else // not dropping anything, continue with the IDCT
+    {
+        for (b4 = 0; b4 < 4; b4++)
+        {
+            ncoeff = nz_temp[b4] ; // in raster scan
+            currMB->nz_coeff[16+(b4&1)+(cr<<1)+((b4>>1)<<2)] = ncoeff; // in raster scan
+
+            if (ncoeff) // do a check on the nonzero-coeff
+            {
+                currMB->CBP |= (2 << 4);
+
+                // do inverse transform here
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = coef[0] + coef[2];
+                    r1 = coef[0] - coef[2];
+                    r2 = (coef[1] >> 1) - coef[3];
+                    r3 = coef[1] + (coef[3] >> 1);
+
+                    coef[0] = r0 + r3;
+                    coef[1] = r1 + r2;
+                    coef[2] = r1 - r2;
+                    coef[3] = r0 - r3;
+
+                    coef += 16;
+                }
+                coef -= 64;
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = coef[0] + coef[32];
+                    r1 = coef[0] - coef[32];
+                    r2 = (coef[16] >> 1) - coef[48];
+                    r3 = coef[16] + (coef[48] >> 1);
+
+                    r0 += r3;
+                    r3 = (r0 - (r3 << 1)); /* r0-r3 */
+                    r1 += r2;
+                    r2 = (r1 - (r2 << 1)); /* r1-r2 */
+                    r0 += 32;
+                    r1 += 32;
+                    r2 += 32;
+                    r3 += 32;
+                    r0 = pred[0] + (r0 >> 6);
+                    if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                    r1 = *(pred += pred_pitch) + (r1 >> 6);
+                    if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                    r2 = pred[pred_pitch] + (r2 >> 6);
+                    if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                    r3 = pred[pred_pitch<<1] + (r3 >> 6);
+                    if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                    *curC = r0;
+                    *(curC += pitch) = r1;
+                    *(curC += pitch) = r2;
+                    curC[pitch] = r3;
+                    curC -= (pitch << 1);
+                    curC++;
+                    pred += (1 - pred_pitch);
+                    coef++;
+                }
+            }
+            else
+            {
+                // do DC-only inverse
+                m0 = coef[0] + 32;
+
+                for (j = 4; j > 0; j--)
+                {
+                    r0 = pred[0] + (m0 >> 6);
+                    if ((uint)r0 > 0xFF)   r0 = 0xFF & (~(r0 >> 31));  /* clip */
+                    r1 = *(pred += pred_pitch) + (m0 >> 6);
+                    if ((uint)r1 > 0xFF)   r1 = 0xFF & (~(r1 >> 31));  /* clip */
+                    r2 = pred[pred_pitch] + (m0 >> 6);
+                    if ((uint)r2 > 0xFF)   r2 = 0xFF & (~(r2 >> 31));  /* clip */
+                    r3 = pred[pred_pitch<<1] + (m0 >> 6);
+                    if ((uint)r3 > 0xFF)   r3 = 0xFF & (~(r3 >> 31));  /* clip */
+                    *curC = r0;
+                    *(curC += pitch) = r1;
+                    *(curC += pitch) = r2;
+                    curC[pitch] = r3;
+                    curC -= (pitch << 1);
+                    curC++;
+                    pred += (1 - pred_pitch);
+                }
+                coef += 4;
+            }
+            curC += offset_cur[b4&1];
+            pred += offset_pred[b4&1];
+            coef += offset_coef[b4&1];
+        }
+    }
+
+    return ;
+}
+
+
+/* only DC transform */
+int TransQuantIntra16DC(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    int16 *block = video->block;
+    int *level = encvid->leveldc;
+    int *run = encvid->rundc;
+    int16 *ptr = block;
+    int r0, r1, r2, r3, j;
+    int Qq = video->QPy_div_6;
+    int Rq = video->QPy_mod_6;
+    int q_bits, qp_const, quant;
+    int data, lev, zero_run;
+    int k, ncoeff, idx;
+
+    /* DC transform */
+    /* horizontal */
+    j = 4;
+    while (j)
+    {
+        r0 = ptr[0] + ptr[12];
+        r3 = ptr[0] - ptr[12];
+        r1 = ptr[4] + ptr[8];
+        r2 = ptr[4] - ptr[8];
+
+        ptr[0] = r0 + r1;
+        ptr[8] = r0 - r1;
+        ptr[4] = r3 + r2;
+        ptr[12] = r3 - r2;
+        ptr += 64;
+        j--;
+    }
+    /* vertical */
+    ptr = block;
+    j = 4;
+    while (j)
+    {
+        r0 = ptr[0] + ptr[192];
+        r3 = ptr[0] - ptr[192];
+        r1 = ptr[64] + ptr[128];
+        r2 = ptr[64] - ptr[128];
+
+        ptr[0] = (r0 + r1) >> 1;
+        ptr[128] = (r0 - r1) >> 1;
+        ptr[64] = (r3 + r2) >> 1;
+        ptr[192] = (r3 - r2) >> 1;
+        ptr += 4;
+        j--;
+    }
+
+    quant = quant_coef[Rq][0];
+    q_bits    = 15 + Qq;
+    qp_const = (1 << q_bits) / 3;    // intra
+
+    zero_run = 0;
+    ncoeff = 0;
+
+    for (k = 0; k < 16; k++) /* in zigzag scan order */
+    {
+        idx = ZIGZAG2RASTERDC[k];
+        data = block[idx];
+        if (data > 0)
+        {
+            lev = data * quant + (qp_const << 1);
+        }
+        else
+        {
+            lev = -data * quant + (qp_const << 1);
+        }
+        lev >>= (q_bits + 1);
+        if (lev)
+        {
+            if (data > 0)
+            {
+                level[ncoeff] = lev;
+                block[idx] = lev;
+            }
+            else
+            {
+                level[ncoeff] = -lev;
+                block[idx] = -lev;
+            }
+            run[ncoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            block[idx] = 0;
+        }
+    }
+    return ncoeff;
+}
+
+int TransQuantChromaDC(AVCEncObject *encvid, int16 *block, int slice_type, int cr)
+{
+    AVCCommonObj *video = encvid->common;
+    int *level, *run;
+    int r0, r1, r2, r3;
+    int Qq, Rq, q_bits, qp_const, quant;
+    int data, lev, zero_run;
+    int k, ncoeff, idx;
+
+    level = encvid->levelcdc + (cr << 2); /* cb or cr */
+    run = encvid->runcdc + (cr << 2);
+
+    /* 2x2 transform of DC components*/
+    r0 = block[0];
+    r1 = block[4];
+    r2 = block[64];
+    r3 = block[68];
+
+    block[0] = r0 + r1 + r2 + r3;
+    block[4] = r0 - r1 + r2 - r3;
+    block[64] = r0 + r1 - r2 - r3;
+    block[68] = r0 - r1 - r2 + r3;
+
+    Qq    = video->QPc_div_6;
+    Rq    = video->QPc_mod_6;
+    quant = quant_coef[Rq][0];
+    q_bits    = 15 + Qq;
+    if (slice_type == AVC_I_SLICE)
+    {
+        qp_const = (1 << q_bits) / 3;
+    }
+    else
+    {
+        qp_const = (1 << q_bits) / 6;
+    }
+
+    zero_run = 0;
+    ncoeff = 0;
+
+    for (k = 0; k < 4; k++) /* in zigzag scan order */
+    {
+        idx = ((k >> 1) << 6) + ((k & 1) << 2);
+        data = block[idx];
+        if (data > 0)
+        {
+            lev = data * quant + (qp_const << 1);
+        }
+        else
+        {
+            lev = -data * quant + (qp_const << 1);
+        }
+        lev >>= (q_bits + 1);
+        if (lev)
+        {
+            if (data > 0)
+            {
+                level[ncoeff] = lev;
+                block[idx] = lev;
+            }
+            else
+            {
+                level[ncoeff] = -lev;
+                block[idx] = -lev;
+            }
+            run[ncoeff++] = zero_run;
+            zero_run = 0;
+        }
+        else
+        {
+            zero_run++;
+            block[idx] = 0;
+        }
+    }
+    return ncoeff;
+}
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp b/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
new file mode 100644
index 0000000..38a2a15
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/findhalfpel.cpp
@@ -0,0 +1,622 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+/* 3/29/01 fast half-pel search based on neighboring guess */
+/* value ranging from 0 to 4, high complexity (more accurate) to
+   low complexity (less accurate) */
+#define HP_DISTANCE_TH      5 // 2  /* half-pel distance threshold */
+
+#define PREF_16_VEC 129     /* 1MV bias versus 4MVs*/
+
+const static int distance_tab[9][9] =   /* [hp_guess][k] */
+{
+    {0, 1, 1, 1, 1, 1, 1, 1, 1},
+    {1, 0, 1, 2, 3, 4, 3, 2, 1},
+    {1, 0, 0, 0, 1, 2, 3, 2, 1},
+    {1, 2, 1, 0, 1, 2, 3, 4, 3},
+    {1, 2, 1, 0, 0, 0, 1, 2, 3},
+    {1, 4, 3, 2, 1, 0, 1, 2, 3},
+    {1, 2, 3, 2, 1, 0, 0, 0, 1},
+    {1, 2, 3, 4, 3, 2, 1, 0, 1},
+    {1, 0, 1, 2, 3, 2, 1, 0, 0}
+};
+
+#define CLIP_RESULT(x)      if((uint)x > 0xFF){ \
+                 x = 0xFF & (~(x>>31));}
+
+#define CLIP_UPPER16(x)     if((uint)x >= 0x20000000){ \
+        x = 0xFF0000 & (~(x>>31));} \
+        else { \
+        x = (x>>5)&0xFF0000; \
+        }
+
+/*=====================================================================
+    Function:   AVCFindHalfPelMB
+    Date:       10/31/2007
+    Purpose:    Find half pel resolution MV surrounding the full-pel MV
+=====================================================================*/
+
+int AVCFindHalfPelMB(AVCEncObject *encvid, uint8 *cur, AVCMV *mot, uint8 *ncand,
+                     int xpos, int ypos, int hp_guess, int cmvx, int cmvy)
+{
+    AVCPictureData *currPic = encvid->common->currPic;
+    int lx = currPic->pitch;
+    int d, dmin, satd_min;
+    uint8* cand;
+    int lambda_motion = encvid->lambda_motion;
+    uint8 *mvbits = encvid->mvbits;
+    int mvcost;
+    /* list of candidate to go through for half-pel search*/
+    uint8 *subpel_pred = (uint8*) encvid->subpel_pred; // all 16 sub-pel positions
+    uint8 **hpel_cand = (uint8**) encvid->hpel_cand; /* half-pel position */
+
+    int xh[9] = {0, 0, 2, 2, 2, 0, -2, -2, -2};
+    int yh[9] = {0, -2, -2, 0, 2, 2, 2, 0, -2};
+    int xq[8] = {0, 1, 1, 1, 0, -1, -1, -1};
+    int yq[8] = { -1, -1, 0, 1, 1, 1, 0, -1};
+    int h, hmin, q, qmin;
+
+    OSCL_UNUSED_ARG(xpos);
+    OSCL_UNUSED_ARG(ypos);
+    OSCL_UNUSED_ARG(hp_guess);
+
+    GenerateHalfPelPred(subpel_pred, ncand, lx);
+
+    cur = encvid->currYMB; // pre-load current original MB
+
+    cand = hpel_cand[0];
+
+    // find cost for the current full-pel position
+    dmin = SATD_MB(cand, cur, 65535); // get Hadamaard transform SAD
+    mvcost = MV_COST_S(lambda_motion, mot->x, mot->y, cmvx, cmvy);
+    satd_min = dmin;
+    dmin += mvcost;
+    hmin = 0;
+
+    /* find half-pel */
+    for (h = 1; h < 9; h++)
+    {
+        d = SATD_MB(hpel_cand[h], cur, dmin);
+        mvcost = MV_COST_S(lambda_motion, mot->x + xh[h], mot->y + yh[h], cmvx, cmvy);
+        d += mvcost;
+
+        if (d < dmin)
+        {
+            dmin = d;
+            hmin = h;
+            satd_min = d - mvcost;
+        }
+    }
+
+    mot->sad = dmin;
+    mot->x += xh[hmin];
+    mot->y += yh[hmin];
+    encvid->best_hpel_pos = hmin;
+
+    /*** search for quarter-pel ****/
+    GenerateQuartPelPred(encvid->bilin_base[hmin], &(encvid->qpel_cand[0][0]), hmin);
+
+    encvid->best_qpel_pos = qmin = -1;
+
+    for (q = 0; q < 8; q++)
+    {
+        d = SATD_MB(encvid->qpel_cand[q], cur, dmin);
+        mvcost = MV_COST_S(lambda_motion, mot->x + xq[q], mot->y + yq[q], cmvx, cmvy);
+        d += mvcost;
+        if (d < dmin)
+        {
+            dmin = d;
+            qmin = q;
+            satd_min = d - mvcost;
+        }
+    }
+
+    if (qmin != -1)
+    {
+        mot->sad = dmin;
+        mot->x += xq[qmin];
+        mot->y += yq[qmin];
+        encvid->best_qpel_pos = qmin;
+    }
+
+    return satd_min;
+}
+
+
+
+/** This function generates sub-pel prediction around the full-pel candidate.
+Each sub-pel position array is 20 pixel wide (for word-alignment) and 17 pixel tall. */
+/** The sub-pel position is labeled in spiral manner from the center. */
+
+void GenerateHalfPelPred(uint8* subpel_pred, uint8 *ncand, int lx)
+{
+    /* let's do straightforward way first */
+    uint8 *ref;
+    uint8 *dst;
+    uint8 tmp8;
+    int32 tmp32;
+    int16 tmp_horz[18*22], *dst_16, *src_16;
+    register int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; // temp register
+    int msk;
+    int i, j;
+
+    /* first copy full-pel to the first array */
+    /* to be optimized later based on byte-offset load */
+    ref = ncand - 3 - lx - (lx << 1); /* move back (-3,-3) */
+    dst = subpel_pred;
+
+    dst -= 4; /* offset */
+    for (j = 0; j < 22; j++) /* 24x22 */
+    {
+        i = 6;
+        while (i > 0)
+        {
+            tmp32 = *ref++;
+            tmp8 = *ref++;
+            tmp32 |= (tmp8 << 8);
+            tmp8 = *ref++;
+            tmp32 |= (tmp8 << 16);
+            tmp8 = *ref++;
+            tmp32 |= (tmp8 << 24);
+            *((uint32*)(dst += 4)) = tmp32;
+            i--;
+        }
+        ref += (lx - 24);
+    }
+
+    /* from the first array, we do horizontal interp */
+    ref = subpel_pred + 2;
+    dst_16 = tmp_horz; /* 17 x 22 */
+
+    for (j = 4; j > 0; j--)
+    {
+        for (i = 16; i > 0; i -= 4)
+        {
+            a = ref[-2];
+            b = ref[-1];
+            c = ref[0];
+            d = ref[1];
+            e = ref[2];
+            f = ref[3];
+            *dst_16++ = a + f - 5 * (b + e) + 20 * (c + d);
+            a = ref[4];
+            *dst_16++ = b + a - 5 * (c + f) + 20 * (d + e);
+            b = ref[5];
+            *dst_16++ = c + b - 5 * (d + a) + 20 * (e + f);
+            c = ref[6];
+            *dst_16++ = d + c - 5 * (e + b) + 20 * (f + a);
+
+            ref += 4;
+        }
+        /* do the 17th column here */
+        d = ref[3];
+        *dst_16 =  e + d - 5 * (f + c) + 20 * (a + b);
+        dst_16 += 2; /* stride for tmp_horz is 18 */
+        ref += 8;  /* stride for ref is 24 */
+        if (j == 3)  // move 18 lines down
+        {
+            dst_16 += 324;//18*18;
+            ref += 432;//18*24;
+        }
+    }
+
+    ref -= 480;//20*24;
+    dst_16 -= 360;//20*18;
+    dst = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE; /* go to the 14th array 17x18*/
+
+    for (j = 18; j > 0; j--)
+    {
+        for (i = 16; i > 0; i -= 4)
+        {
+            a = ref[-2];
+            b = ref[-1];
+            c = ref[0];
+            d = ref[1];
+            e = ref[2];
+            f = ref[3];
+            tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
+            *dst_16++ = tmp32;
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *dst++ = tmp32;
+
+            a = ref[4];
+            tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
+            *dst_16++ = tmp32;
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *dst++ = tmp32;
+
+            b = ref[5];
+            tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
+            *dst_16++ = tmp32;
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *dst++ = tmp32;
+
+            c = ref[6];
+            tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
+            *dst_16++ = tmp32;
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *dst++ = tmp32;
+
+            ref += 4;
+        }
+        /* do the 17th column here */
+        d = ref[3];
+        tmp32 =  e + d - 5 * (f + c) + 20 * (a + b);
+        *dst_16 = tmp32;
+        tmp32 = (tmp32 + 16) >> 5;
+        CLIP_RESULT(tmp32)
+        *dst = tmp32;
+
+        dst += 8;  /* stride for dst is 24 */
+        dst_16 += 2; /* stride for tmp_horz is 18 */
+        ref += 8;  /* stride for ref is 24 */
+    }
+
+
+    /* Do middle point filtering*/
+    src_16 = tmp_horz; /* 17 x 22 */
+    dst = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE; /* 12th array 17x17*/
+    dst -= 24; // offset
+    for (i = 0; i < 17; i++)
+    {
+        for (j = 16; j > 0; j -= 4)
+        {
+            a = *src_16;
+            b = *(src_16 += 18);
+            c = *(src_16 += 18);
+            d = *(src_16 += 18);
+            e = *(src_16 += 18);
+            f = *(src_16 += 18);
+
+            tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
+            tmp32 = (tmp32 + 512) >> 10;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;
+
+            a = *(src_16 += 18);
+            tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
+            tmp32 = (tmp32 + 512) >> 10;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;
+
+            b = *(src_16 += 18);
+            tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
+            tmp32 = (tmp32 + 512) >> 10;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;
+
+            c = *(src_16 += 18);
+            tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
+            tmp32 = (tmp32 + 512) >> 10;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;
+
+            src_16 -= (18 << 2);
+        }
+
+        d = src_16[90]; // 18*5
+        tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
+        tmp32 = (tmp32 + 512) >> 10;
+        CLIP_RESULT(tmp32)
+        dst[24] = tmp32;
+
+        src_16 -= ((18 << 4) - 1);
+        dst -= ((24 << 4) - 1);
+    }
+
+    /* do vertical interpolation */
+    ref = subpel_pred + 2;
+    dst = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE; /* 10th array 18x17 */
+    dst -= 24; // offset
+
+    for (i = 2; i > 0; i--)
+    {
+        for (j = 16; j > 0; j -= 4)
+        {
+            a = *ref;
+            b = *(ref += 24);
+            c = *(ref += 24);
+            d = *(ref += 24);
+            e = *(ref += 24);
+            f = *(ref += 24);
+
+            tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            a = *(ref += 24);
+            tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            b = *(ref += 24);
+            tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            c = *(ref += 24);
+            tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            ref -= (24 << 2);
+        }
+
+        d = ref[120]; // 24*5
+        tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
+        tmp32 = (tmp32 + 16) >> 5;
+        CLIP_RESULT(tmp32)
+        dst[24] = tmp32;  // 10th
+
+        dst -= ((24 << 4) - 1);
+        ref -= ((24 << 4) - 1);
+    }
+
+    // note that using SIMD here doesn't help much, the cycle almost stays the same
+    // one can just use the above code and change the for(i=2 to for(i=18
+    for (i = 16; i > 0; i -= 4)
+    {
+        msk = 0;
+        for (j = 17; j > 0; j--)
+        {
+            a = *((uint32*)ref); /* load 4 bytes */
+            b = (a >> 8) & 0xFF00FF; /* second and fourth byte */
+            a &= 0xFF00FF;
+
+            c = *((uint32*)(ref + 120));
+            d = (c >> 8) & 0xFF00FF;
+            c &= 0xFF00FF;
+
+            a += c;
+            b += d;
+
+            e = *((uint32*)(ref + 72)); /* e, f */
+            f = (e >> 8) & 0xFF00FF;
+            e &= 0xFF00FF;
+
+            c = *((uint32*)(ref + 48)); /* c, d */
+            d = (c >> 8) & 0xFF00FF;
+            c &= 0xFF00FF;
+
+            c += e;
+            d += f;
+
+            a += 20 * c;
+            b += 20 * d;
+            a += 0x100010;
+            b += 0x100010;
+
+            e = *((uint32*)(ref += 24)); /* e, f */
+            f = (e >> 8) & 0xFF00FF;
+            e &= 0xFF00FF;
+
+            c = *((uint32*)(ref + 72)); /* c, d */
+            d = (c >> 8) & 0xFF00FF;
+            c &= 0xFF00FF;
+
+            c += e;
+            d += f;
+
+            a -= 5 * c;
+            b -= 5 * d;
+
+            c = a << 16;
+            d = b << 16;
+            CLIP_UPPER16(a)
+            CLIP_UPPER16(c)
+            CLIP_UPPER16(b)
+            CLIP_UPPER16(d)
+
+            a |= (c >> 16);
+            b |= (d >> 16);
+            //  a>>=5;
+            //  b>>=5;
+            /* clip */
+            //  msk |= b;  msk|=a;
+            //  a &= 0xFF00FF;
+            //  b &= 0xFF00FF;
+            a |= (b << 8);  /* pack it back */
+
+            *((uint16*)(dst += 24)) = a & 0xFFFF; //dst is not word-aligned.
+            *((uint16*)(dst + 2)) = a >> 16;
+
+        }
+        dst -= 404; // 24*17-4
+        ref -= 404;
+        /*      if(msk & 0xFF00FF00) // need clipping
+                {
+                    VertInterpWClip(dst,ref); // re-do 4 column with clip
+                }*/
+    }
+
+    return ;
+}
+
+void VertInterpWClip(uint8 *dst, uint8 *ref)
+{
+    int i, j;
+    int a, b, c, d, e, f;
+    int32 tmp32;
+
+    dst -= 4;
+    ref -= 4;
+
+    for (i = 4; i > 0; i--)
+    {
+        for (j = 16; j > 0; j -= 4)
+        {
+            a = *ref;
+            b = *(ref += 24);
+            c = *(ref += 24);
+            d = *(ref += 24);
+            e = *(ref += 24);
+            f = *(ref += 24);
+
+            tmp32 = a + f - 5 * (b + e) + 20 * (c + d);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            a = *(ref += 24);
+            tmp32 = b + a - 5 * (c + f) + 20 * (d + e);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            b = *(ref += 24);
+            tmp32 = c + b - 5 * (d + a) + 20 * (e + f);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            c = *(ref += 24);
+            tmp32 = d + c - 5 * (e + b) + 20 * (f + a);
+            tmp32 = (tmp32 + 16) >> 5;
+            CLIP_RESULT(tmp32)
+            *(dst += 24) = tmp32;  // 10th
+
+            ref -= (24 << 2);
+        }
+
+        d = ref[120]; // 24*5
+        tmp32 = e + d - 5 * (f + c) + 20 * (a + b);
+        tmp32 = (tmp32 + 16) >> 5;
+        CLIP_RESULT(tmp32)
+        dst[24] = tmp32;  // 10th
+
+        dst -= ((24 << 4) - 1);
+        ref -= ((24 << 4) - 1);
+    }
+
+    return ;
+}
+
+
+void GenerateQuartPelPred(uint8 **bilin_base, uint8 *qpel_cand, int hpel_pos)
+{
+    // for even value of hpel_pos, start with pattern 1, otherwise, start with pattern 2
+    int i, j;
+
+    uint8 *c1 = qpel_cand;
+    uint8 *tl = bilin_base[0];
+    uint8 *tr = bilin_base[1];
+    uint8 *bl = bilin_base[2];
+    uint8 *br = bilin_base[3];
+    int a, b, c, d;
+    int offset = 1 - (384 * 7);
+
+    if (!(hpel_pos&1)) // diamond pattern
+    {
+        j = 16;
+        while (j--)
+        {
+            i = 16;
+            while (i--)
+            {
+                d = tr[24];
+                a = *tr++;
+                b = bl[1];
+                c = *br++;
+
+                *c1 = (c + a + 1) >> 1;
+                *(c1 += 384) = (b + a + 1) >> 1; /* c2 */
+                *(c1 += 384) = (b + c + 1) >> 1; /* c3 */
+                *(c1 += 384) = (b + d + 1) >> 1; /* c4 */
+
+                b = *bl++;
+
+                *(c1 += 384) = (c + d + 1) >> 1;  /* c5 */
+                *(c1 += 384) = (b + d + 1) >> 1;  /* c6 */
+                *(c1 += 384) = (b + c + 1) >> 1;  /* c7 */
+                *(c1 += 384) = (b + a + 1) >> 1;  /* c8 */
+
+                c1 += offset;
+            }
+            // advance to the next line, pitch is 24
+            tl += 8;
+            tr += 8;
+            bl += 8;
+            br += 8;
+            c1 += 8;
+        }
+    }
+    else // star pattern
+    {
+        j = 16;
+        while (j--)
+        {
+            i = 16;
+            while (i--)
+            {
+                a = *br++;
+                b = *tr++;
+                c = tl[1];
+                *c1 = (a + b + 1) >> 1;
+                b = bl[1];
+                *(c1 += 384) = (a + c + 1) >> 1; /* c2 */
+                c = tl[25];
+                *(c1 += 384) = (a + b + 1) >> 1; /* c3 */
+                b = tr[23];
+                *(c1 += 384) = (a + c + 1) >> 1; /* c4 */
+                c = tl[24];
+                *(c1 += 384) = (a + b + 1) >> 1; /* c5 */
+                b = *bl++;
+                *(c1 += 384) = (a + c + 1) >> 1; /* c6 */
+                c = *tl++;
+                *(c1 += 384) = (a + b + 1) >> 1; /* c7 */
+                *(c1 += 384) = (a + c + 1) >> 1; /* c8 */
+
+                c1 += offset;
+            }
+            // advance to the next line, pitch is 24
+            tl += 8;
+            tr += 8;
+            bl += 8;
+            br += 8;
+            c1 += 8;
+        }
+    }
+
+    return ;
+}
+
+
+/* assuming cand always has a pitch of 24 */
+int SATD_MB(uint8 *cand, uint8 *cur, int dmin)
+{
+    int cost;
+
+
+    dmin = (dmin << 16) | 24;
+    cost = AVCSAD_Macroblock_C(cand, cur, dmin, NULL);
+
+    return cost;
+}
+
+
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/header.cpp b/media/libstagefright/codecs/avc/enc/src/header.cpp
new file mode 100644
index 0000000..9acff9e
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/header.cpp
@@ -0,0 +1,917 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+#include "avcenc_api.h"
+
+/** see subclause 7.4.2.1 */
+/* no need for checking the valid range , already done in SetEncodeParam(),
+if we have to send another SPS, the ranges should be verified first before
+users call PVAVCEncodeSPS() */
+AVCEnc_Status EncodeSPS(AVCEncObject *encvid, AVCEncBitstream *stream)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSeqParamSet *seqParam = video->currSeqParams;
+    AVCVUIParams *vui = &(seqParam->vui_parameters);
+    int i;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+
+    //DEBUG_LOG(userData,AVC_LOGTYPE_INFO,"EncodeSPS",-1,-1);
+
+    status = BitstreamWriteBits(stream, 8, seqParam->profile_idc);
+    status = BitstreamWrite1Bit(stream, seqParam->constrained_set0_flag);
+    status = BitstreamWrite1Bit(stream, seqParam->constrained_set1_flag);
+    status = BitstreamWrite1Bit(stream, seqParam->constrained_set2_flag);
+    status = BitstreamWrite1Bit(stream, seqParam->constrained_set3_flag);
+    status = BitstreamWriteBits(stream, 4, 0);  /* forbidden zero bits */
+    if (status != AVCENC_SUCCESS)  /* we can check after each write also */
+    {
+        return status;
+    }
+
+    status = BitstreamWriteBits(stream, 8, seqParam->level_idc);
+    status = ue_v(stream, seqParam->seq_parameter_set_id);
+    status = ue_v(stream, seqParam->log2_max_frame_num_minus4);
+    status = ue_v(stream, seqParam->pic_order_cnt_type);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if (seqParam->pic_order_cnt_type == 0)
+    {
+        status = ue_v(stream, seqParam->log2_max_pic_order_cnt_lsb_minus4);
+    }
+    else if (seqParam->pic_order_cnt_type == 1)
+    {
+        status = BitstreamWrite1Bit(stream, seqParam->delta_pic_order_always_zero_flag);
+        status = se_v(stream, seqParam->offset_for_non_ref_pic); /* upto 32 bits */
+        status = se_v(stream, seqParam->offset_for_top_to_bottom_field); /* upto 32 bits */
+        status = ue_v(stream, seqParam->num_ref_frames_in_pic_order_cnt_cycle);
+
+        for (i = 0; i < (int)(seqParam->num_ref_frames_in_pic_order_cnt_cycle); i++)
+        {
+            status = se_v(stream, seqParam->offset_for_ref_frame[i]); /* upto 32 bits */
+        }
+    }
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = ue_v(stream, seqParam->num_ref_frames);
+    status = BitstreamWrite1Bit(stream, seqParam->gaps_in_frame_num_value_allowed_flag);
+    status = ue_v(stream, seqParam->pic_width_in_mbs_minus1);
+    status = ue_v(stream, seqParam->pic_height_in_map_units_minus1);
+    status = BitstreamWrite1Bit(stream, seqParam->frame_mbs_only_flag);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+    /* if frame_mbs_only_flag is 0, then write, mb_adaptive_frame_field_frame here */
+
+    status = BitstreamWrite1Bit(stream, seqParam->direct_8x8_inference_flag);
+    status = BitstreamWrite1Bit(stream, seqParam->frame_cropping_flag);
+    if (seqParam->frame_cropping_flag)
+    {
+        status = ue_v(stream, seqParam->frame_crop_left_offset);
+        status = ue_v(stream, seqParam->frame_crop_right_offset);
+        status = ue_v(stream, seqParam->frame_crop_top_offset);
+        status = ue_v(stream, seqParam->frame_crop_bottom_offset);
+    }
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = BitstreamWrite1Bit(stream, seqParam->vui_parameters_present_flag);
+    if (seqParam->vui_parameters_present_flag)
+    {
+        /* not supported */
+        //return AVCENC_SPS_FAIL;
+        EncodeVUI(stream, vui);
+    }
+
+    return status;
+}
+
+
+void EncodeVUI(AVCEncBitstream* stream, AVCVUIParams* vui)
+{
+    int temp;
+
+    temp = vui->aspect_ratio_info_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWriteBits(stream, 8, vui->aspect_ratio_idc);
+        if (vui->aspect_ratio_idc == 255)
+        {
+            BitstreamWriteBits(stream, 16, vui->sar_width);
+            BitstreamWriteBits(stream, 16, vui->sar_height);
+        }
+    }
+    temp = vui->overscan_info_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWrite1Bit(stream, vui->overscan_appropriate_flag);
+    }
+    temp = vui->video_signal_type_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWriteBits(stream, 3, vui->video_format);
+        BitstreamWrite1Bit(stream, vui->video_full_range_flag);
+        temp = vui->colour_description_present_flag;
+        BitstreamWrite1Bit(stream, temp);
+        if (temp)
+        {
+            BitstreamWriteBits(stream, 8, vui->colour_primaries);
+            BitstreamWriteBits(stream, 8, vui->transfer_characteristics);
+            BitstreamWriteBits(stream, 8, vui->matrix_coefficients);
+        }
+    }
+    temp = vui->chroma_location_info_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        ue_v(stream, vui->chroma_sample_loc_type_top_field);
+        ue_v(stream, vui->chroma_sample_loc_type_bottom_field);
+    }
+
+    temp = vui->timing_info_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWriteBits(stream, 32, vui->num_units_in_tick);
+        BitstreamWriteBits(stream, 32, vui->time_scale);
+        BitstreamWrite1Bit(stream, vui->fixed_frame_rate_flag);
+    }
+
+    temp = vui->nal_hrd_parameters_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        EncodeHRD(stream, &(vui->nal_hrd_parameters));
+    }
+    temp = vui->vcl_hrd_parameters_present_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        EncodeHRD(stream, &(vui->vcl_hrd_parameters));
+    }
+    if (vui->nal_hrd_parameters_present_flag || vui->vcl_hrd_parameters_present_flag)
+    {
+        BitstreamWrite1Bit(stream, vui->low_delay_hrd_flag);
+    }
+    BitstreamWrite1Bit(stream, vui->pic_struct_present_flag);
+    temp = vui->bitstream_restriction_flag;
+    BitstreamWrite1Bit(stream, temp);
+    if (temp)
+    {
+        BitstreamWrite1Bit(stream, vui->motion_vectors_over_pic_boundaries_flag);
+        ue_v(stream, vui->max_bytes_per_pic_denom);
+        ue_v(stream, vui->max_bits_per_mb_denom);
+        ue_v(stream, vui->log2_max_mv_length_horizontal);
+        ue_v(stream, vui->log2_max_mv_length_vertical);
+        ue_v(stream, vui->max_dec_frame_reordering);
+        ue_v(stream, vui->max_dec_frame_buffering);
+    }
+
+    return ;
+}
+
+
+void EncodeHRD(AVCEncBitstream* stream, AVCHRDParams* hrd)
+{
+    int i;
+
+    ue_v(stream, hrd->cpb_cnt_minus1);
+    BitstreamWriteBits(stream, 4, hrd->bit_rate_scale);
+    BitstreamWriteBits(stream, 4, hrd->cpb_size_scale);
+    for (i = 0; i <= (int)hrd->cpb_cnt_minus1; i++)
+    {
+        ue_v(stream, hrd->bit_rate_value_minus1[i]);
+        ue_v(stream, hrd->cpb_size_value_minus1[i]);
+        ue_v(stream, hrd->cbr_flag[i]);
+    }
+    BitstreamWriteBits(stream, 5, hrd->initial_cpb_removal_delay_length_minus1);
+    BitstreamWriteBits(stream, 5, hrd->cpb_removal_delay_length_minus1);
+    BitstreamWriteBits(stream, 5, hrd->dpb_output_delay_length_minus1);
+    BitstreamWriteBits(stream, 5, hrd->time_offset_length);
+
+    return ;
+}
+
+
+
+/** see subclause 7.4.2.2 */
+/* no need for checking the valid range , already done in SetEncodeParam().
+If we have to send another SPS, the ranges should be verified first before
+users call PVAVCEncodeSPS()*/
+AVCEnc_Status EncodePPS(AVCEncObject *encvid, AVCEncBitstream *stream)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCPicParamSet *picParam = video->currPicParams;
+    int i, iGroup, numBits;
+    uint temp;
+
+    status = ue_v(stream, picParam->pic_parameter_set_id);
+    status = ue_v(stream, picParam->seq_parameter_set_id);
+    status = BitstreamWrite1Bit(stream, picParam->entropy_coding_mode_flag);
+    status = BitstreamWrite1Bit(stream, picParam->pic_order_present_flag);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = ue_v(stream, picParam->num_slice_groups_minus1);
+    if (picParam->num_slice_groups_minus1 > 0)
+    {
+        status = ue_v(stream, picParam->slice_group_map_type);
+        if (picParam->slice_group_map_type == 0)
+        {
+            for (iGroup = 0; iGroup <= (int)picParam->num_slice_groups_minus1; iGroup++)
+            {
+                status = ue_v(stream, picParam->run_length_minus1[iGroup]);
+            }
+        }
+        else if (picParam->slice_group_map_type == 2)
+        {
+            for (iGroup = 0; iGroup < (int)picParam->num_slice_groups_minus1; iGroup++)
+            {
+                status = ue_v(stream, picParam->top_left[iGroup]);
+                status = ue_v(stream, picParam->bottom_right[iGroup]);
+            }
+        }
+        else if (picParam->slice_group_map_type == 3 ||
+                 picParam->slice_group_map_type == 4 ||
+                 picParam->slice_group_map_type == 5)
+        {
+            status = BitstreamWrite1Bit(stream, picParam->slice_group_change_direction_flag);
+            status = ue_v(stream, picParam->slice_group_change_rate_minus1);
+        }
+        else /*if(picParam->slice_group_map_type == 6)*/
+        {
+            status = ue_v(stream, picParam->pic_size_in_map_units_minus1);
+
+            numBits = 0;/* ceil(log2(num_slice_groups_minus1+1)) bits */
+            i = picParam->num_slice_groups_minus1;
+            while (i > 0)
+            {
+                numBits++;
+                i >>= 1;
+            }
+
+            for (i = 0; i <= (int)picParam->pic_size_in_map_units_minus1; i++)
+            {
+                status = BitstreamWriteBits(stream, numBits, picParam->slice_group_id[i]);
+            }
+        }
+    }
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = ue_v(stream, picParam->num_ref_idx_l0_active_minus1);
+    status = ue_v(stream, picParam->num_ref_idx_l1_active_minus1);
+    status = BitstreamWrite1Bit(stream, picParam->weighted_pred_flag);
+    status = BitstreamWriteBits(stream, 2, picParam->weighted_bipred_idc);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = se_v(stream, picParam->pic_init_qp_minus26);
+    status = se_v(stream, picParam->pic_init_qs_minus26);
+    status = se_v(stream, picParam->chroma_qp_index_offset);
+
+    temp = picParam->deblocking_filter_control_present_flag << 2;
+    temp |= (picParam->constrained_intra_pred_flag << 1);
+    temp |= picParam->redundant_pic_cnt_present_flag;
+
+    status = BitstreamWriteBits(stream, 3, temp);
+
+    return status;
+}
+
+/** see subclause 7.4.3 */
+AVCEnc_Status EncodeSliceHeader(AVCEncObject *encvid, AVCEncBitstream *stream)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCPicParamSet *currPPS = video->currPicParams;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    int slice_type, temp, i;
+    int num_bits;
+
+    num_bits = (stream->write_pos << 3) - stream->bit_left;
+
+    status = ue_v(stream, sliceHdr->first_mb_in_slice);
+
+    slice_type = video->slice_type;
+
+    if (video->mbNum == 0) /* first mb in frame */
+    {
+        status = ue_v(stream, sliceHdr->slice_type);
+    }
+    else
+    {
+        status = ue_v(stream, slice_type);
+    }
+
+    status = ue_v(stream, sliceHdr->pic_parameter_set_id);
+
+    status = BitstreamWriteBits(stream, currSPS->log2_max_frame_num_minus4 + 4, sliceHdr->frame_num);
+
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+    /* if frame_mbs_only_flag is 0, encode field_pic_flag, bottom_field_flag here */
+
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        status = ue_v(stream, sliceHdr->idr_pic_id);
+    }
+
+    if (currSPS->pic_order_cnt_type == 0)
+    {
+        status = BitstreamWriteBits(stream, currSPS->log2_max_pic_order_cnt_lsb_minus4 + 4,
+                                    sliceHdr->pic_order_cnt_lsb);
+
+        if (currPPS->pic_order_present_flag && !sliceHdr->field_pic_flag)
+        {
+            status = se_v(stream, sliceHdr->delta_pic_order_cnt_bottom); /* 32 bits */
+        }
+    }
+    if (currSPS->pic_order_cnt_type == 1 && !currSPS->delta_pic_order_always_zero_flag)
+    {
+        status = se_v(stream, sliceHdr->delta_pic_order_cnt[0]);    /* 32 bits */
+        if (currPPS->pic_order_present_flag && !sliceHdr->field_pic_flag)
+        {
+            status = se_v(stream, sliceHdr->delta_pic_order_cnt[1]); /* 32 bits */
+        }
+    }
+
+    if (currPPS->redundant_pic_cnt_present_flag)
+    {
+        status = ue_v(stream, sliceHdr->redundant_pic_cnt);
+    }
+
+    if (slice_type == AVC_B_SLICE)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->direct_spatial_mv_pred_flag);
+    }
+
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE || slice_type == AVC_B_SLICE)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->num_ref_idx_active_override_flag);
+        if (sliceHdr->num_ref_idx_active_override_flag)
+        {
+            /* we shouldn't enter this part at all */
+            status = ue_v(stream, sliceHdr->num_ref_idx_l0_active_minus1);
+            if (slice_type == AVC_B_SLICE)
+            {
+                status = ue_v(stream, sliceHdr->num_ref_idx_l1_active_minus1);
+            }
+        }
+    }
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    /* ref_pic_list_reordering() */
+    status = ref_pic_list_reordering(video, stream, sliceHdr, slice_type);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if ((currPPS->weighted_pred_flag && (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE)) ||
+            (currPPS->weighted_bipred_idc == 1 && slice_type == AVC_B_SLICE))
+    {
+        //      pred_weight_table(); // not supported !!
+        return AVCENC_PRED_WEIGHT_TAB_FAIL;
+    }
+
+    if (video->nal_ref_idc != 0)
+    {
+        status = dec_ref_pic_marking(video, stream, sliceHdr);
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+    }
+
+    if (currPPS->entropy_coding_mode_flag && slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
+    {
+        return AVCENC_CABAC_FAIL;
+        /*      ue_v(stream,&(sliceHdr->cabac_init_idc));
+                if(sliceHdr->cabac_init_idc > 2){
+                    // not supported !!!!
+                }*/
+    }
+
+    status = se_v(stream, sliceHdr->slice_qp_delta);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    if (slice_type == AVC_SP_SLICE || slice_type == AVC_SI_SLICE)
+    {
+        if (slice_type == AVC_SP_SLICE)
+        {
+            status = BitstreamWrite1Bit(stream, sliceHdr->sp_for_switch_flag);
+            /* if sp_for_switch_flag is 0, P macroblocks in SP slice is decoded using
+            SP decoding process for non-switching pictures in 8.6.1 */
+            /* else, P macroblocks in SP slice is decoded using SP and SI decoding
+            process for switching picture in 8.6.2 */
+        }
+        status = se_v(stream, sliceHdr->slice_qs_delta);
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+    }
+
+    if (currPPS->deblocking_filter_control_present_flag)
+    {
+
+        status = ue_v(stream, sliceHdr->disable_deblocking_filter_idc);
+
+        if (sliceHdr->disable_deblocking_filter_idc != 1)
+        {
+            status = se_v(stream, sliceHdr->slice_alpha_c0_offset_div2);
+
+            status = se_v(stream, sliceHdr->slice_beta_offset_div_2);
+        }
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+    }
+
+    if (currPPS->num_slice_groups_minus1 > 0 && currPPS->slice_group_map_type >= 3
+            && currPPS->slice_group_map_type <= 5)
+    {
+        /* Ceil(Log2(PicSizeInMapUnits/(float)SliceGroupChangeRate + 1)) */
+        temp = video->PicSizeInMapUnits / video->SliceGroupChangeRate;
+        if (video->PicSizeInMapUnits % video->SliceGroupChangeRate)
+        {
+            temp++;
+        }
+        i = 0;
+        while (temp > 1)
+        {
+            temp >>= 1;
+            i++;
+        }
+
+        BitstreamWriteBits(stream, i, sliceHdr->slice_group_change_cycle);
+    }
+
+
+    encvid->rateCtrl->NumberofHeaderBits += (stream->write_pos << 3) - stream->bit_left - num_bits;
+
+    return AVCENC_SUCCESS;
+}
+
+/** see subclause 7.4.3.1 */
+AVCEnc_Status ref_pic_list_reordering(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr, int slice_type)
+{
+    (void)(video);
+    int i;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+
+    if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->ref_pic_list_reordering_flag_l0);
+        if (sliceHdr->ref_pic_list_reordering_flag_l0)
+        {
+            i = 0;
+            do
+            {
+                status = ue_v(stream, sliceHdr->reordering_of_pic_nums_idc_l0[i]);
+                if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 0 ||
+                        sliceHdr->reordering_of_pic_nums_idc_l0[i] == 1)
+                {
+                    status = ue_v(stream, sliceHdr->abs_diff_pic_num_minus1_l0[i]);
+                    /* this check should be in InitSlice(), if we ever use it */
+                    /*if(sliceHdr->reordering_of_pic_nums_idc_l0[i] == 0 &&
+                        sliceHdr->abs_diff_pic_num_minus1_l0[i] > video->MaxPicNum/2 -1)
+                    {
+                        return AVCENC_REF_PIC_REORDER_FAIL; // out of range
+                    }
+                    if(sliceHdr->reordering_of_pic_nums_idc_l0[i] == 1 &&
+                        sliceHdr->abs_diff_pic_num_minus1_l0[i] > video->MaxPicNum/2 -2)
+                    {
+                        return AVCENC_REF_PIC_REORDER_FAIL; // out of range
+                    }*/
+                }
+                else if (sliceHdr->reordering_of_pic_nums_idc_l0[i] == 2)
+                {
+                    status = ue_v(stream, sliceHdr->long_term_pic_num_l0[i]);
+                }
+                i++;
+            }
+            while (sliceHdr->reordering_of_pic_nums_idc_l0[i] != 3
+                    && i <= (int)sliceHdr->num_ref_idx_l0_active_minus1 + 1) ;
+        }
+    }
+    if (slice_type == AVC_B_SLICE)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->ref_pic_list_reordering_flag_l1);
+        if (sliceHdr->ref_pic_list_reordering_flag_l1)
+        {
+            i = 0;
+            do
+            {
+                status = ue_v(stream, sliceHdr->reordering_of_pic_nums_idc_l1[i]);
+                if (sliceHdr->reordering_of_pic_nums_idc_l1[i] == 0 ||
+                        sliceHdr->reordering_of_pic_nums_idc_l1[i] == 1)
+                {
+                    status = ue_v(stream, sliceHdr->abs_diff_pic_num_minus1_l1[i]);
+                    /* This check should be in InitSlice() if we ever use it
+                    if(sliceHdr->reordering_of_pic_nums_idc_l1[i] == 0 &&
+                        sliceHdr->abs_diff_pic_num_minus1_l1[i] > video->MaxPicNum/2 -1)
+                    {
+                        return AVCENC_REF_PIC_REORDER_FAIL; // out of range
+                    }
+                    if(sliceHdr->reordering_of_pic_nums_idc_l1[i] == 1 &&
+                        sliceHdr->abs_diff_pic_num_minus1_l1[i] > video->MaxPicNum/2 -2)
+                    {
+                        return AVCENC_REF_PIC_REORDER_FAIL; // out of range
+                    }*/
+                }
+                else if (sliceHdr->reordering_of_pic_nums_idc_l1[i] == 2)
+                {
+                    status = ue_v(stream, sliceHdr->long_term_pic_num_l1[i]);
+                }
+                i++;
+            }
+            while (sliceHdr->reordering_of_pic_nums_idc_l1[i] != 3
+                    && i <= (int)sliceHdr->num_ref_idx_l1_active_minus1 + 1) ;
+        }
+    }
+
+    return status;
+}
+
+/** see subclause 7.4.3.3 */
+AVCEnc_Status dec_ref_pic_marking(AVCCommonObj *video, AVCEncBitstream *stream, AVCSliceHeader *sliceHdr)
+{
+    int i;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->no_output_of_prior_pics_flag);
+        status = BitstreamWrite1Bit(stream, sliceHdr->long_term_reference_flag);
+        if (sliceHdr->long_term_reference_flag == 0) /* used for short-term */
+        {
+            video->MaxLongTermFrameIdx = -1; /* no long-term frame indx */
+        }
+        else /* used for long-term */
+        {
+            video->MaxLongTermFrameIdx = 0;
+            video->LongTermFrameIdx = 0;
+        }
+    }
+    else
+    {
+        status = BitstreamWrite1Bit(stream, sliceHdr->adaptive_ref_pic_marking_mode_flag); /* default to zero */
+        if (sliceHdr->adaptive_ref_pic_marking_mode_flag)
+        {
+            i = 0;
+            do
+            {
+                status = ue_v(stream, sliceHdr->memory_management_control_operation[i]);
+                if (sliceHdr->memory_management_control_operation[i] == 1 ||
+                        sliceHdr->memory_management_control_operation[i] == 3)
+                {
+                    status = ue_v(stream, sliceHdr->difference_of_pic_nums_minus1[i]);
+                }
+                if (sliceHdr->memory_management_control_operation[i] == 2)
+                {
+                    status = ue_v(stream, sliceHdr->long_term_pic_num[i]);
+                }
+                if (sliceHdr->memory_management_control_operation[i] == 3 ||
+                        sliceHdr->memory_management_control_operation[i] == 6)
+                {
+                    status = ue_v(stream, sliceHdr->long_term_frame_idx[i]);
+                }
+                if (sliceHdr->memory_management_control_operation[i] == 4)
+                {
+                    status = ue_v(stream, sliceHdr->max_long_term_frame_idx_plus1[i]);
+                }
+                i++;
+            }
+            while (sliceHdr->memory_management_control_operation[i] != 0 && i < MAX_DEC_REF_PIC_MARKING);
+            if (i >= MAX_DEC_REF_PIC_MARKING && sliceHdr->memory_management_control_operation[i] != 0)
+            {
+                return AVCENC_DEC_REF_PIC_MARK_FAIL; /* we're screwed!!, not enough memory */
+            }
+        }
+    }
+
+    return status;
+}
+
+/* see subclause 8.2.1 Decoding process for picture order count.
+See also PostPOC() for initialization of some variables. */
+AVCEnc_Status InitPOC(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCFrameIO  *currInput = encvid->currInput;
+    int i;
+
+    switch (currSPS->pic_order_cnt_type)
+    {
+        case 0: /* POC MODE 0 , subclause 8.2.1.1 */
+            /* encoding part */
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                encvid->dispOrdPOCRef = currInput->disp_order;
+            }
+            while (currInput->disp_order < encvid->dispOrdPOCRef)
+            {
+                encvid->dispOrdPOCRef -= video->MaxPicOrderCntLsb;
+            }
+            sliceHdr->pic_order_cnt_lsb = currInput->disp_order - encvid->dispOrdPOCRef;
+            while (sliceHdr->pic_order_cnt_lsb >= video->MaxPicOrderCntLsb)
+            {
+                sliceHdr->pic_order_cnt_lsb -= video->MaxPicOrderCntLsb;
+            }
+            /* decoding part */
+            /* Calculate the MSBs of current picture */
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                video->prevPicOrderCntMsb = 0;
+                video->prevPicOrderCntLsb = 0;
+            }
+            if (sliceHdr->pic_order_cnt_lsb  <  video->prevPicOrderCntLsb  &&
+                    (video->prevPicOrderCntLsb - sliceHdr->pic_order_cnt_lsb)  >= (video->MaxPicOrderCntLsb / 2))
+                video->PicOrderCntMsb = video->prevPicOrderCntMsb + video->MaxPicOrderCntLsb;
+            else if (sliceHdr->pic_order_cnt_lsb  >  video->prevPicOrderCntLsb  &&
+                     (sliceHdr->pic_order_cnt_lsb - video->prevPicOrderCntLsb)  > (video->MaxPicOrderCntLsb / 2))
+                video->PicOrderCntMsb = video->prevPicOrderCntMsb - video->MaxPicOrderCntLsb;
+            else
+                video->PicOrderCntMsb = video->prevPicOrderCntMsb;
+
+            /* JVT-I010 page 81 is different from JM7.3 */
+            if (!sliceHdr->field_pic_flag || !sliceHdr->bottom_field_flag)
+            {
+                video->PicOrderCnt = video->TopFieldOrderCnt = video->PicOrderCntMsb + sliceHdr->pic_order_cnt_lsb;
+            }
+
+            if (!sliceHdr->field_pic_flag)
+            {
+                video->BottomFieldOrderCnt = video->TopFieldOrderCnt + sliceHdr->delta_pic_order_cnt_bottom;
+            }
+            else if (sliceHdr->bottom_field_flag)
+            {
+                video->PicOrderCnt = video->BottomFieldOrderCnt = video->PicOrderCntMsb + sliceHdr->pic_order_cnt_lsb;
+            }
+
+            if (!sliceHdr->field_pic_flag)
+            {
+                video->PicOrderCnt = AVC_MIN(video->TopFieldOrderCnt, video->BottomFieldOrderCnt);
+            }
+
+            if (video->currPicParams->pic_order_present_flag && !sliceHdr->field_pic_flag)
+            {
+                sliceHdr->delta_pic_order_cnt_bottom = 0; /* defaulted to zero */
+            }
+
+            break;
+        case 1: /* POC MODE 1, subclause 8.2.1.2 */
+            /* calculate FrameNumOffset */
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                encvid->dispOrdPOCRef = currInput->disp_order;  /* reset the reference point */
+                video->prevFrameNumOffset = 0;
+                video->FrameNumOffset = 0;
+            }
+            else if (video->prevFrameNum > sliceHdr->frame_num)
+            {
+                video->FrameNumOffset = video->prevFrameNumOffset + video->MaxFrameNum;
+            }
+            else
+            {
+                video->FrameNumOffset = video->prevFrameNumOffset;
+            }
+            /* calculate absFrameNum */
+            if (currSPS->num_ref_frames_in_pic_order_cnt_cycle)
+            {
+                video->absFrameNum = video->FrameNumOffset + sliceHdr->frame_num;
+            }
+            else
+            {
+                video->absFrameNum = 0;
+            }
+
+            if (video->absFrameNum > 0 && video->nal_ref_idc == 0)
+            {
+                video->absFrameNum--;
+            }
+
+            /* derive picOrderCntCycleCnt and frameNumInPicOrderCntCycle */
+            if (video->absFrameNum > 0)
+            {
+                video->picOrderCntCycleCnt = (video->absFrameNum - 1) / currSPS->num_ref_frames_in_pic_order_cnt_cycle;
+                video->frameNumInPicOrderCntCycle = (video->absFrameNum - 1) % currSPS->num_ref_frames_in_pic_order_cnt_cycle;
+            }
+            /* derive expectedDeltaPerPicOrderCntCycle, this value can be computed up front. */
+            video->expectedDeltaPerPicOrderCntCycle = 0;
+            for (i = 0; i < (int)currSPS->num_ref_frames_in_pic_order_cnt_cycle; i++)
+            {
+                video->expectedDeltaPerPicOrderCntCycle += currSPS->offset_for_ref_frame[i];
+            }
+            /* derive expectedPicOrderCnt */
+            if (video->absFrameNum)
+            {
+                video->expectedPicOrderCnt = video->picOrderCntCycleCnt * video->expectedDeltaPerPicOrderCntCycle;
+                for (i = 0; i <= video->frameNumInPicOrderCntCycle; i++)
+                {
+                    video->expectedPicOrderCnt += currSPS->offset_for_ref_frame[i];
+                }
+            }
+            else
+            {
+                video->expectedPicOrderCnt = 0;
+            }
+
+            if (video->nal_ref_idc == 0)
+            {
+                video->expectedPicOrderCnt += currSPS->offset_for_non_ref_pic;
+            }
+            /* derive TopFieldOrderCnt and BottomFieldOrderCnt */
+            /* encoding part */
+            if (!currSPS->delta_pic_order_always_zero_flag)
+            {
+                sliceHdr->delta_pic_order_cnt[0] = currInput->disp_order - encvid->dispOrdPOCRef - video->expectedPicOrderCnt;
+
+                if (video->currPicParams->pic_order_present_flag && !sliceHdr->field_pic_flag)
+                {
+                    sliceHdr->delta_pic_order_cnt[1] = sliceHdr->delta_pic_order_cnt[0]; /* should be calculated from currInput->bottom_field->disp_order */
+                }
+                else
+                {
+                    sliceHdr->delta_pic_order_cnt[1] = 0;
+                }
+            }
+            else
+            {
+                sliceHdr->delta_pic_order_cnt[0] = sliceHdr->delta_pic_order_cnt[1] = 0;
+            }
+
+            if (sliceHdr->field_pic_flag == 0)
+            {
+                video->TopFieldOrderCnt = video->expectedPicOrderCnt + sliceHdr->delta_pic_order_cnt[0];
+                video->BottomFieldOrderCnt = video->TopFieldOrderCnt + currSPS->offset_for_top_to_bottom_field + sliceHdr->delta_pic_order_cnt[1];
+
+                video->PicOrderCnt = AVC_MIN(video->TopFieldOrderCnt, video->BottomFieldOrderCnt);
+            }
+            else if (sliceHdr->bottom_field_flag == 0)
+            {
+                video->TopFieldOrderCnt = video->expectedPicOrderCnt + sliceHdr->delta_pic_order_cnt[0];
+                video->PicOrderCnt = video->TopFieldOrderCnt;
+            }
+            else
+            {
+                video->BottomFieldOrderCnt = video->expectedPicOrderCnt + currSPS->offset_for_top_to_bottom_field + sliceHdr->delta_pic_order_cnt[0];
+                video->PicOrderCnt = video->BottomFieldOrderCnt;
+            }
+            break;
+
+
+        case 2: /* POC MODE 2, subclause 8.2.1.3 */
+            /* decoding order must be the same as display order */
+            /* we don't check for that. The decoder will just output in decoding order. */
+            /* Check for 2 consecutive non-reference frame */
+            if (video->nal_ref_idc == 0)
+            {
+                if (encvid->dispOrdPOCRef == 1)
+                {
+                    return AVCENC_CONSECUTIVE_NONREF;
+                }
+                encvid->dispOrdPOCRef = 1;  /* act as a flag for non ref */
+            }
+            else
+            {
+                encvid->dispOrdPOCRef = 0;
+            }
+
+
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                video->FrameNumOffset = 0;
+            }
+            else if (video->prevFrameNum > sliceHdr->frame_num)
+            {
+                video->FrameNumOffset = video->prevFrameNumOffset + video->MaxFrameNum;
+            }
+            else
+            {
+                video->FrameNumOffset = video->prevFrameNumOffset;
+            }
+            /* derive tempPicOrderCnt, we just use PicOrderCnt */
+            if (video->nal_unit_type == AVC_NALTYPE_IDR)
+            {
+                video->PicOrderCnt = 0;
+            }
+            else if (video->nal_ref_idc == 0)
+            {
+                video->PicOrderCnt = 2 * (video->FrameNumOffset + sliceHdr->frame_num) - 1;
+            }
+            else
+            {
+                video->PicOrderCnt = 2 * (video->FrameNumOffset + sliceHdr->frame_num);
+            }
+            /* derive TopFieldOrderCnt and BottomFieldOrderCnt */
+            if (sliceHdr->field_pic_flag == 0)
+            {
+                video->TopFieldOrderCnt = video->BottomFieldOrderCnt = video->PicOrderCnt;
+            }
+            else if (sliceHdr->bottom_field_flag)
+            {
+                video->BottomFieldOrderCnt = video->PicOrderCnt;
+            }
+            else
+            {
+                video->TopFieldOrderCnt = video->PicOrderCnt;
+            }
+            break;
+        default:
+            return AVCENC_POC_FAIL;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+/** see subclause 8.2.1 */
+AVCEnc_Status PostPOC(AVCCommonObj *video)
+{
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+
+    video->prevFrameNum = sliceHdr->frame_num;
+
+    switch (currSPS->pic_order_cnt_type)
+    {
+        case 0: /* subclause 8.2.1.1 */
+            if (video->mem_mgr_ctrl_eq_5)
+            {
+                video->prevPicOrderCntMsb = 0;
+                video->prevPicOrderCntLsb = video->TopFieldOrderCnt;
+            }
+            else
+            {
+                video->prevPicOrderCntMsb = video->PicOrderCntMsb;
+                video->prevPicOrderCntLsb = sliceHdr->pic_order_cnt_lsb;
+            }
+            break;
+        case 1:  /* subclause 8.2.1.2 and 8.2.1.3 */
+        case 2:
+            if (video->mem_mgr_ctrl_eq_5)
+            {
+                video->prevFrameNumOffset = 0;
+            }
+            else
+            {
+                video->prevFrameNumOffset = video->FrameNumOffset;
+            }
+            break;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
diff --git a/media/libstagefright/codecs/avc/enc/src/init.cpp b/media/libstagefright/codecs/avc/enc/src/init.cpp
new file mode 100644
index 0000000..c258b57
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/init.cpp
@@ -0,0 +1,899 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+#include "avcenc_api.h"
+
+#define LOG2_MAX_FRAME_NUM_MINUS4   12   /* 12 default */
+#define SLICE_GROUP_CHANGE_CYCLE    1    /* default */
+
+/* initialized variables to be used in SPS*/
+AVCEnc_Status  SetEncodeParam(AVCHandle* avcHandle, AVCEncParams* encParam,
+                              void* extSPS, void* extPPS)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCSeqParamSet *seqParam = video->currSeqParams;
+    AVCPicParamSet *picParam = video->currPicParams;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCEnc_Status status;
+    void *userData = avcHandle->userData;
+    int ii, maxFrameNum;
+
+    AVCSeqParamSet* extS = NULL;
+    AVCPicParamSet* extP = NULL;
+
+    if (extSPS) extS = (AVCSeqParamSet*) extSPS;
+    if (extPPS) extP = (AVCPicParamSet*) extPPS;
+
+    /* This part sets the default values of the encoding options this
+    library supports in seqParam, picParam and sliceHdr structures and
+    also copy the values from the encParam into the above 3 structures.
+
+    Some parameters will be assigned later when we encode SPS or PPS such as
+    the seq_parameter_id or pic_parameter_id. Also some of the slice parameters
+    have to be re-assigned per slice basis such as frame_num, slice_type,
+    first_mb_in_slice, pic_order_cnt_lsb, slice_qp_delta, slice_group_change_cycle */
+
+    /* profile_idc, constrained_setx_flag and level_idc is set by VerifyProfile(),
+    and VerifyLevel() functions later. */
+
+    encvid->fullsearch_enable = encParam->fullsearch;
+
+    encvid->outOfBandParamSet = ((encParam->out_of_band_param_set == AVC_ON) ? TRUE : FALSE);
+
+    /* parameters derived from the the encParam that are used in SPS */
+    if (extS)
+    {
+        video->MaxPicOrderCntLsb =  1 << (extS->log2_max_pic_order_cnt_lsb_minus4 + 4);
+        video->PicWidthInMbs = extS->pic_width_in_mbs_minus1 + 1;
+        video->PicHeightInMapUnits = extS->pic_height_in_map_units_minus1 + 1 ;
+        video->FrameHeightInMbs = (2 - extS->frame_mbs_only_flag) * video->PicHeightInMapUnits ;
+    }
+    else
+    {
+        video->MaxPicOrderCntLsb =  1 << (encParam->log2_max_poc_lsb_minus_4 + 4);
+        video->PicWidthInMbs = (encParam->width + 15) >> 4; /* round it to multiple of 16 */
+        video->FrameHeightInMbs = (encParam->height + 15) >> 4; /* round it to multiple of 16 */
+        video->PicHeightInMapUnits = video->FrameHeightInMbs;
+    }
+
+    video->PicWidthInSamplesL = video->PicWidthInMbs * 16 ;
+    if (video->PicWidthInSamplesL + 32 > 0xFFFF)
+    {
+        return AVCENC_NOT_SUPPORTED; // we use 2-bytes for pitch
+    }
+
+    video->PicWidthInSamplesC = video->PicWidthInMbs * 8 ;
+    video->PicHeightInMbs = video->FrameHeightInMbs;
+    video->PicSizeInMapUnits = video->PicWidthInMbs * video->PicHeightInMapUnits ;
+    video->PicHeightInSamplesL = video->PicHeightInMbs * 16;
+    video->PicHeightInSamplesC = video->PicHeightInMbs * 8;
+    video->PicSizeInMbs = video->PicWidthInMbs * video->PicHeightInMbs;
+
+    if (!extS && !extP)
+    {
+        maxFrameNum = (encParam->idr_period == -1) ? (1 << 16) : encParam->idr_period;
+        ii = 0;
+        while (maxFrameNum > 0)
+        {
+            ii++;
+            maxFrameNum >>= 1;
+        }
+        if (ii < 4) ii = 4;
+        else if (ii > 16) ii = 16;
+
+        seqParam->log2_max_frame_num_minus4 = ii - 4;//LOG2_MAX_FRAME_NUM_MINUS4; /* default */
+
+        video->MaxFrameNum = 1 << ii; //(LOG2_MAX_FRAME_NUM_MINUS4 + 4); /* default */
+        video->MaxPicNum = video->MaxFrameNum;
+
+        /************* set the SPS *******************/
+        seqParam->seq_parameter_set_id = 0; /* start with zero */
+        /* POC */
+        seqParam->pic_order_cnt_type = encParam->poc_type; /* POC type */
+        if (encParam->poc_type == 0)
+        {
+            if (/*encParam->log2_max_poc_lsb_minus_4<0 || (no need, it's unsigned)*/
+                encParam->log2_max_poc_lsb_minus_4 > 12)
+            {
+                return AVCENC_INVALID_POC_LSB;
+            }
+            seqParam->log2_max_pic_order_cnt_lsb_minus4 = encParam->log2_max_poc_lsb_minus_4;
+        }
+        else if (encParam->poc_type == 1)
+        {
+            seqParam->delta_pic_order_always_zero_flag = encParam->delta_poc_zero_flag;
+            seqParam->offset_for_non_ref_pic = encParam->offset_poc_non_ref;
+            seqParam->offset_for_top_to_bottom_field = encParam->offset_top_bottom;
+            seqParam->num_ref_frames_in_pic_order_cnt_cycle = encParam->num_ref_in_cycle;
+            if (encParam->offset_poc_ref == NULL)
+            {
+                return AVCENC_ENCPARAM_MEM_FAIL;
+            }
+            for (ii = 0; ii < encParam->num_ref_frame; ii++)
+            {
+                seqParam->offset_for_ref_frame[ii] = encParam->offset_poc_ref[ii];
+            }
+        }
+        /* number of reference frame */
+        if (encParam->num_ref_frame > 16 || encParam->num_ref_frame < 0)
+        {
+            return AVCENC_INVALID_NUM_REF;
+        }
+        seqParam->num_ref_frames = encParam->num_ref_frame; /* num reference frame range 0...16*/
+        seqParam->gaps_in_frame_num_value_allowed_flag = FALSE;
+        seqParam->pic_width_in_mbs_minus1 = video->PicWidthInMbs - 1;
+        seqParam->pic_height_in_map_units_minus1 = video->PicHeightInMapUnits - 1;
+        seqParam->frame_mbs_only_flag = TRUE;
+        seqParam->mb_adaptive_frame_field_flag = FALSE;
+        seqParam->direct_8x8_inference_flag = FALSE; /* default */
+        seqParam->frame_cropping_flag = FALSE;
+        seqParam->frame_crop_bottom_offset = 0;
+        seqParam->frame_crop_left_offset = 0;
+        seqParam->frame_crop_right_offset = 0;
+        seqParam->frame_crop_top_offset = 0;
+        seqParam->vui_parameters_present_flag = FALSE; /* default */
+    }
+    else if (extS) // use external SPS and PPS
+    {
+        seqParam->seq_parameter_set_id = extS->seq_parameter_set_id;
+        seqParam->log2_max_frame_num_minus4 = extS->log2_max_frame_num_minus4;
+        video->MaxFrameNum = 1 << (extS->log2_max_frame_num_minus4 + 4);
+        video->MaxPicNum = video->MaxFrameNum;
+        if (encParam->idr_period > (int)(video->MaxFrameNum) || (encParam->idr_period == -1))
+        {
+            encParam->idr_period = (int)video->MaxFrameNum;
+        }
+
+        seqParam->pic_order_cnt_type = extS->pic_order_cnt_type;
+        if (seqParam->pic_order_cnt_type == 0)
+        {
+            if (/*extS->log2_max_pic_order_cnt_lsb_minus4<0 || (no need it's unsigned)*/
+                extS->log2_max_pic_order_cnt_lsb_minus4 > 12)
+            {
+                return AVCENC_INVALID_POC_LSB;
+            }
+            seqParam->log2_max_pic_order_cnt_lsb_minus4 = extS->log2_max_pic_order_cnt_lsb_minus4;
+        }
+        else if (seqParam->pic_order_cnt_type == 1)
+        {
+            seqParam->delta_pic_order_always_zero_flag = extS->delta_pic_order_always_zero_flag;
+            seqParam->offset_for_non_ref_pic = extS->offset_for_non_ref_pic;
+            seqParam->offset_for_top_to_bottom_field = extS->offset_for_top_to_bottom_field;
+            seqParam->num_ref_frames_in_pic_order_cnt_cycle = extS->num_ref_frames_in_pic_order_cnt_cycle;
+            if (extS->offset_for_ref_frame == NULL)
+            {
+                return AVCENC_ENCPARAM_MEM_FAIL;
+            }
+            for (ii = 0; ii < (int) extS->num_ref_frames; ii++)
+            {
+                seqParam->offset_for_ref_frame[ii] = extS->offset_for_ref_frame[ii];
+            }
+        }
+        /* number of reference frame */
+        if (extS->num_ref_frames > 16 /*|| extS->num_ref_frames<0 (no need, it's unsigned)*/)
+        {
+            return AVCENC_INVALID_NUM_REF;
+        }
+        seqParam->num_ref_frames = extS->num_ref_frames; /* num reference frame range 0...16*/
+        seqParam->gaps_in_frame_num_value_allowed_flag = extS->gaps_in_frame_num_value_allowed_flag;
+        seqParam->pic_width_in_mbs_minus1 = extS->pic_width_in_mbs_minus1;
+        seqParam->pic_height_in_map_units_minus1 = extS->pic_height_in_map_units_minus1;
+        seqParam->frame_mbs_only_flag = extS->frame_mbs_only_flag;
+        if (extS->frame_mbs_only_flag != TRUE)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+        seqParam->mb_adaptive_frame_field_flag = extS->mb_adaptive_frame_field_flag;
+        if (extS->mb_adaptive_frame_field_flag != FALSE)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+
+        seqParam->direct_8x8_inference_flag = extS->direct_8x8_inference_flag;
+        seqParam->frame_cropping_flag = extS->frame_cropping_flag ;
+        if (extS->frame_cropping_flag != FALSE)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+
+        seqParam->frame_crop_bottom_offset = 0;
+        seqParam->frame_crop_left_offset = 0;
+        seqParam->frame_crop_right_offset = 0;
+        seqParam->frame_crop_top_offset = 0;
+        seqParam->vui_parameters_present_flag = extS->vui_parameters_present_flag;
+        if (extS->vui_parameters_present_flag)
+        {
+            memcpy(&(seqParam->vui_parameters), &(extS->vui_parameters), sizeof(AVCVUIParams));
+        }
+    }
+    else
+    {
+        return AVCENC_NOT_SUPPORTED;
+    }
+
+    /***************** now PPS ******************************/
+    if (!extP && !extS)
+    {
+        picParam->pic_parameter_set_id = (uint)(-1); /* start with zero */
+        picParam->seq_parameter_set_id = (uint)(-1); /* start with zero */
+        picParam->entropy_coding_mode_flag = 0; /* default to CAVLC */
+        picParam->pic_order_present_flag = 0; /* default for now, will need it for B-slice */
+        /* FMO */
+        if (encParam->num_slice_group < 1 || encParam->num_slice_group > MAX_NUM_SLICE_GROUP)
+        {
+            return AVCENC_INVALID_NUM_SLICEGROUP;
+        }
+        picParam->num_slice_groups_minus1 = encParam->num_slice_group - 1;
+
+        if (picParam->num_slice_groups_minus1 > 0)
+        {
+            picParam->slice_group_map_type = encParam->fmo_type;
+            switch (encParam->fmo_type)
+            {
+                case 0:
+                    for (ii = 0; ii <= (int)picParam->num_slice_groups_minus1; ii++)
+                    {
+                        picParam->run_length_minus1[ii] = encParam->run_length_minus1[ii];
+                    }
+                    break;
+                case 2:
+                    for (ii = 0; ii < (int)picParam->num_slice_groups_minus1; ii++)
+                    {
+                        picParam->top_left[ii] = encParam->top_left[ii];
+                        picParam->bottom_right[ii] = encParam->bottom_right[ii];
+                    }
+                    break;
+                case 3:
+                case 4:
+                case 5:
+                    if (encParam->change_dir_flag == AVC_ON)
+                    {
+                        picParam->slice_group_change_direction_flag = TRUE;
+                    }
+                    else
+                    {
+                        picParam->slice_group_change_direction_flag = FALSE;
+                    }
+                    if (/*encParam->change_rate_minus1 < 0 || (no need it's unsigned) */
+                        encParam->change_rate_minus1 > video->PicSizeInMapUnits - 1)
+                    {
+                        return AVCENC_INVALID_CHANGE_RATE;
+                    }
+                    picParam->slice_group_change_rate_minus1 = encParam->change_rate_minus1;
+                    video->SliceGroupChangeRate = picParam->slice_group_change_rate_minus1 + 1;
+                    break;
+                case 6:
+                    picParam->pic_size_in_map_units_minus1 = video->PicSizeInMapUnits - 1;
+
+                    /* allocate picParam->slice_group_id */
+                    picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits, DEFAULT_ATTR);
+                    if (picParam->slice_group_id == NULL)
+                    {
+                        return AVCENC_MEMORY_FAIL;
+                    }
+
+                    if (encParam->slice_group == NULL)
+                    {
+                        return AVCENC_ENCPARAM_MEM_FAIL;
+                    }
+                    for (ii = 0; ii < (int)video->PicSizeInMapUnits; ii++)
+                    {
+                        picParam->slice_group_id[ii] = encParam->slice_group[ii];
+                    }
+                    break;
+                default:
+                    return AVCENC_INVALID_FMO_TYPE;
+            }
+        }
+        picParam->num_ref_idx_l0_active_minus1 = encParam->num_ref_frame - 1; /* assume frame only */
+        picParam->num_ref_idx_l1_active_minus1 = 0; /* default value */
+        picParam->weighted_pred_flag = 0; /* no weighted prediction supported */
+        picParam->weighted_bipred_idc = 0; /* range 0,1,2 */
+        if (/*picParam->weighted_bipred_idc < 0 || (no need, it's unsigned) */
+            picParam->weighted_bipred_idc > 2)
+        {
+            return AVCENC_WEIGHTED_BIPRED_FAIL;
+        }
+        picParam->pic_init_qp_minus26 = 0; /* default, will be changed at slice level anyway */
+        if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25)
+        {
+            return AVCENC_INIT_QP_FAIL; /* out of range */
+        }
+        picParam->pic_init_qs_minus26 = 0;
+        if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25)
+        {
+            return AVCENC_INIT_QS_FAIL; /* out of range */
+        }
+
+        picParam->chroma_qp_index_offset = 0; /* default to zero for now */
+        if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12)
+        {
+            return AVCENC_CHROMA_QP_FAIL; /* out of range */
+        }
+        /* deblocking */
+        picParam->deblocking_filter_control_present_flag = (encParam->db_filter == AVC_ON) ? TRUE : FALSE ;
+        /* constrained intra prediction */
+        picParam->constrained_intra_pred_flag = (encParam->constrained_intra_pred == AVC_ON) ? TRUE : FALSE;
+        picParam->redundant_pic_cnt_present_flag = 0; /* default */
+    }
+    else if (extP)// external PPS
+    {
+        picParam->pic_parameter_set_id = extP->pic_parameter_set_id - 1; /* to be increased by one */
+        picParam->seq_parameter_set_id = extP->seq_parameter_set_id;
+        picParam->entropy_coding_mode_flag = extP->entropy_coding_mode_flag;
+        if (extP->entropy_coding_mode_flag != 0) /* default to CAVLC */
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+        picParam->pic_order_present_flag = extP->pic_order_present_flag; /* default for now, will need it for B-slice */
+        if (extP->pic_order_present_flag != 0)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+        /* FMO */
+        if (/*(extP->num_slice_groups_minus1<0) || (no need it's unsigned) */
+            (extP->num_slice_groups_minus1 > MAX_NUM_SLICE_GROUP - 1))
+        {
+            return AVCENC_INVALID_NUM_SLICEGROUP;
+        }
+        picParam->num_slice_groups_minus1 = extP->num_slice_groups_minus1;
+
+        if (picParam->num_slice_groups_minus1 > 0)
+        {
+            picParam->slice_group_map_type = extP->slice_group_map_type;
+            switch (extP->slice_group_map_type)
+            {
+                case 0:
+                    for (ii = 0; ii <= (int)extP->num_slice_groups_minus1; ii++)
+                    {
+                        picParam->run_length_minus1[ii] = extP->run_length_minus1[ii];
+                    }
+                    break;
+                case 2:
+                    for (ii = 0; ii < (int)picParam->num_slice_groups_minus1; ii++)
+                    {
+                        picParam->top_left[ii] = extP->top_left[ii];
+                        picParam->bottom_right[ii] = extP->bottom_right[ii];
+                    }
+                    break;
+                case 3:
+                case 4:
+                case 5:
+                    picParam->slice_group_change_direction_flag = extP->slice_group_change_direction_flag;
+                    if (/*extP->slice_group_change_rate_minus1 < 0 || (no need, it's unsigned) */
+                        extP->slice_group_change_rate_minus1 > video->PicSizeInMapUnits - 1)
+                    {
+                        return AVCENC_INVALID_CHANGE_RATE;
+                    }
+                    picParam->slice_group_change_rate_minus1 = extP->slice_group_change_rate_minus1;
+                    video->SliceGroupChangeRate = picParam->slice_group_change_rate_minus1 + 1;
+                    break;
+                case 6:
+                    if (extP->pic_size_in_map_units_minus1 != video->PicSizeInMapUnits - 1)
+                    {
+                        return AVCENC_NOT_SUPPORTED;
+                    }
+
+                    picParam->pic_size_in_map_units_minus1 = extP->pic_size_in_map_units_minus1;
+
+                    /* allocate picParam->slice_group_id */
+                    picParam->slice_group_id = (uint*)avcHandle->CBAVC_Malloc(userData, sizeof(uint) * video->PicSizeInMapUnits, DEFAULT_ATTR);
+                    if (picParam->slice_group_id == NULL)
+                    {
+                        return AVCENC_MEMORY_FAIL;
+                    }
+
+                    if (extP->slice_group_id == NULL)
+                    {
+                        return AVCENC_ENCPARAM_MEM_FAIL;
+                    }
+                    for (ii = 0; ii < (int)video->PicSizeInMapUnits; ii++)
+                    {
+                        picParam->slice_group_id[ii] = extP->slice_group_id[ii];
+                    }
+                    break;
+                default:
+                    return AVCENC_INVALID_FMO_TYPE;
+            }
+        }
+        picParam->num_ref_idx_l0_active_minus1 = extP->num_ref_idx_l0_active_minus1;
+        picParam->num_ref_idx_l1_active_minus1 = extP->num_ref_idx_l1_active_minus1; /* default value */
+        if (picParam->num_ref_idx_l1_active_minus1 != 0)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+
+        if (extP->weighted_pred_flag)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+
+        picParam->weighted_pred_flag = 0; /* no weighted prediction supported */
+        picParam->weighted_bipred_idc = extP->weighted_bipred_idc; /* range 0,1,2 */
+        if (/*picParam->weighted_bipred_idc < 0 || (no need, it's unsigned) */
+            picParam->weighted_bipred_idc > 2)
+        {
+            return AVCENC_WEIGHTED_BIPRED_FAIL;
+        }
+        picParam->pic_init_qp_minus26 = extP->pic_init_qp_minus26; /* default, will be changed at slice level anyway */
+        if (picParam->pic_init_qp_minus26 < -26 || picParam->pic_init_qp_minus26 > 25)
+        {
+            return AVCENC_INIT_QP_FAIL; /* out of range */
+        }
+        picParam->pic_init_qs_minus26 = extP->pic_init_qs_minus26;
+        if (picParam->pic_init_qs_minus26 < -26 || picParam->pic_init_qs_minus26 > 25)
+        {
+            return AVCENC_INIT_QS_FAIL; /* out of range */
+        }
+
+        picParam->chroma_qp_index_offset = extP->chroma_qp_index_offset; /* default to zero for now */
+        if (picParam->chroma_qp_index_offset < -12 || picParam->chroma_qp_index_offset > 12)
+        {
+            return AVCENC_CHROMA_QP_FAIL; /* out of range */
+        }
+        /* deblocking */
+        picParam->deblocking_filter_control_present_flag = extP->deblocking_filter_control_present_flag;
+        /* constrained intra prediction */
+        picParam->constrained_intra_pred_flag = extP->constrained_intra_pred_flag;
+        if (extP->redundant_pic_cnt_present_flag  != 0)
+        {
+            return AVCENC_NOT_SUPPORTED;
+        }
+        picParam->redundant_pic_cnt_present_flag = extP->redundant_pic_cnt_present_flag; /* default */
+    }
+    else
+    {
+        return AVCENC_NOT_SUPPORTED;
+    }
+
+    /****************** now set up some SliceHeader parameters ***********/
+    if (picParam->deblocking_filter_control_present_flag == TRUE)
+    {
+        /* these values only present when db_filter is ON */
+        if (encParam->disable_db_idc > 2)
+        {
+            return AVCENC_INVALID_DEBLOCK_IDC; /* out of range */
+        }
+        sliceHdr->disable_deblocking_filter_idc = encParam->disable_db_idc;
+
+        if (encParam->alpha_offset < -6 || encParam->alpha_offset > 6)
+        {
+            return AVCENC_INVALID_ALPHA_OFFSET;
+        }
+        sliceHdr->slice_alpha_c0_offset_div2 = encParam->alpha_offset;
+
+        if (encParam->beta_offset < -6 || encParam->beta_offset > 6)
+        {
+            return AVCENC_INVALID_BETA_OFFSET;
+        }
+        sliceHdr->slice_beta_offset_div_2 =  encParam->beta_offset;
+    }
+    if (encvid->outOfBandParamSet == TRUE)
+    {
+        sliceHdr->idr_pic_id = 0;
+    }
+    else
+    {
+        sliceHdr->idr_pic_id = (uint)(-1); /* start with zero */
+    }
+    sliceHdr->field_pic_flag = FALSE;
+    sliceHdr->bottom_field_flag = FALSE;  /* won't be used anyway */
+    video->MbaffFrameFlag = (seqParam->mb_adaptive_frame_field_flag && !sliceHdr->field_pic_flag);
+
+    /* the rest will be set in InitSlice() */
+
+    /* now the rate control and performance related parameters */
+    rateCtrl->scdEnable = (encParam->auto_scd == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->idrPeriod = encParam->idr_period + 1;
+    rateCtrl->intraMBRate = encParam->intramb_refresh;
+    rateCtrl->dpEnable = (encParam->data_par == AVC_ON) ? TRUE : FALSE;
+
+    rateCtrl->subPelEnable = (encParam->sub_pel == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->mvRange = encParam->search_range;
+
+    rateCtrl->subMBEnable = (encParam->submb_pred == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->rdOptEnable = (encParam->rdopt_mode == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->bidirPred = (encParam->bidir_pred == AVC_ON) ? TRUE : FALSE;
+
+    rateCtrl->rcEnable = (encParam->rate_control == AVC_ON) ? TRUE : FALSE;
+    rateCtrl->initQP = encParam->initQP;
+    rateCtrl->initQP = AVC_CLIP3(0, 51, rateCtrl->initQP);
+
+    rateCtrl->bitRate = encParam->bitrate;
+    rateCtrl->cpbSize = encParam->CPB_size;
+    rateCtrl->initDelayOffset = (rateCtrl->bitRate * encParam->init_CBP_removal_delay / 1000);
+
+    if (encParam->frame_rate == 0)
+    {
+        return AVCENC_INVALID_FRAMERATE;
+    }
+
+    rateCtrl->frame_rate = (OsclFloat)(encParam->frame_rate * 1.0 / 1000);
+//  rateCtrl->srcInterval = encParam->src_interval;
+    rateCtrl->first_frame = 1; /* set this flag for the first time */
+
+    /* contrained_setx_flag will be set inside the VerifyProfile called below.*/
+    if (!extS && !extP)
+    {
+        seqParam->profile_idc = encParam->profile;
+        seqParam->constrained_set0_flag = FALSE;
+        seqParam->constrained_set1_flag = FALSE;
+        seqParam->constrained_set2_flag = FALSE;
+        seqParam->constrained_set3_flag = FALSE;
+        seqParam->level_idc = encParam->level;
+    }
+    else
+    {
+        seqParam->profile_idc = extS->profile_idc;
+        seqParam->constrained_set0_flag = extS->constrained_set0_flag;
+        seqParam->constrained_set1_flag = extS->constrained_set1_flag;
+        seqParam->constrained_set2_flag = extS->constrained_set2_flag;
+        seqParam->constrained_set3_flag = extS->constrained_set3_flag;
+        seqParam->level_idc = extS->level_idc;
+    }
+
+
+    status = VerifyProfile(encvid, seqParam, picParam);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    status = VerifyLevel(encvid, seqParam, picParam);
+    if (status != AVCENC_SUCCESS)
+    {
+        return status;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+/* verify the profile setting */
+AVCEnc_Status VerifyProfile(AVCEncObject *encvid, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam)
+{
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+
+    if (seqParam->profile_idc == 0) /* find profile for this setting */
+    {
+        /* find the right profile for it */
+        if (seqParam->direct_8x8_inference_flag == TRUE &&
+                picParam->entropy_coding_mode_flag == FALSE &&
+                picParam->num_slice_groups_minus1 <= 7 /*&&
+            picParam->num_slice_groups_minus1>=0 (no need, it's unsigned) */)
+        {
+            seqParam->profile_idc = AVC_EXTENDED;
+            seqParam->constrained_set2_flag = TRUE;
+        }
+
+        if (rateCtrl->dpEnable == FALSE &&
+                picParam->num_slice_groups_minus1 == 0 &&
+                picParam->redundant_pic_cnt_present_flag == FALSE)
+        {
+            seqParam->profile_idc = AVC_MAIN;
+            seqParam->constrained_set1_flag = TRUE;
+        }
+
+        if (rateCtrl->bidirPred == FALSE &&
+                rateCtrl->dpEnable == FALSE &&
+                seqParam->frame_mbs_only_flag == TRUE &&
+                picParam->weighted_pred_flag == FALSE &&
+                picParam->weighted_bipred_idc == 0 &&
+                picParam->entropy_coding_mode_flag == FALSE &&
+                picParam->num_slice_groups_minus1 <= 7 /*&&
+            picParam->num_slice_groups_minus1>=0 (no need, it's unsigned)*/)
+        {
+            seqParam->profile_idc = AVC_BASELINE;
+            seqParam->constrained_set0_flag = TRUE;
+        }
+
+        if (seqParam->profile_idc == 0) /* still zero */
+        {
+            return AVCENC_PROFILE_NOT_SUPPORTED;
+        }
+    }
+
+    /* check the list of supported profile by this library */
+    switch (seqParam->profile_idc)
+    {
+        case AVC_BASELINE:
+            if (rateCtrl->bidirPred == TRUE ||
+                    rateCtrl->dpEnable == TRUE ||
+                    seqParam->frame_mbs_only_flag != TRUE ||
+                    picParam->weighted_pred_flag == TRUE ||
+                    picParam->weighted_bipred_idc != 0 ||
+                    picParam->entropy_coding_mode_flag == TRUE ||
+                    picParam->num_slice_groups_minus1 > 7 /*||
+            picParam->num_slice_groups_minus1<0 (no need, it's unsigned) */)
+            {
+                status = AVCENC_TOOLS_NOT_SUPPORTED;
+            }
+            break;
+
+        case AVC_MAIN:
+        case AVC_EXTENDED:
+            status = AVCENC_PROFILE_NOT_SUPPORTED;
+    }
+
+    return status;
+}
+
+/* verify the level setting */
+AVCEnc_Status VerifyLevel(AVCEncObject *encvid, AVCSeqParamSet *seqParam, AVCPicParamSet *picParam)
+{
+    (void)(picParam);
+
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCCommonObj *video = encvid->common;
+    int mb_per_sec, ii;
+    int lev_idx;
+    int dpb_size;
+
+    mb_per_sec = (int)(video->PicSizeInMbs * rateCtrl->frame_rate + 0.5);
+    dpb_size = (seqParam->num_ref_frames * video->PicSizeInMbs * 3) >> 6;
+
+    if (seqParam->level_idc == 0) /* find level for this setting */
+    {
+        for (ii = 0; ii < MAX_LEVEL_IDX; ii++)
+        {
+            if (mb_per_sec <= MaxMBPS[ii] &&
+                    video->PicSizeInMbs <= (uint)MaxFS[ii] &&
+                    rateCtrl->bitRate <= (int32)MaxBR[ii]*1000 &&
+                    rateCtrl->cpbSize <= (int32)MaxCPB[ii]*1000 &&
+                    rateCtrl->mvRange <= MaxVmvR[ii] &&
+                    dpb_size <= MaxDPBX2[ii]*512)
+            {
+                seqParam->level_idc = mapIdx2Lev[ii];
+                break;
+            }
+        }
+        if (seqParam->level_idc == 0)
+        {
+            return AVCENC_LEVEL_NOT_SUPPORTED;
+        }
+    }
+
+    /* check if this level is supported by this library */
+    lev_idx = mapLev2Idx[seqParam->level_idc];
+    if (seqParam->level_idc == AVC_LEVEL1_B)
+    {
+        seqParam->constrained_set3_flag = 1;
+    }
+
+
+    if (lev_idx == 255) /* not defined */
+    {
+        return AVCENC_LEVEL_NOT_SUPPORTED;
+    }
+
+    /* check if the encoding setting complies with the level */
+    if (mb_per_sec > MaxMBPS[lev_idx] ||
+            video->PicSizeInMbs > (uint)MaxFS[lev_idx] ||
+            rateCtrl->bitRate > (int32)MaxBR[lev_idx]*1000 ||
+            rateCtrl->cpbSize > (int32)MaxCPB[lev_idx]*1000 ||
+            rateCtrl->mvRange > MaxVmvR[lev_idx])
+    {
+        return AVCENC_LEVEL_FAIL;
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+/* initialize variables at the beginning of each frame */
+/* determine the picture type */
+/* encode POC */
+/* maybe we should do more stuff here. MotionEstimation+SCD and generate a new SPS and PPS */
+AVCEnc_Status InitFrame(AVCEncObject *encvid)
+{
+    AVCStatus ret;
+    AVCEnc_Status status;
+    AVCCommonObj *video = encvid->common;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+
+    /* look for the next frame in coding_order and look for available picture
+       in the DPB. Note, video->currFS->PicOrderCnt, currFS->FrameNum and currPic->PicNum
+       are set to wrong number in this function (right for decoder). */
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        // call init DPB in here.
+        ret = AVCConfigureSequence(encvid->avcHandle, video, TRUE);
+        if (ret != AVC_SUCCESS)
+        {
+            return AVCENC_FAIL;
+        }
+    }
+
+    /* flexible macroblock ordering (every frame)*/
+    /* populate video->mapUnitToSliceGroupMap and video->MbToSliceGroupMap */
+    /* It changes once per each PPS. */
+    FMOInit(video);
+
+    ret = DPBInitBuffer(encvid->avcHandle, video); // get new buffer
+
+    if (ret != AVC_SUCCESS)
+    {
+        return (AVCEnc_Status)ret; // AVCENC_PICTURE_READY, FAIL
+    }
+
+    DPBInitPic(video, 0); /* 0 is dummy */
+
+    /************* determine picture type IDR or non-IDR ***********/
+    video->currPicType = AVC_FRAME;
+    video->slice_data_partitioning = FALSE;
+    encvid->currInput->is_reference = 1; /* default to all frames */
+    video->nal_ref_idc = 1;  /* need to set this for InitPOC */
+    video->currPic->isReference = TRUE;
+
+    /************* set frame_num ********************/
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        video->prevFrameNum = video->MaxFrameNum;
+        video->PrevRefFrameNum = 0;
+        sliceHdr->frame_num = 0;
+    }
+    /* otherwise, it's set to previous reference frame access unit's frame_num in decoding order,
+       see the end of PVAVCDecodeSlice()*/
+    /* There's also restriction on the frame_num, see page 59 of JVT-I1010.doc. */
+    /* Basically, frame_num can't be repeated unless it's opposite fields or non reference fields */
+    else
+    {
+        sliceHdr->frame_num = (video->PrevRefFrameNum + 1) % video->MaxFrameNum;
+    }
+    video->CurrPicNum = sliceHdr->frame_num;  /* for field_pic_flag = 0 */
+    //video->CurrPicNum = 2*sliceHdr->frame_num + 1; /* for field_pic_flag = 1 */
+
+    /* assign pic_order_cnt, video->PicOrderCnt */
+    status = InitPOC(encvid);
+    if (status != AVCENC_SUCCESS)  /* incorrigable fail */
+    {
+        return status;
+    }
+
+    /* Initialize refListIdx for this picture */
+    RefListInit(video);
+
+    /************* motion estimation and scene analysis ************/
+    // , to move this to MB-based MV search for comparison
+    // use sub-optimal QP for mv search
+    AVCMotionEstimation(encvid);  /* AVCENC_SUCCESS or AVCENC_NEW_IDR */
+
+    /* after this point, the picture type will be fixed to either IDR or non-IDR */
+    video->currFS->PicOrderCnt = video->PicOrderCnt;
+    video->currFS->FrameNum = video->sliceHdr->frame_num;
+    video->currPic->PicNum = video->CurrPicNum;
+    video->mbNum = 0; /* start from zero MB */
+    encvid->currSliceGroup = 0; /* start from slice group #0 */
+    encvid->numIntraMB = 0; /* reset this counter */
+
+    if (video->nal_unit_type == AVC_NALTYPE_IDR)
+    {
+        RCInitGOP(encvid);
+
+        /* calculate picture QP */
+        RCInitFrameQP(encvid);
+
+        return AVCENC_NEW_IDR;
+    }
+
+    /* calculate picture QP */
+    RCInitFrameQP(encvid); /* get QP after MV search */
+
+    return AVCENC_SUCCESS;
+}
+
+/* initialize variables for this slice */
+AVCEnc_Status InitSlice(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCPicParamSet *currPPS = video->currPicParams;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+    int slice_type = video->slice_type;
+
+    sliceHdr->first_mb_in_slice = video->mbNum;
+    if (video->mbNum) // not first slice of a frame
+    {
+        video->sliceHdr->slice_type = (AVCSliceType)slice_type;
+    }
+
+    /* sliceHdr->slice_type already set in InitFrame */
+
+    sliceHdr->pic_parameter_set_id = video->currPicParams->pic_parameter_set_id;
+
+    /* sliceHdr->frame_num already set in InitFrame */
+
+    if (!currSPS->frame_mbs_only_flag)  /* we shouldn't need this check */
+    {
+        sliceHdr->field_pic_flag = sliceHdr->bottom_field_flag = FALSE;
+        return AVCENC_TOOLS_NOT_SUPPORTED;
+    }
+
+    /* sliceHdr->idr_pic_id already set in PVAVCEncodeNAL
+
+     sliceHdr->pic_order_cnt_lsb already set in InitFrame..InitPOC
+     sliceHdr->delta_pic_order_cnt_bottom  already set in InitPOC
+
+    sliceHdr->delta_pic_order_cnt[0] already set in InitPOC
+    sliceHdr->delta_pic_order_cnt[1] already set in InitPOC
+    */
+
+    sliceHdr->redundant_pic_cnt = 0; /* default if(currPPS->redundant_pic_cnt_present_flag), range 0..127 */
+    sliceHdr->direct_spatial_mv_pred_flag = 0; // default if(slice_type == AVC_B_SLICE)
+
+    sliceHdr->num_ref_idx_active_override_flag = FALSE; /* default, if(slice_type== P,SP or B)*/
+    sliceHdr->num_ref_idx_l0_active_minus1 = 0; /* default, if (num_ref_idx_active_override_flag) */
+    sliceHdr->num_ref_idx_l1_active_minus1 = 0; /* default, if above and B_slice */
+    /* the above 2 values range from 0..15 for frame picture and 0..31 for field picture */
+
+    /* ref_pic_list_reordering(), currently we don't do anything */
+    sliceHdr->ref_pic_list_reordering_flag_l0 = FALSE; /* default */
+    sliceHdr->ref_pic_list_reordering_flag_l1 = FALSE; /* default */
+    /* if the above are TRUE, some other params must be set */
+
+    if ((currPPS->weighted_pred_flag && (slice_type == AVC_P_SLICE || slice_type == AVC_SP_SLICE)) ||
+            (currPPS->weighted_bipred_idc == 1 && slice_type == AVC_B_SLICE))
+    {
+        //      pred_weight_table(); // not supported !!
+        return AVCENC_TOOLS_NOT_SUPPORTED;
+    }
+
+    /* dec_ref_pic_marking(), this will be done later*/
+    sliceHdr->no_output_of_prior_pics_flag = FALSE; /* default */
+    sliceHdr->long_term_reference_flag = FALSE; /* for IDR frame, do not make it long term */
+    sliceHdr->adaptive_ref_pic_marking_mode_flag = FALSE; /* default */
+    /* other params are not set here because they are not used */
+
+    sliceHdr->cabac_init_idc = 0; /* default, if entropy_coding_mode_flag && slice_type==I or SI, range 0..2  */
+    sliceHdr->slice_qp_delta = 0; /* default for now */
+    sliceHdr->sp_for_switch_flag = FALSE; /* default, if slice_type == SP */
+    sliceHdr->slice_qs_delta = 0; /* default, if slice_type == SP or SI */
+
+    /* derived variables from encParam */
+    /* deblocking filter */
+    video->FilterOffsetA = video->FilterOffsetB = 0;
+    if (currPPS->deblocking_filter_control_present_flag == TRUE)
+    {
+        video->FilterOffsetA = sliceHdr->slice_alpha_c0_offset_div2 << 1;
+        video->FilterOffsetB = sliceHdr->slice_beta_offset_div_2 << 1;
+    }
+
+    /* flexible macroblock ordering */
+    /* populate video->mapUnitToSliceGroupMap and video->MbToSliceGroupMap */
+    /* We already call it at the end of PVAVCEncInitialize(). It changes once per each PPS. */
+    if (video->currPicParams->num_slice_groups_minus1 > 0 && video->currPicParams->slice_group_map_type >= 3
+            && video->currPicParams->slice_group_map_type <= 5)
+    {
+        sliceHdr->slice_group_change_cycle = SLICE_GROUP_CHANGE_CYCLE;  /* default, don't understand how to set it!!!*/
+
+        video->MapUnitsInSliceGroup0 =
+            AVC_MIN(sliceHdr->slice_group_change_cycle * video->SliceGroupChangeRate, video->PicSizeInMapUnits);
+
+        FMOInit(video);
+    }
+
+    /* calculate SliceQPy first  */
+    /* calculate QSy first */
+
+    sliceHdr->slice_qp_delta = video->QPy - 26 - currPPS->pic_init_qp_minus26;
+    //sliceHdr->slice_qs_delta = video->QSy - 26 - currPPS->pic_init_qs_minus26;
+
+    return AVCENC_SUCCESS;
+}
+
diff --git a/media/libstagefright/codecs/avc/enc/src/intra_est.cpp b/media/libstagefright/codecs/avc/enc/src/intra_est.cpp
new file mode 100644
index 0000000..17e5985
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/intra_est.cpp
@@ -0,0 +1,2199 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+
+#define TH_I4  0  /* threshold biasing toward I16 mode instead of I4 mode */
+#define TH_Intra  0 /* threshold biasing toward INTER mode instead of intra mode */
+
+#define FIXED_INTRAPRED_MODE  AVC_I16
+#define FIXED_I16_MODE  AVC_I16_DC
+#define FIXED_I4_MODE   AVC_I4_Diagonal_Down_Left
+#define FIXED_INTRA_CHROMA_MODE AVC_IC_DC
+
+#define CLIP_RESULT(x)      if((uint)x > 0xFF){ \
+                 x = 0xFF & (~(x>>31));}
+
+
+bool IntraDecisionABE(AVCEncObject *encvid, int min_cost, uint8 *curL, int picPitch)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCFrameIO *currInput = encvid->currInput;
+    int orgPitch = currInput->pitch;
+    int x_pos = (video->mb_x) << 4;
+    int y_pos = (video->mb_y) << 4;
+    uint8 *orgY = currInput->YCbCr[0] + y_pos * orgPitch + x_pos;
+    int j;
+    uint8 *topL, *leftL, *orgY_2, *orgY_3;
+    int temp, SBE, offset;
+    OsclFloat ABE;
+    bool intra = true;
+
+    if (((x_pos >> 4) != (int)video->PicWidthInMbs - 1) &&
+            ((y_pos >> 4) != (int)video->PicHeightInMbs - 1) &&
+            video->intraAvailA &&
+            video->intraAvailB)
+    {
+        SBE = 0;
+        /* top neighbor */
+        topL = curL - picPitch;
+        /* left neighbor */
+        leftL = curL - 1;
+        orgY_2 = orgY - orgPitch;
+
+        for (j = 0; j < 16; j++)
+        {
+            temp = *topL++ - orgY[j];
+            SBE += ((temp >= 0) ? temp : -temp);
+            temp = *(leftL += picPitch) - *(orgY_2 += orgPitch);
+            SBE += ((temp >= 0) ? temp : -temp);
+        }
+
+        /* calculate chroma */
+        offset = (y_pos >> 2) * picPitch + (x_pos >> 1);
+        topL = video->currPic->Scb + offset;
+        orgY_2 = currInput->YCbCr[1] + offset + (y_pos >> 2) * (orgPitch - picPitch);
+
+        leftL = topL - 1;
+        topL -= (picPitch >> 1);
+        orgY_3 = orgY_2 - (orgPitch >> 1);
+        for (j = 0; j < 8; j++)
+        {
+            temp = *topL++ - orgY_2[j];
+            SBE += ((temp >= 0) ? temp : -temp);
+            temp = *(leftL += (picPitch >> 1)) - *(orgY_3 += (orgPitch >> 1));
+            SBE += ((temp >= 0) ? temp : -temp);
+        }
+
+        topL = video->currPic->Scr + offset;
+        orgY_2 = currInput->YCbCr[2] + offset + (y_pos >> 2) * (orgPitch - picPitch);
+
+        leftL = topL - 1;
+        topL -= (picPitch >> 1);
+        orgY_3 = orgY_2 - (orgPitch >> 1);
+        for (j = 0; j < 8; j++)
+        {
+            temp = *topL++ - orgY_2[j];
+            SBE += ((temp >= 0) ? temp : -temp);
+            temp = *(leftL += (picPitch >> 1)) - *(orgY_3 += (orgPitch >> 1));
+            SBE += ((temp >= 0) ? temp : -temp);
+        }
+
+        /* compare mincost/384 and SBE/64 */
+        ABE = SBE / 64.0;
+        if (ABE*0.8 >= min_cost / 384.0)
+        {
+            intra = false;
+        }
+    }
+
+    return intra;
+}
+
+/* perform searching for MB mode */
+/* assuming that this is done inside the encoding loop,
+no need to call InitNeighborAvailability */
+
+void MBIntraSearch(AVCEncObject *encvid, int mbnum, uint8 *curL, int picPitch)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCFrameIO *currInput = encvid->currInput;
+    AVCMacroblock *currMB = video->currMB;
+    int min_cost;
+    uint8 *orgY;
+    int x_pos = (video->mb_x) << 4;
+    int y_pos = (video->mb_y) << 4;
+    uint32 *saved_inter;
+    int j;
+    int orgPitch = currInput->pitch;
+    bool intra = true;
+
+    currMB->CBP = 0;
+
+    /* first do motion vector and variable block size search */
+    min_cost = encvid->min_cost[mbnum];
+
+    /* now perform intra prediction search */
+    /* need to add the check for encvid->intraSearch[video->mbNum] to skip intra
+       if it's not worth checking. */
+    if (video->slice_type == AVC_P_SLICE)
+    {
+        /* Decide whether intra search is necessary or not */
+        /* This one, we do it in the encoding loop so the neighboring pixel are the
+        actual reconstructed pixels. */
+        intra = IntraDecisionABE(encvid, min_cost, curL, picPitch);
+    }
+
+    if (intra == true || video->slice_type == AVC_I_SLICE)
+    {
+        orgY = currInput->YCbCr[0] + y_pos * orgPitch + x_pos;
+
+        /* i16 mode search */
+        /* generate all the predictions */
+        intrapred_luma_16x16(encvid);
+
+        /* evaluate them one by one */
+        find_cost_16x16(encvid, orgY, &min_cost);
+
+        if (video->slice_type == AVC_P_SLICE)
+        {
+            /* save current inter prediction */
+            saved_inter = encvid->subpel_pred; /* reuse existing buffer */
+            j = 16;
+            curL -= 4;
+            picPitch -= 16;
+            while (j--)
+            {
+                *saved_inter++ = *((uint32*)(curL += 4));
+                *saved_inter++ = *((uint32*)(curL += 4));
+                *saved_inter++ = *((uint32*)(curL += 4));
+                *saved_inter++ = *((uint32*)(curL += 4));
+                curL += picPitch;
+            }
+
+        }
+
+        /* i4 mode search */
+        mb_intra4x4_search(encvid, &min_cost);
+
+        encvid->min_cost[mbnum] = min_cost; /* update min_cost */
+    }
+
+
+    if (currMB->mb_intra)
+    {
+        chroma_intra_search(encvid);
+
+        /* need to set this in order for the MBInterPrediction to work!! */
+        memset(currMB->mvL0, 0, sizeof(int32)*16);
+        currMB->ref_idx_L0[0] = currMB->ref_idx_L0[1] =
+                                    currMB->ref_idx_L0[2] = currMB->ref_idx_L0[3] = -1;
+    }
+    else if (video->slice_type == AVC_P_SLICE && intra == true)
+    {
+        /* restore current inter prediction */
+        saved_inter = encvid->subpel_pred; /* reuse existing buffer */
+        j = 16;
+        curL -= ((picPitch + 16) << 4);
+        while (j--)
+        {
+            *((uint32*)(curL += 4)) = *saved_inter++;
+            *((uint32*)(curL += 4)) = *saved_inter++;
+            *((uint32*)(curL += 4)) = *saved_inter++;
+            *((uint32*)(curL += 4)) = *saved_inter++;
+            curL += picPitch;
+        }
+    }
+
+    return ;
+}
+
+/* generate all the prediction values */
+void intrapred_luma_16x16(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCPictureData *currPic = video->currPic;
+
+    int x_pos = (video->mb_x) << 4;
+    int y_pos = (video->mb_y) << 4;
+    int pitch = currPic->pitch;
+
+    int offset = y_pos * pitch + x_pos;
+
+    uint8 *pred, *top, *left;
+    uint8 *curL = currPic->Sl + offset; /* point to reconstructed frame */
+    uint32 word1, word2, word3, word4;
+    uint32 sum = 0;
+
+    int a_16, b, c, factor_c;
+    uint8 *comp_ref_x0, *comp_ref_x1, *comp_ref_y0, *comp_ref_y1;
+    int H = 0, V = 0, tmp, value;
+    int i;
+
+    if (video->intraAvailB)
+    {
+        //get vertical prediction mode
+        top = curL - pitch;
+
+        pred = encvid->pred_i16[AVC_I16_Vertical] - 16;
+
+        word1 = *((uint32*)(top));  /* read 4 bytes from top */
+        word2 = *((uint32*)(top + 4)); /* read 4 bytes from top */
+        word3 = *((uint32*)(top + 8)); /* read 4 bytes from top */
+        word4 = *((uint32*)(top + 12)); /* read 4 bytes from top */
+
+        for (i = 0; i < 16; i++)
+        {
+            *((uint32*)(pred += 16)) = word1;
+            *((uint32*)(pred + 4)) = word2;
+            *((uint32*)(pred + 8)) = word3;
+            *((uint32*)(pred + 12)) = word4;
+
+        }
+
+        sum = word1 & 0xFF00FF;
+        word1 = (word1 >> 8) & 0xFF00FF;
+        sum += word1;
+        word1 = (word2 & 0xFF00FF);
+        sum += word1;
+        word2 = (word2 >> 8) & 0xFF00FF;
+        sum += word2;
+        word1 = (word3 & 0xFF00FF);
+        sum += word1;
+        word3 = (word3 >> 8) & 0xFF00FF;
+        sum += word3;
+        word1 = (word4 & 0xFF00FF);
+        sum += word1;
+        word4 = (word4 >> 8) & 0xFF00FF;
+        sum += word4;
+
+        sum += (sum >> 16);
+        sum &= 0xFFFF;
+
+        if (!video->intraAvailA)
+        {
+            sum = (sum + 8) >> 4;
+        }
+    }
+
+    if (video->intraAvailA)
+    {
+        // get horizontal mode
+        left = curL - 1 - pitch;
+
+        pred = encvid->pred_i16[AVC_I16_Horizontal] - 16;
+
+        for (i = 0; i < 16; i++)
+        {
+            word1 = *(left += pitch);
+            sum += word1;
+
+            word1 = (word1 << 8) | word1;
+            word1 = (word1 << 16) | word1; /* make it 4 */
+
+            *(uint32*)(pred += 16) = word1;
+            *(uint32*)(pred + 4) = word1;
+            *(uint32*)(pred + 8) = word1;
+            *(uint32*)(pred + 12) = word1;
+        }
+
+        if (!video->intraAvailB)
+        {
+            sum = (sum + 8) >> 4;
+        }
+        else
+        {
+            sum = (sum + 16) >> 5;
+        }
+    }
+
+    // get DC mode
+    if (!video->intraAvailA && !video->intraAvailB)
+    {
+        sum = 0x80808080;
+    }
+    else
+    {
+        sum = (sum << 8) | sum;
+        sum = (sum << 16) | sum;
+    }
+
+    pred = encvid->pred_i16[AVC_I16_DC] - 16;
+    for (i = 0; i < 16; i++)
+    {
+        *((uint32*)(pred += 16)) = sum;
+        *((uint32*)(pred + 4)) = sum;
+        *((uint32*)(pred + 8)) = sum;
+        *((uint32*)(pred + 12)) = sum;
+    }
+
+    // get plane mode
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        pred = encvid->pred_i16[AVC_I16_Plane] - 16;
+
+        comp_ref_x0 = curL - pitch + 8;
+        comp_ref_x1 = curL - pitch + 6;
+        comp_ref_y0 = curL - 1 + (pitch << 3);
+        comp_ref_y1 = curL - 1 + 6 * pitch;
+
+        for (i = 1; i < 8; i++)
+        {
+            H += i * (*comp_ref_x0++ - *comp_ref_x1--);
+            V += i * (*comp_ref_y0 - *comp_ref_y1);
+            comp_ref_y0 += pitch;
+            comp_ref_y1 -= pitch;
+        }
+
+        H += i * (*comp_ref_x0++ - curL[-pitch-1]);
+        V += i * (*comp_ref_y0 - *comp_ref_y1);
+
+
+        a_16 = ((*(curL - pitch + 15) + *(curL - 1 + 15 * pitch)) << 4) + 16;;
+        b = (5 * H + 32) >> 6;
+        c = (5 * V + 32) >> 6;
+
+        tmp = 0;
+        for (i = 0; i < 16; i++)
+        {
+            factor_c = a_16 + c * (tmp++ - 7);
+            factor_c -= 7 * b;
+
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = value;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 8);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 16);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 24);
+            *((uint32*)(pred += 16)) = word1;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = value;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 8);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 16);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 24);
+            *((uint32*)(pred + 4)) = word1;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = value;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 8);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 16);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 24);
+            *((uint32*)(pred + 8)) = word1;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = value;
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 8);
+            value = factor_c >> 5;
+            factor_c += b;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 16);
+            value = factor_c >> 5;
+            CLIP_RESULT(value)
+            word1 = (word1) | (value << 24);
+            *((uint32*)(pred + 12)) = word1;
+        }
+    }
+
+    return ;
+}
+
+
+/* evaluate each prediction mode of I16 */
+void find_cost_16x16(AVCEncObject *encvid, uint8 *orgY, int *min_cost)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+    int cost;
+    int org_pitch = encvid->currInput->pitch;
+
+    /* evaluate vertical mode */
+    if (video->intraAvailB)
+    {
+        cost = cost_i16(orgY, org_pitch, encvid->pred_i16[AVC_I16_Vertical], *min_cost);
+        if (cost < *min_cost)
+        {
+            *min_cost = cost;
+            currMB->mbMode = AVC_I16;
+            currMB->mb_intra = 1;
+            currMB->i16Mode = AVC_I16_Vertical;
+        }
+    }
+
+
+    /* evaluate horizontal mode */
+    if (video->intraAvailA)
+    {
+        cost = cost_i16(orgY, org_pitch, encvid->pred_i16[AVC_I16_Horizontal], *min_cost);
+        if (cost < *min_cost)
+        {
+            *min_cost = cost;
+            currMB->mbMode = AVC_I16;
+            currMB->mb_intra = 1;
+            currMB->i16Mode = AVC_I16_Horizontal;
+        }
+    }
+
+    /* evaluate DC mode */
+    cost = cost_i16(orgY, org_pitch, encvid->pred_i16[AVC_I16_DC], *min_cost);
+    if (cost < *min_cost)
+    {
+        *min_cost = cost;
+        currMB->mbMode = AVC_I16;
+        currMB->mb_intra = 1;
+        currMB->i16Mode = AVC_I16_DC;
+    }
+
+    /* evaluate plane mode */
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        cost = cost_i16(orgY, org_pitch, encvid->pred_i16[AVC_I16_Plane], *min_cost);
+        if (cost < *min_cost)
+        {
+            *min_cost = cost;
+            currMB->mbMode = AVC_I16;
+            currMB->mb_intra = 1;
+            currMB->i16Mode = AVC_I16_Plane;
+        }
+    }
+
+    return ;
+}
+
+
+int cost_i16(uint8 *org, int org_pitch, uint8 *pred, int min_cost)
+{
+
+    int cost;
+    int j, k;
+    int16 res[256], *pres; // residue
+    int m0, m1, m2, m3;
+
+    // calculate SATD
+    org_pitch -= 16;
+    pres = res;
+    // horizontal transform
+    for (j = 0; j < 16; j++)
+    {
+        k = 4;
+        while (k > 0)
+        {
+            m0 = org[0] - pred[0];
+            m3 = org[3] - pred[3];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = org[1] - pred[1];
+            m2 = org[2] - pred[2];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 + m1;
+            pres[2] = m0 - m1;
+            pres[1] = m2 + m3;
+            pres[3] = m3 - m2;
+
+            org += 4;
+            pres += 4;
+            pred += 4;
+            k--;
+        }
+        org += org_pitch;
+    }
+    /* vertical transform */
+    cost = 0;
+    for (j = 0; j < 4; j++)
+    {
+        pres = res + (j << 6);
+        k = 16;
+        while (k > 0)
+        {
+            m0 = pres[0];
+            m3 = pres[3<<4];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = pres[1<<4];
+            m2 = pres[2<<4];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 = m0 + m1;
+
+            if (k&0x3)  // only sum up non DC values.
+            {
+                cost += ((m0 > 0) ? m0 : -m0);
+            }
+
+            m1 = m0 - (m1 << 1);
+            cost += ((m1 > 0) ? m1 : -m1);
+            m3 = m2 + m3;
+            cost += ((m3 > 0) ? m3 : -m3);
+            m2 = m3 - (m2 << 1);
+            cost += ((m2 > 0) ? m2 : -m2);
+
+            pres++;
+            k--;
+        }
+        if ((cost >> 1) > min_cost) /* early drop out */
+        {
+            return (cost >> 1);
+        }
+    }
+
+    /* Hadamard of the DC coefficient */
+    pres = res;
+    k = 4;
+    while (k > 0)
+    {
+        m0 = pres[0];
+        m3 = pres[3<<2];
+        m0 >>= 2;
+        m0 += (m3 >> 2);
+        m3 = m0 - (m3 >> 1);
+        m1 = pres[1<<2];
+        m2 = pres[2<<2];
+        m1 >>= 2;
+        m1 += (m2 >> 2);
+        m2 = m1 - (m2 >> 1);
+        pres[0] = (m0 + m1);
+        pres[2<<2] = (m0 - m1);
+        pres[1<<2] = (m2 + m3);
+        pres[3<<2] = (m3 - m2);
+        pres += (4 << 4);
+        k--;
+    }
+
+    pres = res;
+    k = 4;
+    while (k > 0)
+    {
+        m0 = pres[0];
+        m3 = pres[3<<6];
+        m0 += m3;
+        m3 = m0 - (m3 << 1);
+        m1 = pres[1<<6];
+        m2 = pres[2<<6];
+        m1 += m2;
+        m2 = m1 - (m2 << 1);
+        m0 = m0 + m1;
+        cost += ((m0 >= 0) ? m0 : -m0);
+        m1 = m0 - (m1 << 1);
+        cost += ((m1 >= 0) ? m1 : -m1);
+        m3 = m2 + m3;
+        cost += ((m3 >= 0) ? m3 : -m3);
+        m2 = m3 - (m2 << 1);
+        cost += ((m2 >= 0) ? m2 : -m2);
+        pres += 4;
+
+        if ((cost >> 1) > min_cost) /* early drop out */
+        {
+            return (cost >> 1);
+        }
+
+        k--;
+    }
+
+    return (cost >> 1);
+}
+
+
+void mb_intra4x4_search(AVCEncObject *encvid, int *min_cost)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+    AVCPictureData *currPic = video->currPic;
+    AVCFrameIO *currInput = encvid->currInput;
+    int pitch = currPic->pitch;
+    int org_pitch = currInput->pitch;
+    int offset;
+    uint8 *curL, *comp, *org4, *org8;
+    int y = video->mb_y << 4;
+    int x = video->mb_x << 4;
+
+    int b8, b4, cost4x4, blkidx;
+    int cost = 0;
+    int numcoef;
+    int dummy = 0;
+    int mb_intra = currMB->mb_intra; // save the original value
+
+    offset = y * pitch + x;
+
+    curL = currPic->Sl + offset;
+    org8 = currInput->YCbCr[0] + y * org_pitch + x;
+    video->pred_pitch = 4;
+
+    cost = (int)(6.0 * encvid->lambda_mode + 0.4999);
+    cost <<= 2;
+
+    currMB->mb_intra = 1;  // temporary set this to one to enable the IDCT
+    // operation inside dct_luma
+
+    for (b8 = 0; b8 < 4; b8++)
+    {
+        comp = curL;
+        org4 = org8;
+
+        for (b4 = 0; b4 < 4; b4++)
+        {
+            blkidx = blkIdx2blkXY[b8][b4];
+            cost4x4 = blk_intra4x4_search(encvid, blkidx, comp, org4);
+            cost += cost4x4;
+            if (cost > *min_cost)
+            {
+                currMB->mb_intra = mb_intra; // restore the value
+                return ;
+            }
+
+            /* do residue, Xfrm, Q, invQ, invXfrm, recon and save the DCT coefs.*/
+            video->pred_block = encvid->pred_i4[currMB->i4Mode[blkidx]];
+            numcoef = dct_luma(encvid, blkidx, comp, org4, &dummy);
+            currMB->nz_coeff[blkidx] = numcoef;
+            if (numcoef)
+            {
+                video->cbp4x4 |= (1 << blkidx);
+                currMB->CBP |= (1 << b8);
+            }
+
+            if (b4&1)
+            {
+                comp += ((pitch << 2) - 4);
+                org4 += ((org_pitch << 2) - 4);
+            }
+            else
+            {
+                comp += 4;
+                org4 += 4;
+            }
+        }
+
+        if (b8&1)
+        {
+            curL += ((pitch << 3) - 8);
+            org8 += ((org_pitch << 3) - 8);
+        }
+        else
+        {
+            curL += 8;
+            org8 += 8;
+        }
+    }
+
+    currMB->mb_intra = mb_intra; // restore the value
+
+    if (cost < *min_cost)
+    {
+        *min_cost = cost;
+        currMB->mbMode = AVC_I4;
+        currMB->mb_intra = 1;
+    }
+
+    return ;
+}
+
+
+/* search for i4 mode for a 4x4 block */
+int blk_intra4x4_search(AVCEncObject *encvid, int blkidx, uint8 *cur, uint8 *org)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCNeighborAvailability availability;
+    AVCMacroblock *currMB = video->currMB;
+    bool top_left = FALSE;
+    int pitch = video->currPic->pitch;
+    uint8 mode_avail[AVCNumI4PredMode];
+    uint32 temp, DC;
+    uint8 *pred;
+    int org_pitch = encvid->currInput->pitch;
+    uint16 min_cost, cost;
+
+    int P_x, Q_x, R_x, P_y, Q_y, R_y, D, D0, D1;
+    int P0, Q0, R0, S0, P1, Q1, R1, P2, Q2;
+    uint8 P_A, P_B, P_C, P_D, P_E, P_F, P_G, P_H, P_I, P_J, P_K, P_L, P_X;
+    int r0, r1, r2, r3, r4, r5, r6, r7;
+    int x0, x1, x2, x3, x4, x5;
+    uint32 temp1, temp2;
+
+    int ipmode, mostProbableMode;
+    int fixedcost = 4 * encvid->lambda_mode;
+    int min_sad = 0x7FFF;
+
+    availability.left = TRUE;
+    availability.top = TRUE;
+    if (blkidx <= 3) /* top row block  (!block_y) */
+    { /* check availability up */
+        availability.top = video->intraAvailB ;
+    }
+    if (!(blkidx&0x3)) /* left column block (!block_x)*/
+    { /* check availability left */
+        availability.left = video->intraAvailA ;
+    }
+    availability.top_right = BlkTopRight[blkidx];
+
+    if (availability.top_right == 2)
+    {
+        availability.top_right = video->intraAvailB;
+    }
+    else if (availability.top_right == 3)
+    {
+        availability.top_right = video->intraAvailC;
+    }
+
+    if (availability.top == TRUE)
+    {
+        temp = *(uint32*)(cur - pitch);
+        P_A = temp & 0xFF;
+        P_B = (temp >> 8) & 0xFF;
+        P_C = (temp >> 16) & 0xFF;
+        P_D = (temp >> 24) & 0xFF;
+    }
+    else
+    {
+        P_A = P_B = P_C = P_D = 128;
+    }
+
+    if (availability.top_right == TRUE)
+    {
+        temp = *(uint32*)(cur - pitch + 4);
+        P_E = temp & 0xFF;
+        P_F = (temp >> 8) & 0xFF;
+        P_G = (temp >> 16) & 0xFF;
+        P_H = (temp >> 24) & 0xFF;
+    }
+    else
+    {
+        P_E = P_F = P_G = P_H = 128;
+    }
+
+    if (availability.left == TRUE)
+    {
+        cur--;
+        P_I = *cur;
+        P_J = *(cur += pitch);
+        P_K = *(cur += pitch);
+        P_L = *(cur + pitch);
+        cur -= (pitch << 1);
+        cur++;
+    }
+    else
+    {
+        P_I = P_J = P_K = P_L = 128;
+    }
+
+    /* check if top-left pixel is available */
+    if (((blkidx > 3) && (blkidx&0x3)) || ((blkidx > 3) && video->intraAvailA)
+            || ((blkidx&0x3) && video->intraAvailB)
+            || (video->intraAvailA && video->intraAvailD && video->intraAvailB))
+    {
+        top_left = TRUE;
+        P_X = *(cur - pitch - 1);
+    }
+    else
+    {
+        P_X = 128;
+    }
+
+    //===== INTRA PREDICTION FOR 4x4 BLOCK =====
+    /* vertical */
+    mode_avail[AVC_I4_Vertical] = 0;
+    if (availability.top)
+    {
+        mode_avail[AVC_I4_Vertical] = 1;
+        pred = encvid->pred_i4[AVC_I4_Vertical];
+
+        temp = (P_D << 24) | (P_C << 16) | (P_B << 8) | P_A ;
+        *((uint32*)pred) =  temp; /* write 4 at a time */
+        *((uint32*)(pred += 4)) =  temp;
+        *((uint32*)(pred += 4)) =  temp;
+        *((uint32*)(pred += 4)) =  temp;
+    }
+    /* horizontal */
+    mode_avail[AVC_I4_Horizontal] = 0;
+    mode_avail[AVC_I4_Horizontal_Up] = 0;
+    if (availability.left)
+    {
+        mode_avail[AVC_I4_Horizontal] = 1;
+        pred = encvid->pred_i4[AVC_I4_Horizontal];
+
+        temp = P_I | (P_I << 8);
+        temp = temp | (temp << 16);
+        *((uint32*)pred) = temp;
+        temp = P_J | (P_J << 8);
+        temp = temp | (temp << 16);
+        *((uint32*)(pred += 4)) = temp;
+        temp = P_K | (P_K << 8);
+        temp = temp | (temp << 16);
+        *((uint32*)(pred += 4)) = temp;
+        temp = P_L | (P_L << 8);
+        temp = temp | (temp << 16);
+        *((uint32*)(pred += 4)) = temp;
+
+        mode_avail[AVC_I4_Horizontal_Up] = 1;
+        pred = encvid->pred_i4[AVC_I4_Horizontal_Up];
+
+        Q0 = (P_J + P_K + 1) >> 1;
+        Q1 = (P_J + (P_K << 1) + P_L + 2) >> 2;
+        P0 = ((P_I + P_J + 1) >> 1);
+        P1 = ((P_I + (P_J << 1) + P_K + 2) >> 2);
+
+        temp = P0 | (P1 << 8);      // [P0 P1 Q0 Q1]
+        temp |= (Q0 << 16);     // [Q0 Q1 R0 DO]
+        temp |= (Q1 << 24);     // [R0 D0 D1 D1]
+        *((uint32*)pred) = temp;      // [D1 D1 D1 D1]
+
+        D0 = (P_K + 3 * P_L + 2) >> 2;
+        R0 = (P_K + P_L + 1) >> 1;
+
+        temp = Q0 | (Q1 << 8);
+        temp |= (R0 << 16);
+        temp |= (D0 << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        D1 = P_L;
+
+        temp = R0 | (D0 << 8);
+        temp |= (D1 << 16);
+        temp |= (D1 << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp = D1 | (D1 << 8);
+        temp |= (temp << 16);
+        *((uint32*)(pred += 4)) = temp;
+    }
+    /* DC */
+    mode_avail[AVC_I4_DC] = 1;
+    pred = encvid->pred_i4[AVC_I4_DC];
+    if (availability.left)
+    {
+        DC = P_I + P_J + P_K + P_L;
+
+        if (availability.top)
+        {
+            DC = (P_A + P_B + P_C + P_D + DC + 4) >> 3;
+        }
+        else
+        {
+            DC = (DC + 2) >> 2;
+
+        }
+    }
+    else if (availability.top)
+    {
+        DC = (P_A + P_B + P_C + P_D + 2) >> 2;
+
+    }
+    else
+    {
+        DC = 128;
+    }
+
+    temp = DC | (DC << 8);
+    temp = temp | (temp << 16);
+    *((uint32*)pred) = temp;
+    *((uint32*)(pred += 4)) = temp;
+    *((uint32*)(pred += 4)) = temp;
+    *((uint32*)(pred += 4)) = temp;
+
+    /* Down-left */
+    mode_avail[AVC_I4_Diagonal_Down_Left] = 0;
+
+    if (availability.top)
+    {
+        mode_avail[AVC_I4_Diagonal_Down_Left] = 1;
+
+        pred = encvid->pred_i4[AVC_I4_Diagonal_Down_Left];
+
+        r0 = P_A;
+        r1 = P_B;
+        r2 = P_C;
+        r3 = P_D;
+
+        r0 += (r1 << 1);
+        r0 += r2;
+        r0 += 2;
+        r0 >>= 2;
+        r1 += (r2 << 1);
+        r1 += r3;
+        r1 += 2;
+        r1 >>= 2;
+
+        if (availability.top_right)
+        {
+            r4 = P_E;
+            r5 = P_F;
+            r6 = P_G;
+            r7 = P_H;
+
+            r2 += (r3 << 1);
+            r2 += r4;
+            r2 += 2;
+            r2 >>= 2;
+            r3 += (r4 << 1);
+            r3 += r5;
+            r3 += 2;
+            r3 >>= 2;
+            r4 += (r5 << 1);
+            r4 += r6;
+            r4 += 2;
+            r4 >>= 2;
+            r5 += (r6 << 1);
+            r5 += r7;
+            r5 += 2;
+            r5 >>= 2;
+            r6 += (3 * r7);
+            r6 += 2;
+            r6 >>= 2;
+            temp = r0 | (r1 << 8);
+            temp |= (r2 << 16);
+            temp |= (r3 << 24);
+            *((uint32*)pred) = temp;
+
+            temp = (temp >> 8) | (r4 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+            temp = (temp >> 8) | (r5 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+            temp = (temp >> 8) | (r6 << 24);
+            *((uint32*)(pred += 4)) = temp;
+        }
+        else
+        {
+            r2 += (r3 * 3);
+            r2 += 2;
+            r2 >>= 2;
+            r3 = ((r3 << 2) + 2);
+            r3 >>= 2;
+
+            temp = r0 | (r1 << 8);
+            temp |= (r2 << 16);
+            temp |= (r3 << 24);
+            *((uint32*)pred) = temp;
+
+            temp = (temp >> 8) | (r3 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+            temp = (temp >> 8) | (r3 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+            temp = (temp >> 8) | (r3 << 24);
+            *((uint32*)(pred += 4)) = temp;
+
+        }
+    }
+
+    /* Down Right */
+    mode_avail[AVC_I4_Diagonal_Down_Right] = 0;
+    /* Diagonal Vertical Right */
+    mode_avail[AVC_I4_Vertical_Right] = 0;
+    /* Horizontal Down */
+    mode_avail[AVC_I4_Horizontal_Down] = 0;
+
+    if (top_left == TRUE)
+    {
+        /* Down Right */
+        mode_avail[AVC_I4_Diagonal_Down_Right] = 1;
+        pred = encvid->pred_i4[AVC_I4_Diagonal_Down_Right];
+
+        Q_x = (P_A + 2 * P_B + P_C + 2) >> 2;
+        R_x = (P_B + 2 * P_C + P_D + 2) >> 2;
+        P_x = (P_X + 2 * P_A + P_B + 2) >> 2;
+        D   = (P_A + 2 * P_X + P_I + 2) >> 2;
+        P_y = (P_X + 2 * P_I + P_J + 2) >> 2;
+        Q_y = (P_I + 2 * P_J + P_K + 2) >> 2;
+        R_y = (P_J + 2 * P_K + P_L + 2) >> 2;
+
+        /* we can pack these */
+        temp =  D | (P_x << 8);   //[D   P_x Q_x R_x]
+        //[P_y D   P_x Q_x]
+        temp |= (Q_x << 16); //[Q_y P_y D   P_x]
+        temp |= (R_x << 24);  //[R_y Q_y P_y D  ]
+        *((uint32*)pred) = temp;
+
+        temp =  P_y | (D << 8);
+        temp |= (P_x << 16);
+        temp |= (Q_x << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp =  Q_y | (P_y << 8);
+        temp |= (D << 16);
+        temp |= (P_x << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp = R_y | (Q_y << 8);
+        temp |= (P_y << 16);
+        temp |= (D << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+
+        /* Diagonal Vertical Right */
+        mode_avail[AVC_I4_Vertical_Right] = 1;
+        pred = encvid->pred_i4[AVC_I4_Vertical_Right];
+
+        Q0 = P_A + P_B + 1;
+        R0 = P_B + P_C + 1;
+        S0 = P_C + P_D + 1;
+        P0 = P_X + P_A + 1;
+        D = (P_I + 2 * P_X + P_A + 2) >> 2;
+
+        P1 = (P0 + Q0) >> 2;
+        Q1 = (Q0 + R0) >> 2;
+        R1 = (R0 + S0) >> 2;
+
+        P0 >>= 1;
+        Q0 >>= 1;
+        R0 >>= 1;
+        S0 >>= 1;
+
+        P2 = (P_X + 2 * P_I + P_J + 2) >> 2;
+        Q2 = (P_I + 2 * P_J + P_K + 2) >> 2;
+
+        temp =  P0 | (Q0 << 8);  //[P0 Q0 R0 S0]
+        //[D  P1 Q1 R1]
+        temp |= (R0 << 16); //[P2 P0 Q0 R0]
+        temp |= (S0 << 24); //[Q2 D  P1 Q1]
+        *((uint32*)pred) =  temp;
+
+        temp =  D | (P1 << 8);
+        temp |= (Q1 << 16);
+        temp |= (R1 << 24);
+        *((uint32*)(pred += 4)) =  temp;
+
+        temp = P2 | (P0 << 8);
+        temp |= (Q0 << 16);
+        temp |= (R0 << 24);
+        *((uint32*)(pred += 4)) =  temp;
+
+        temp = Q2 | (D << 8);
+        temp |= (P1 << 16);
+        temp |= (Q1 << 24);
+        *((uint32*)(pred += 4)) =  temp;
+
+
+        /* Horizontal Down */
+        mode_avail[AVC_I4_Horizontal_Down] = 1;
+        pred = encvid->pred_i4[AVC_I4_Horizontal_Down];
+
+
+        Q2 = (P_A + 2 * P_B + P_C + 2) >> 2;
+        P2 = (P_X + 2 * P_A + P_B + 2) >> 2;
+        D = (P_I + 2 * P_X + P_A + 2) >> 2;
+        P0 = P_X + P_I + 1;
+        Q0 = P_I + P_J + 1;
+        R0 = P_J + P_K + 1;
+        S0 = P_K + P_L + 1;
+
+        P1 = (P0 + Q0) >> 2;
+        Q1 = (Q0 + R0) >> 2;
+        R1 = (R0 + S0) >> 2;
+
+        P0 >>= 1;
+        Q0 >>= 1;
+        R0 >>= 1;
+        S0 >>= 1;
+
+
+        /* we can pack these */
+        temp = P0 | (D << 8);   //[P0 D  P2 Q2]
+        //[Q0 P1 P0 D ]
+        temp |= (P2 << 16);  //[R0 Q1 Q0 P1]
+        temp |= (Q2 << 24); //[S0 R1 R0 Q1]
+        *((uint32*)pred) = temp;
+
+        temp = Q0 | (P1 << 8);
+        temp |= (P0 << 16);
+        temp |= (D << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp = R0 | (Q1 << 8);
+        temp |= (Q0 << 16);
+        temp |= (P1 << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+        temp = S0 | (R1 << 8);
+        temp |= (R0 << 16);
+        temp |= (Q1 << 24);
+        *((uint32*)(pred += 4)) = temp;
+
+    }
+
+    /* vertical left */
+    mode_avail[AVC_I4_Vertical_Left] = 0;
+    if (availability.top)
+    {
+        mode_avail[AVC_I4_Vertical_Left] = 1;
+        pred = encvid->pred_i4[AVC_I4_Vertical_Left];
+
+        x0 = P_A + P_B + 1;
+        x1 = P_B + P_C + 1;
+        x2 = P_C + P_D + 1;
+        if (availability.top_right)
+        {
+            x3 = P_D + P_E + 1;
+            x4 = P_E + P_F + 1;
+            x5 = P_F + P_G + 1;
+        }
+        else
+        {
+            x3 = x4 = x5 = (P_D << 1) + 1;
+        }
+
+        temp1 = (x0 >> 1);
+        temp1 |= ((x1 >> 1) << 8);
+        temp1 |= ((x2 >> 1) << 16);
+        temp1 |= ((x3 >> 1) << 24);
+
+        *((uint32*)pred) = temp1;
+
+        temp2 = ((x0 + x1) >> 2);
+        temp2 |= (((x1 + x2) >> 2) << 8);
+        temp2 |= (((x2 + x3) >> 2) << 16);
+        temp2 |= (((x3 + x4) >> 2) << 24);
+
+        *((uint32*)(pred += 4)) = temp2;
+
+        temp1 = (temp1 >> 8) | ((x4 >> 1) << 24);   /* rotate out old value */
+        *((uint32*)(pred += 4)) = temp1;
+
+        temp2 = (temp2 >> 8) | (((x4 + x5) >> 2) << 24); /* rotate out old value */
+        *((uint32*)(pred += 4)) = temp2;
+    }
+
+    //===== LOOP OVER ALL 4x4 INTRA PREDICTION MODES =====
+    // can re-order the search here instead of going in order
+
+    // find most probable mode
+    encvid->mostProbableI4Mode[blkidx] = mostProbableMode = FindMostProbableI4Mode(video, blkidx);
+
+    min_cost = 0xFFFF;
+
+    for (ipmode = 0; ipmode < AVCNumI4PredMode; ipmode++)
+    {
+        if (mode_avail[ipmode] == TRUE)
+        {
+            cost  = (ipmode == mostProbableMode) ? 0 : fixedcost;
+            pred = encvid->pred_i4[ipmode];
+
+            cost_i4(org, org_pitch, pred, &cost);
+
+            if (cost < min_cost)
+            {
+                currMB->i4Mode[blkidx] = (AVCIntra4x4PredMode)ipmode;
+                min_cost   = cost;
+                min_sad = cost - ((ipmode == mostProbableMode) ? 0 : fixedcost);
+            }
+        }
+    }
+
+    if (blkidx == 0)
+    {
+        encvid->i4_sad = min_sad;
+    }
+    else
+    {
+        encvid->i4_sad += min_sad;
+    }
+
+    return min_cost;
+}
+
+int FindMostProbableI4Mode(AVCCommonObj *video, int blkidx)
+{
+    int dcOnlyPredictionFlag;
+    AVCMacroblock *currMB = video->currMB;
+    int intra4x4PredModeA, intra4x4PredModeB, predIntra4x4PredMode;
+
+
+    dcOnlyPredictionFlag = 0;
+    if (blkidx&0x3)
+    {
+        intra4x4PredModeA = currMB->i4Mode[blkidx-1]; // block to the left
+    }
+    else /* for blk 0, 4, 8, 12 */
+    {
+        if (video->intraAvailA)
+        {
+            if (video->mblock[video->mbAddrA].mbMode == AVC_I4)
+            {
+                intra4x4PredModeA = video->mblock[video->mbAddrA].i4Mode[blkidx + 3];
+            }
+            else
+            {
+                intra4x4PredModeA = AVC_I4_DC;
+            }
+        }
+        else
+        {
+            dcOnlyPredictionFlag = 1;
+            goto PRED_RESULT_READY;  // skip below
+        }
+    }
+
+    if (blkidx >> 2)
+    {
+        intra4x4PredModeB = currMB->i4Mode[blkidx-4]; // block above
+    }
+    else /* block 0, 1, 2, 3 */
+    {
+        if (video->intraAvailB)
+        {
+            if (video->mblock[video->mbAddrB].mbMode == AVC_I4)
+            {
+                intra4x4PredModeB = video->mblock[video->mbAddrB].i4Mode[blkidx+12];
+            }
+            else
+            {
+                intra4x4PredModeB = AVC_I4_DC;
+            }
+        }
+        else
+        {
+            dcOnlyPredictionFlag = 1;
+        }
+    }
+
+PRED_RESULT_READY:
+    if (dcOnlyPredictionFlag)
+    {
+        intra4x4PredModeA = intra4x4PredModeB = AVC_I4_DC;
+    }
+
+    predIntra4x4PredMode = AVC_MIN(intra4x4PredModeA, intra4x4PredModeB);
+
+    return predIntra4x4PredMode;
+}
+
+void cost_i4(uint8 *org, int org_pitch, uint8 *pred, uint16 *cost)
+{
+    int k;
+    int16 res[16], *pres;
+    int m0, m1, m2, m3, tmp1;
+    int satd = 0;
+
+    pres = res;
+    // horizontal transform
+    k = 4;
+    while (k > 0)
+    {
+        m0 = org[0] - pred[0];
+        m3 = org[3] - pred[3];
+        m0 += m3;
+        m3 = m0 - (m3 << 1);
+        m1 = org[1] - pred[1];
+        m2 = org[2] - pred[2];
+        m1 += m2;
+        m2 = m1 - (m2 << 1);
+        pres[0] = m0 + m1;
+        pres[2] = m0 - m1;
+        pres[1] = m2 + m3;
+        pres[3] = m3 - m2;
+
+        org += org_pitch;
+        pres += 4;
+        pred += 4;
+        k--;
+    }
+    /* vertical transform */
+    pres = res;
+    k = 4;
+    while (k > 0)
+    {
+        m0 = pres[0];
+        m3 = pres[12];
+        m0 += m3;
+        m3 = m0 - (m3 << 1);
+        m1 = pres[4];
+        m2 = pres[8];
+        m1 += m2;
+        m2 = m1 - (m2 << 1);
+        pres[0] = m0 + m1;
+        pres[8] = m0 - m1;
+        pres[4] = m2 + m3;
+        pres[12] = m3 - m2;
+
+        pres++;
+        k--;
+
+    }
+
+    pres = res;
+    k = 4;
+    while (k > 0)
+    {
+        tmp1 = *pres++;
+        satd += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        satd += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        satd += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        satd += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        k--;
+    }
+
+    satd = (satd + 1) >> 1;
+    *cost += satd;
+
+    return ;
+}
+
+void chroma_intra_search(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCPictureData *currPic = video->currPic;
+
+    int x_pos = video->mb_x << 3;
+    int y_pos = video->mb_y << 3;
+    int pitch = currPic->pitch >> 1;
+    int offset = y_pos * pitch + x_pos;
+
+    uint8 *comp_ref_x, *comp_ref_y, *pred;
+    int  sum_x0, sum_x1, sum_y0, sum_y1;
+    int pred_0[2], pred_1[2], pred_2[2], pred_3[2];
+    uint32 pred_a, pred_b, pred_c, pred_d;
+    int i, j, component;
+    int a_16, b, c, factor_c, topleft;
+    int H, V, value;
+    uint8 *comp_ref_x0, *comp_ref_x1,  *comp_ref_y0, *comp_ref_y1;
+
+    uint8 *curCb = currPic->Scb + offset;
+    uint8 *curCr = currPic->Scr + offset;
+
+    uint8 *orgCb, *orgCr;
+    AVCFrameIO *currInput = encvid->currInput;
+    AVCMacroblock *currMB = video->currMB;
+    int org_pitch;
+    int cost, mincost;
+
+    /* evaluate DC mode */
+    if (video->intraAvailB & video->intraAvailA)
+    {
+        comp_ref_x = curCb - pitch;
+        comp_ref_y = curCb - 1;
+
+        for (i = 0; i < 2; i++)
+        {
+            pred_a = *((uint32*)comp_ref_x);
+            comp_ref_x += 4;
+            pred_b = (pred_a >> 8) & 0xFF00FF;
+            pred_a &= 0xFF00FF;
+            pred_a += pred_b;
+            pred_a += (pred_a >> 16);
+            sum_x0 = pred_a & 0xFFFF;
+
+            pred_a = *((uint32*)comp_ref_x);
+            pred_b = (pred_a >> 8) & 0xFF00FF;
+            pred_a &= 0xFF00FF;
+            pred_a += pred_b;
+            pred_a += (pred_a >> 16);
+            sum_x1 = pred_a & 0xFFFF;
+
+            pred_1[i] = (sum_x1 + 2) >> 2;
+
+            sum_y0 = *comp_ref_y;
+            sum_y0 += *(comp_ref_y += pitch);
+            sum_y0 += *(comp_ref_y += pitch);
+            sum_y0 += *(comp_ref_y += pitch);
+
+            sum_y1 = *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+
+            pred_2[i] = (sum_y1 + 2) >> 2;
+
+            pred_0[i] = (sum_y0 + sum_x0 + 4) >> 3;
+            pred_3[i] = (sum_y1 + sum_x1 + 4) >> 3;
+
+            comp_ref_x = curCr - pitch;
+            comp_ref_y = curCr - 1;
+        }
+    }
+
+    else if (video->intraAvailA)
+    {
+        comp_ref_y = curCb - 1;
+        for (i = 0; i < 2; i++)
+        {
+            sum_y0 = *comp_ref_y;
+            sum_y0 += *(comp_ref_y += pitch);
+            sum_y0 += *(comp_ref_y += pitch);
+            sum_y0 += *(comp_ref_y += pitch);
+
+            sum_y1 = *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+            sum_y1 += *(comp_ref_y += pitch);
+
+            pred_0[i] = pred_1[i] = (sum_y0 + 2) >> 2;
+            pred_2[i] = pred_3[i] = (sum_y1 + 2) >> 2;
+
+            comp_ref_y = curCr - 1;
+        }
+    }
+    else if (video->intraAvailB)
+    {
+        comp_ref_x = curCb - pitch;
+        for (i = 0; i < 2; i++)
+        {
+            pred_a = *((uint32*)comp_ref_x);
+            comp_ref_x += 4;
+            pred_b = (pred_a >> 8) & 0xFF00FF;
+            pred_a &= 0xFF00FF;
+            pred_a += pred_b;
+            pred_a += (pred_a >> 16);
+            sum_x0 = pred_a & 0xFFFF;
+
+            pred_a = *((uint32*)comp_ref_x);
+            pred_b = (pred_a >> 8) & 0xFF00FF;
+            pred_a &= 0xFF00FF;
+            pred_a += pred_b;
+            pred_a += (pred_a >> 16);
+            sum_x1 = pred_a & 0xFFFF;
+
+            pred_0[i] = pred_2[i] = (sum_x0 + 2) >> 2;
+            pred_1[i] = pred_3[i] = (sum_x1 + 2) >> 2;
+
+            comp_ref_x = curCr - pitch;
+        }
+    }
+    else
+    {
+        pred_0[0] = pred_0[1] = pred_1[0] = pred_1[1] =
+                                                pred_2[0] = pred_2[1] = pred_3[0] = pred_3[1] = 128;
+    }
+
+    pred = encvid->pred_ic[AVC_IC_DC];
+
+    pred_a = pred_0[0];
+    pred_b = pred_1[0];
+    pred_a |= (pred_a << 8);
+    pred_a |= (pred_a << 16);
+    pred_b |= (pred_b << 8);
+    pred_b |= (pred_b << 16);
+
+    pred_c = pred_0[1];
+    pred_d = pred_1[1];
+    pred_c |= (pred_c << 8);
+    pred_c |= (pred_c << 16);
+    pred_d |= (pred_d << 8);
+    pred_d |= (pred_d << 16);
+
+
+    for (j = 0; j < 4; j++) /* 4 lines */
+    {
+        *((uint32*)pred) = pred_a;
+        *((uint32*)(pred + 4)) = pred_b;
+        *((uint32*)(pred + 8)) = pred_c;
+        *((uint32*)(pred + 12)) = pred_d;
+        pred += 16; /* move to the next line */
+    }
+
+    pred_a = pred_2[0];
+    pred_b = pred_3[0];
+    pred_a |= (pred_a << 8);
+    pred_a |= (pred_a << 16);
+    pred_b |= (pred_b << 8);
+    pred_b |= (pred_b << 16);
+
+    pred_c = pred_2[1];
+    pred_d = pred_3[1];
+    pred_c |= (pred_c << 8);
+    pred_c |= (pred_c << 16);
+    pred_d |= (pred_d << 8);
+    pred_d |= (pred_d << 16);
+
+    for (j = 0; j < 4; j++) /* 4 lines */
+    {
+        *((uint32*)pred) = pred_a;
+        *((uint32*)(pred + 4)) = pred_b;
+        *((uint32*)(pred + 8)) = pred_c;
+        *((uint32*)(pred + 12)) = pred_d;
+        pred += 16; /* move to the next line */
+    }
+
+    /* predict horizontal mode */
+    if (video->intraAvailA)
+    {
+        comp_ref_y = curCb - 1;
+        comp_ref_x = curCr - 1;
+        pred = encvid->pred_ic[AVC_IC_Horizontal];
+
+        for (i = 4; i < 6; i++)
+        {
+            for (j = 0; j < 4; j++)
+            {
+                pred_a = *comp_ref_y;
+                comp_ref_y += pitch;
+                pred_a |= (pred_a << 8);
+                pred_a |= (pred_a << 16);
+                *((uint32*)pred) = pred_a;
+                *((uint32*)(pred + 4)) = pred_a;
+
+                pred_a = *comp_ref_x;
+                comp_ref_x += pitch;
+                pred_a |= (pred_a << 8);
+                pred_a |= (pred_a << 16);
+                *((uint32*)(pred + 8)) = pred_a;
+                *((uint32*)(pred + 12)) = pred_a;
+
+                pred += 16;
+            }
+        }
+    }
+
+    /* vertical mode */
+    if (video->intraAvailB)
+    {
+        comp_ref_x = curCb - pitch;
+        comp_ref_y = curCr - pitch;
+        pred = encvid->pred_ic[AVC_IC_Vertical];
+
+        pred_a = *((uint32*)comp_ref_x);
+        pred_b = *((uint32*)(comp_ref_x + 4));
+        pred_c = *((uint32*)comp_ref_y);
+        pred_d = *((uint32*)(comp_ref_y + 4));
+
+        for (j = 0; j < 8; j++)
+        {
+            *((uint32*)pred) = pred_a;
+            *((uint32*)(pred + 4)) = pred_b;
+            *((uint32*)(pred + 8)) = pred_c;
+            *((uint32*)(pred + 12)) = pred_d;
+            pred += 16;
+        }
+    }
+
+    /* Intra_Chroma_Plane */
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        comp_ref_x = curCb - pitch;
+        comp_ref_y = curCb - 1;
+        topleft = curCb[-pitch-1];
+
+        pred = encvid->pred_ic[AVC_IC_Plane];
+        for (component = 0; component < 2; component++)
+        {
+            H = V = 0;
+            comp_ref_x0 = comp_ref_x + 4;
+            comp_ref_x1 = comp_ref_x + 2;
+            comp_ref_y0 = comp_ref_y + (pitch << 2);
+            comp_ref_y1 = comp_ref_y + (pitch << 1);
+            for (i = 1; i < 4; i++)
+            {
+                H += i * (*comp_ref_x0++ - *comp_ref_x1--);
+                V += i * (*comp_ref_y0 - *comp_ref_y1);
+                comp_ref_y0 += pitch;
+                comp_ref_y1 -= pitch;
+            }
+            H += i * (*comp_ref_x0++ - topleft);
+            V += i * (*comp_ref_y0 - *comp_ref_y1);
+
+            a_16 = ((*(comp_ref_x + 7) + *(comp_ref_y + 7 * pitch)) << 4) + 16;
+            b = (17 * H + 16) >> 5;
+            c = (17 * V + 16) >> 5;
+
+            pred_a = 0;
+            for (i = 4; i < 6; i++)
+            {
+                for (j = 0; j < 4; j++)
+                {
+                    factor_c = a_16 + c * (pred_a++ - 3);
+
+                    factor_c -= 3 * b;
+
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b = value;
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 8);
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 16);
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 24);
+                    *((uint32*)pred) = pred_b;
+
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b = value;
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 8);
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 16);
+                    value = factor_c >> 5;
+                    factor_c += b;
+                    CLIP_RESULT(value)
+                    pred_b |= (value << 24);
+                    *((uint32*)(pred + 4)) = pred_b;
+                    pred += 16;
+                }
+            }
+
+            pred -= 120; /* point to cr */
+            comp_ref_x = curCr - pitch;
+            comp_ref_y = curCr - 1;
+            topleft = curCr[-pitch-1];
+        }
+    }
+
+    /* now evaluate it */
+
+    org_pitch = (currInput->pitch) >> 1;
+    offset = x_pos + y_pos * org_pitch;
+
+    orgCb = currInput->YCbCr[1] + offset;
+    orgCr = currInput->YCbCr[2] + offset;
+
+    mincost = 0x7fffffff;
+    cost = SATDChroma(orgCb, orgCr, org_pitch, encvid->pred_ic[AVC_IC_DC], mincost);
+    if (cost < mincost)
+    {
+        mincost = cost;
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+    }
+
+    if (video->intraAvailA)
+    {
+        cost = SATDChroma(orgCb, orgCr, org_pitch, encvid->pred_ic[AVC_IC_Horizontal], mincost);
+        if (cost < mincost)
+        {
+            mincost = cost;
+            currMB->intra_chroma_pred_mode = AVC_IC_Horizontal;
+        }
+    }
+
+    if (video->intraAvailB)
+    {
+        cost = SATDChroma(orgCb, orgCr, org_pitch, encvid->pred_ic[AVC_IC_Vertical], mincost);
+        if (cost < mincost)
+        {
+            mincost = cost;
+            currMB->intra_chroma_pred_mode = AVC_IC_Vertical;
+        }
+    }
+
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        cost = SATDChroma(orgCb, orgCr, org_pitch, encvid->pred_ic[AVC_IC_Plane], mincost);
+        if (cost < mincost)
+        {
+            mincost = cost;
+            currMB->intra_chroma_pred_mode = AVC_IC_Plane;
+        }
+    }
+
+
+    return ;
+}
+
+
+int SATDChroma(uint8 *orgCb, uint8 *orgCr, int org_pitch, uint8 *pred, int min_cost)
+{
+    int cost;
+    /* first take difference between orgCb, orgCr and pred */
+    int16 res[128], *pres; // residue
+    int m0, m1, m2, m3, tmp1;
+    int j, k;
+
+    pres = res;
+    org_pitch -= 8;
+    // horizontal transform
+    for (j = 0; j < 8; j++)
+    {
+        k = 2;
+        while (k > 0)
+        {
+            m0 = orgCb[0] - pred[0];
+            m3 = orgCb[3] - pred[3];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = orgCb[1] - pred[1];
+            m2 = orgCb[2] - pred[2];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 + m1;
+            pres[2] = m0 - m1;
+            pres[1] = m2 + m3;
+            pres[3] = m3 - m2;
+
+            orgCb += 4;
+            pres += 4;
+            pred += 4;
+            k--;
+        }
+        orgCb += org_pitch;
+        k = 2;
+        while (k > 0)
+        {
+            m0 = orgCr[0] - pred[0];
+            m3 = orgCr[3] - pred[3];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = orgCr[1] - pred[1];
+            m2 = orgCr[2] - pred[2];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 + m1;
+            pres[2] = m0 - m1;
+            pres[1] = m2 + m3;
+            pres[3] = m3 - m2;
+
+            orgCr += 4;
+            pres += 4;
+            pred += 4;
+            k--;
+        }
+        orgCr += org_pitch;
+    }
+
+    /* vertical transform */
+    for (j = 0; j < 2; j++)
+    {
+        pres = res + (j << 6);
+        k = 16;
+        while (k > 0)
+        {
+            m0 = pres[0];
+            m3 = pres[3<<4];
+            m0 += m3;
+            m3 = m0 - (m3 << 1);
+            m1 = pres[1<<4];
+            m2 = pres[2<<4];
+            m1 += m2;
+            m2 = m1 - (m2 << 1);
+            pres[0] = m0 + m1;
+            pres[2<<4] = m0 - m1;
+            pres[1<<4] = m2 + m3;
+            pres[3<<4] = m3 - m2;
+
+            pres++;
+            k--;
+        }
+    }
+
+    /* now sum of absolute value */
+    pres = res;
+    cost = 0;
+    k = 128;
+    while (k > 0)
+    {
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        tmp1 = *pres++;
+        cost += ((tmp1 >= 0) ? tmp1 : -tmp1);
+        k -= 8;
+        if (cost > min_cost) /* early drop out */
+        {
+            return cost;
+        }
+    }
+
+    return cost;
+}
+
+
+
+///////////////////////////////// old code, unused
+/* find the best intra mode based on original (unencoded) frame */
+/* output is
+    currMB->mb_intra, currMB->mbMode,
+    currMB->i16Mode  (if currMB->mbMode == AVC_I16)
+    currMB->i4Mode[..] (if currMB->mbMode == AVC_I4) */
+
+#ifdef FIXED_INTRAPRED_MODE
+void MBIntraSearch(AVCEncObject *encvid, AVCMacroblock *currMB, int mbNum)
+{
+    (void)(mbNum);
+
+    AVCCommonObj *video = encvid->common;
+    int indx, block_x, block_y;
+
+    video->intraAvailA = video->intraAvailB = video->intraAvailC = video->intraAvailD = 0;
+
+    if (!video->currPicParams->constrained_intra_pred_flag)
+    {
+        video->intraAvailA = video->mbAvailA;
+        video->intraAvailB = video->mbAvailB;
+        video->intraAvailC = video->mbAvailC;
+        video->intraAvailD = video->mbAvailD;
+    }
+    else
+    {
+        if (video->mbAvailA)
+        {
+            video->intraAvailA = video->mblock[video->mbAddrA].mb_intra;
+        }
+        if (video->mbAvailB)
+        {
+            video->intraAvailB = video->mblock[video->mbAddrB].mb_intra ;
+        }
+        if (video->mbAvailC)
+        {
+            video->intraAvailC = video->mblock[video->mbAddrC].mb_intra;
+        }
+        if (video->mbAvailD)
+        {
+            video->intraAvailD = video->mblock[video->mbAddrD].mb_intra;
+        }
+    }
+
+    currMB->mb_intra = TRUE;
+    currMB->mbMode = FIXED_INTRAPRED_MODE;
+
+    if (currMB->mbMode == AVC_I16)
+    {
+        currMB->i16Mode = FIXED_I16_MODE;
+
+        if (FIXED_I16_MODE == AVC_I16_Vertical && !video->intraAvailB)
+        {
+            currMB->i16Mode = AVC_I16_DC;
+        }
+
+        if (FIXED_I16_MODE == AVC_I16_Horizontal && !video->intraAvailA)
+        {
+            currMB->i16Mode = AVC_I16_DC;
+        }
+
+        if (FIXED_I16_MODE == AVC_I16_Plane && !(video->intraAvailA && video->intraAvailB && video->intraAvailD))
+        {
+            currMB->i16Mode = AVC_I16_DC;
+        }
+    }
+    else //if(currMB->mbMode == AVC_I4)
+    {
+        for (indx = 0; indx < 16; indx++)
+        {
+            block_x = blkIdx2blkX[indx];
+            block_y = blkIdx2blkY[indx];
+
+            currMB->i4Mode[(block_y<<2)+block_x] = FIXED_I4_MODE;
+
+            if (FIXED_I4_MODE == AVC_I4_Vertical && !(block_y > 0 || video->intraAvailB))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Horizontal && !(block_x || video->intraAvailA))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Diagonal_Down_Left &&
+                    (block_y == 0 && !video->intraAvailB))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Diagonal_Down_Right &&
+                    !((block_y && block_x)
+                      || (block_y && video->intraAvailA)
+                      || (block_x && video->intraAvailB)
+                      || (video->intraAvailA && video->intraAvailD && video->intraAvailB)))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Vertical_Right &&
+                    !((block_y && block_x)
+                      || (block_y && video->intraAvailA)
+                      || (block_x && video->intraAvailB)
+                      || (video->intraAvailA && video->intraAvailD && video->intraAvailB)))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Horizontal_Down &&
+                    !((block_y && block_x)
+                      || (block_y && video->intraAvailA)
+                      || (block_x && video->intraAvailB)
+                      || (video->intraAvailA && video->intraAvailD && video->intraAvailB)))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Vertical_Left &&
+                    (block_y == 0 && !video->intraAvailB))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+
+            if (FIXED_I4_MODE == AVC_I4_Horizontal_Up && !(block_x || video->intraAvailA))
+            {
+                currMB->i4Mode[(block_y<<2)+block_x] = AVC_I4_DC;
+            }
+        }
+    }
+
+    currMB->intra_chroma_pred_mode = FIXED_INTRA_CHROMA_MODE;
+
+    if (FIXED_INTRA_CHROMA_MODE == AVC_IC_Horizontal && !(video->intraAvailA))
+    {
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+    }
+
+    if (FIXED_INTRA_CHROMA_MODE == AVC_IC_Vertical && !(video->intraAvailB))
+    {
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+    }
+
+    if (FIXED_INTRA_CHROMA_MODE == AVC_IC_Plane && !(video->intraAvailA && video->intraAvailB && video->intraAvailD))
+    {
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+    }
+
+    /* also reset the motion vectors */
+    /* set MV and Ref_Idx codes of Intra blocks in P-slices */
+    memset(currMB->mvL0, 0, sizeof(int32)*16);
+    currMB->ref_idx_L0[0] = -1;
+    currMB->ref_idx_L0[1] = -1;
+    currMB->ref_idx_L0[2] = -1;
+    currMB->ref_idx_L0[3] = -1;
+
+    // output from this function, currMB->mbMode should be set to either
+    // AVC_I4, AVC_I16, or else in AVCMBMode enum, mbType, mb_intra, intra_chroma_pred_mode */
+    return ;
+}
+#else // faster combined prediction+SAD calculation
+void MBIntraSearch(AVCEncObject *encvid, AVCMacroblock *currMB, int mbNum)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCFrameIO *currInput = encvid->currInput;
+    uint8 *curL, *curCb, *curCr;
+    uint8 *comp, *pred_block;
+    int block_x, block_y, offset;
+    uint sad, sad4, sadI4, sadI16;
+    int component, SubBlock_indx, temp;
+    int pitch = video->currPic->pitch;
+
+    /* calculate the cost of each intra prediction mode  and compare to the
+    inter mode */
+    /* full search for all intra prediction */
+    offset = (video->mb_y << 4) * pitch + (video->mb_x << 4);
+    curL = currInput->YCbCr[0] + offset;
+    pred_block = video->pred_block + 84;
+
+    /* Assuming that InitNeighborAvailability has been called prior to this function */
+    video->intraAvailA = video->intraAvailB = video->intraAvailC = video->intraAvailD = 0;
+
+    if (!video->currPicParams->constrained_intra_pred_flag)
+    {
+        video->intraAvailA = video->mbAvailA;
+        video->intraAvailB = video->mbAvailB;
+        video->intraAvailC = video->mbAvailC;
+        video->intraAvailD = video->mbAvailD;
+    }
+    else
+    {
+        if (video->mbAvailA)
+        {
+            video->intraAvailA = video->mblock[video->mbAddrA].mb_intra;
+        }
+        if (video->mbAvailB)
+        {
+            video->intraAvailB = video->mblock[video->mbAddrB].mb_intra ;
+        }
+        if (video->mbAvailC)
+        {
+            video->intraAvailC = video->mblock[video->mbAddrC].mb_intra;
+        }
+        if (video->mbAvailD)
+        {
+            video->intraAvailD = video->mblock[video->mbAddrD].mb_intra;
+        }
+    }
+
+    /* currently we're doing exhaustive search. Smart search will be used later */
+
+    /* I16 modes */
+    curL = currInput->YCbCr[0] + offset;
+    video->pintra_pred_top = curL - pitch;
+    video->pintra_pred_left = curL - 1;
+    if (video->mb_y)
+    {
+        video->intra_pred_topleft = *(curL - pitch - 1);
+    }
+
+    /* Intra_16x16_Vertical */
+    sadI16 = 65536;
+    /* check availability of top */
+    if (video->intraAvailB)
+    {
+        sad = SAD_I16_Vert(video, curL, sadI16);
+
+        if (sad < sadI16)
+        {
+            sadI16 = sad;
+            currMB->i16Mode = AVC_I16_Vertical;
+        }
+    }
+    /* Intra_16x16_Horizontal */
+    /* check availability of left */
+    if (video->intraAvailA)
+    {
+        sad = SAD_I16_HorzDC(video, curL, AVC_I16_Horizontal, sadI16);
+
+        if (sad < sadI16)
+        {
+            sadI16 = sad;
+            currMB->i16Mode = AVC_I16_Horizontal;
+        }
+    }
+
+    /* Intra_16x16_DC, default mode */
+    sad = SAD_I16_HorzDC(video, curL, AVC_I16_DC, sadI16);
+    if (sad < sadI16)
+    {
+        sadI16 = sad;
+        currMB->i16Mode = AVC_I16_DC;
+    }
+
+    /* Intra_16x16_Plane */
+    if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+    {
+        sad = SAD_I16_Plane(video, curL, sadI16);
+
+        if (sad < sadI16)
+        {
+            sadI16 = sad;
+            currMB->i16Mode = AVC_I16_Plane;
+        }
+    }
+
+    sadI16 >>= 1;  /* before comparison */
+
+    /* selection between intra4, intra16 or inter mode */
+    if (sadI16 < encvid->min_cost)
+    {
+        currMB->mb_intra = TRUE;
+        currMB->mbMode = AVC_I16;
+        encvid->min_cost = sadI16;
+    }
+
+    if (currMB->mb_intra) /* only do the chrominance search when intra is decided */
+    {
+        /* Note that we might be able to guess the type of prediction from
+        the luma prediction type */
+
+        /* now search for the best chroma intra prediction */
+        offset = (offset >> 2) + (video->mb_x << 2);
+        curCb = currInput->YCbCr[1] + offset;
+        curCr = currInput->YCbCr[2] + offset;
+
+        pitch >>= 1;
+        video->pintra_pred_top_cb = curCb - pitch;
+        video->pintra_pred_left_cb = curCb - 1;
+        video->pintra_pred_top_cr = curCr - pitch;
+        video->pintra_pred_left_cr = curCr - 1;
+
+        if (video->mb_y)
+        {
+            video->intra_pred_topleft_cb = *(curCb - pitch - 1);
+            video->intra_pred_topleft_cr = *(curCr - pitch - 1);
+        }
+
+        /* Intra_Chroma_DC */
+        sad4 = SAD_Chroma_DC(video, curCb, curCr, 65536);
+        currMB->intra_chroma_pred_mode = AVC_IC_DC;
+
+        /* Intra_Chroma_Horizontal */
+        if (video->intraAvailA)
+        {
+            /* check availability of left */
+            sad = SAD_Chroma_Horz(video, curCb, curCr, sad4);
+            if (sad < sad4)
+            {
+                sad4 = sad;
+                currMB->intra_chroma_pred_mode = AVC_IC_Horizontal;
+            }
+        }
+
+        /* Intra_Chroma_Vertical */
+        if (video->intraAvailB)
+        {
+            /* check availability of top */
+            sad = SAD_Chroma_Vert(video, curCb, curCr, sad4);
+
+            if (sad < sad4)
+            {
+                sad4 = sad;
+                currMB->intra_chroma_pred_mode = AVC_IC_Vertical;
+            }
+        }
+
+        /* Intra_Chroma_Plane */
+        if (video->intraAvailA && video->intraAvailB && video->intraAvailD)
+        {
+            /* check availability of top and left */
+            Intra_Chroma_Plane(video, pitch);
+
+            sad = SADChroma(pred_block + 452, curCb, curCr, pitch);
+
+            if (sad < sad4)
+            {
+                sad4 = sad;
+                currMB->intra_chroma_pred_mode = AVC_IC_Plane;
+            }
+        }
+
+        /* also reset the motion vectors */
+        /* set MV and Ref_Idx codes of Intra blocks in P-slices */
+        memset(currMB->mvL0, 0, sizeof(int32)*16);
+        memset(currMB->ref_idx_L0, -1, sizeof(int16)*4);
+
+    }
+
+    // output from this function, currMB->mbMode should be set to either
+    // AVC_I4, AVC_I16, or else in AVCMBMode enum, mbType, mb_intra, intra_chroma_pred_mode */
+
+    return ;
+}
+#endif
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/motion_comp.cpp b/media/libstagefright/codecs/avc/enc/src/motion_comp.cpp
new file mode 100644
index 0000000..ac62d78
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/motion_comp.cpp
@@ -0,0 +1,2156 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+#include "avcenc_int.h"
+
+
+#define CLIP_RESULT(x)      if((uint)x > 0xFF){ \
+                 x = 0xFF & (~(x>>31));}
+
+/* (blkwidth << 2) + (dy << 1) + dx */
+static void (*const eChromaMC_SIMD[8])(uint8 *, int , int , int , uint8 *, int, int , int) =
+{
+    &eChromaFullMC_SIMD,
+    &eChromaHorizontalMC_SIMD,
+    &eChromaVerticalMC_SIMD,
+    &eChromaDiagonalMC_SIMD,
+    &eChromaFullMC_SIMD,
+    &eChromaHorizontalMC2_SIMD,
+    &eChromaVerticalMC2_SIMD,
+    &eChromaDiagonalMC2_SIMD
+};
+/* Perform motion prediction and compensation with residue if exist. */
+void AVCMBMotionComp(AVCEncObject *encvid, AVCCommonObj *video)
+{
+    (void)(encvid);
+
+    AVCMacroblock *currMB = video->currMB;
+    AVCPictureData *currPic = video->currPic;
+    int mbPartIdx, subMbPartIdx;
+    int ref_idx;
+    int offset_MbPart_indx = 0;
+    int16 *mv;
+    uint32 x_pos, y_pos;
+    uint8 *curL, *curCb, *curCr;
+    uint8 *ref_l, *ref_Cb, *ref_Cr;
+    uint8 *predBlock, *predCb, *predCr;
+    int block_x, block_y, offset_x, offset_y, offsetP, offset;
+    int x_position = (video->mb_x << 4);
+    int y_position = (video->mb_y << 4);
+    int MbHeight, MbWidth, mbPartIdx_X, mbPartIdx_Y, offset_indx;
+    int picWidth = currPic->width;
+    int picPitch = currPic->pitch;
+    int picHeight = currPic->height;
+    uint32 tmp_word;
+
+    tmp_word = y_position * picPitch;
+    curL = currPic->Sl + tmp_word + x_position;
+    offset = (tmp_word >> 2) + (x_position >> 1);
+    curCb = currPic->Scb + offset;
+    curCr = currPic->Scr + offset;
+
+    predBlock = curL;
+    predCb = curCb;
+    predCr = curCr;
+
+    GetMotionVectorPredictor(video, 1);
+
+    for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+    {
+        MbHeight = currMB->SubMbPartHeight[mbPartIdx];
+        MbWidth = currMB->SubMbPartWidth[mbPartIdx];
+        mbPartIdx_X = ((mbPartIdx + offset_MbPart_indx) & 1);
+        mbPartIdx_Y = (mbPartIdx + offset_MbPart_indx) >> 1;
+        ref_idx = currMB->ref_idx_L0[(mbPartIdx_Y << 1) + mbPartIdx_X];
+        offset_indx = 0;
+
+        ref_l = video->RefPicList0[ref_idx]->Sl;
+        ref_Cb = video->RefPicList0[ref_idx]->Scb;
+        ref_Cr = video->RefPicList0[ref_idx]->Scr;
+
+        for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
+        {
+            block_x = (mbPartIdx_X << 1) + ((subMbPartIdx + offset_indx) & 1);
+            block_y = (mbPartIdx_Y << 1) + (((subMbPartIdx + offset_indx) >> 1) & 1);
+            mv = (int16*)(currMB->mvL0 + block_x + (block_y << 2));
+            offset_x = x_position + (block_x << 2);
+            offset_y = y_position + (block_y << 2);
+            x_pos = (offset_x << 2) + *mv++;   /*quarter pel */
+            y_pos = (offset_y << 2) + *mv;   /*quarter pel */
+
+            //offset = offset_y * currPic->width;
+            //offsetC = (offset >> 2) + (offset_x >> 1);
+            offsetP = (block_y << 2) * picPitch + (block_x << 2);
+            eLumaMotionComp(ref_l, picPitch, picHeight, x_pos, y_pos,
+                            /*comp_Sl + offset + offset_x,*/
+                            predBlock + offsetP, picPitch, MbWidth, MbHeight);
+
+            offsetP = (block_y * picWidth) + (block_x << 1);
+            eChromaMotionComp(ref_Cb, picWidth >> 1, picHeight >> 1, x_pos, y_pos,
+                              /*comp_Scb +  offsetC,*/
+                              predCb + offsetP, picPitch >> 1, MbWidth >> 1, MbHeight >> 1);
+            eChromaMotionComp(ref_Cr, picWidth >> 1, picHeight >> 1, x_pos, y_pos,
+                              /*comp_Scr +  offsetC,*/
+                              predCr + offsetP, picPitch >> 1, MbWidth >> 1, MbHeight >> 1);
+
+            offset_indx = currMB->SubMbPartWidth[mbPartIdx] >> 3;
+        }
+        offset_MbPart_indx = currMB->MbPartWidth >> 4;
+    }
+
+    return ;
+}
+
+
+/* preform the actual  motion comp here */
+void eLumaMotionComp(uint8 *ref, int picpitch, int picheight,
+                     int x_pos, int y_pos,
+                     uint8 *pred, int pred_pitch,
+                     int blkwidth, int blkheight)
+{
+    (void)(picheight);
+
+    int dx, dy;
+    int temp2[21][21]; /* for intermediate results */
+    uint8 *ref2;
+
+    dx = x_pos & 3;
+    dy = y_pos & 3;
+    x_pos = x_pos >> 2;  /* round it to full-pel resolution */
+    y_pos = y_pos >> 2;
+
+    /* perform actual motion compensation */
+    if (dx == 0 && dy == 0)
+    {  /* fullpel position *//* G */
+
+        ref += y_pos * picpitch + x_pos;
+
+        eFullPelMC(ref, picpitch, pred, pred_pitch, blkwidth, blkheight);
+
+    }   /* other positions */
+    else  if (dy == 0)
+    { /* no vertical interpolation *//* a,b,c*/
+
+        ref += y_pos * picpitch + x_pos;
+
+        eHorzInterp1MC(ref, picpitch, pred, pred_pitch, blkwidth, blkheight, dx);
+    }
+    else if (dx == 0)
+    { /*no horizontal interpolation *//* d,h,n */
+
+        ref += y_pos * picpitch + x_pos;
+
+        eVertInterp1MC(ref, picpitch, pred, pred_pitch, blkwidth, blkheight, dy);
+    }
+    else if (dy == 2)
+    {  /* horizontal cross *//* i, j, k */
+
+        ref += y_pos * picpitch + x_pos - 2; /* move to the left 2 pixels */
+
+        eVertInterp2MC(ref, picpitch, &temp2[0][0], 21, blkwidth + 5, blkheight);
+
+        eHorzInterp2MC(&temp2[0][2], 21, pred, pred_pitch, blkwidth, blkheight, dx);
+    }
+    else if (dx == 2)
+    { /* vertical cross */ /* f,q */
+
+        ref += (y_pos - 2) * picpitch + x_pos; /* move to up 2 lines */
+
+        eHorzInterp3MC(ref, picpitch, &temp2[0][0], 21, blkwidth, blkheight + 5);
+        eVertInterp3MC(&temp2[2][0], 21, pred, pred_pitch, blkwidth, blkheight, dy);
+    }
+    else
+    { /* diagonal *//* e,g,p,r */
+
+        ref2 = ref + (y_pos + (dy / 2)) * picpitch + x_pos;
+
+        ref += (y_pos * picpitch) + x_pos + (dx / 2);
+
+        eDiagonalInterpMC(ref2, ref, picpitch, pred, pred_pitch, blkwidth, blkheight);
+    }
+
+    return ;
+}
+
+void eCreateAlign(uint8 *ref, int picpitch, int y_pos,
+                  uint8 *out, int blkwidth, int blkheight)
+{
+    int i, j;
+    int offset, out_offset;
+    uint32 prev_pix, result, pix1, pix2, pix4;
+
+    ref += y_pos * picpitch;// + x_pos;
+    out_offset = 24 - blkwidth;
+
+    //switch(x_pos&0x3){
+    switch (((uint32)ref)&0x3)
+    {
+        case 1:
+            offset =  picpitch - blkwidth - 3;
+            for (j = 0; j < blkheight; j++)
+            {
+                pix1 = *ref++;
+                pix2 = *((uint16*)ref);
+                ref += 2;
+                result = (pix2 << 8) | pix1;
+
+                for (i = 3; i < blkwidth; i += 4)
+                {
+                    pix4 = *((uint32*)ref);
+                    ref += 4;
+                    prev_pix = (pix4 << 24) & 0xFF000000; /* mask out byte belong to previous word */
+                    result |= prev_pix;
+                    *((uint32*)out) = result;  /* write 4 bytes */
+                    out += 4;
+                    result = pix4 >> 8; /* for the next loop */
+                }
+                ref += offset;
+                out += out_offset;
+            }
+            break;
+        case 2:
+            offset =  picpitch - blkwidth - 2;
+            for (j = 0; j < blkheight; j++)
+            {
+                result = *((uint16*)ref);
+                ref += 2;
+                for (i = 2; i < blkwidth; i += 4)
+                {
+                    pix4 = *((uint32*)ref);
+                    ref += 4;
+                    prev_pix = (pix4 << 16) & 0xFFFF0000; /* mask out byte belong to previous word */
+                    result |= prev_pix;
+                    *((uint32*)out) = result;  /* write 4 bytes */
+                    out += 4;
+                    result = pix4 >> 16; /* for the next loop */
+                }
+                ref += offset;
+                out += out_offset;
+            }
+            break;
+        case 3:
+            offset =  picpitch - blkwidth - 1;
+            for (j = 0; j < blkheight; j++)
+            {
+                result = *ref++;
+                for (i = 1; i < blkwidth; i += 4)
+                {
+                    pix4 = *((uint32*)ref);
+                    ref += 4;
+                    prev_pix = (pix4 << 8) & 0xFFFFFF00; /* mask out byte belong to previous word */
+                    result |= prev_pix;
+                    *((uint32*)out) = result;  /* write 4 bytes */
+                    out += 4;
+                    result = pix4 >> 24; /* for the next loop */
+                }
+                ref += offset;
+                out += out_offset;
+            }
+            break;
+    }
+}
+
+void eHorzInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight, int dx)
+{
+    uint8 *p_ref;
+    uint32 *p_cur;
+    uint32 tmp, pkres;
+    int result, curr_offset, ref_offset;
+    int j;
+    int32 r0, r1, r2, r3, r4, r5;
+    int32 r13, r6;
+
+    p_cur = (uint32*)out; /* assume it's word aligned */
+    curr_offset = (outpitch - blkwidth) >> 2;
+    p_ref = in;
+    ref_offset = inpitch - blkwidth;
+
+    if (dx&1)
+    {
+        dx = ((dx >> 1) ? -3 : -4); /* use in 3/4 pel */
+        p_ref -= 2;
+        r13 = 0;
+        for (j = blkheight; j > 0; j--)
+        {
+            tmp = (uint32)(p_ref + blkwidth);
+            r0 = p_ref[0];
+            r1 = p_ref[2];
+            r0 |= (r1 << 16);           /* 0,c,0,a */
+            r1 = p_ref[1];
+            r2 = p_ref[3];
+            r1 |= (r2 << 16);           /* 0,d,0,b */
+            while ((uint32)p_ref < tmp)
+            {
+                r2 = *(p_ref += 4); /* move pointer to e */
+                r3 = p_ref[2];
+                r2 |= (r3 << 16);           /* 0,g,0,e */
+                r3 = p_ref[1];
+                r4 = p_ref[3];
+                r3 |= (r4 << 16);           /* 0,h,0,f */
+
+                r4 = r0 + r3;       /* c+h, a+f */
+                r5 = r0 + r1;   /* c+d, a+b */
+                r6 = r2 + r3;   /* g+h, e+f */
+                r5 >>= 16;
+                r5 |= (r6 << 16);   /* e+f, c+d */
+                r4 += r5 * 20;      /* c+20*e+20*f+h, a+20*c+20*d+f */
+                r4 += 0x100010; /* +16, +16 */
+                r5 = r1 + r2;       /* d+g, b+e */
+                r4 -= r5 * 5;       /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */
+                r4 >>= 5;
+                r13 |= r4;      /* check clipping */
+
+                r5 = p_ref[dx+2];
+                r6 = p_ref[dx+4];
+                r5 |= (r6 << 16);
+                r4 += r5;
+                r4 += 0x10001;
+                r4 = (r4 >> 1) & 0xFF00FF;
+
+                r5 = p_ref[4];  /* i */
+                r6 = (r5 << 16);
+                r5 = r6 | (r2 >> 16);/* 0,i,0,g */
+                r5 += r1;       /* d+i, b+g */ /* r5 not free */
+                r1 >>= 16;
+                r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */
+                r1 += r2;       /* f+g, d+e */
+                r5 += 20 * r1;  /* d+20f+20g+i, b+20d+20e+g */
+                r0 >>= 16;
+                r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */
+                r0 += r3;       /* e+h, c+f */
+                r5 += 0x100010; /* 16,16 */
+                r5 -= r0 * 5;       /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */
+                r5 >>= 5;
+                r13 |= r5;      /* check clipping */
+
+                r0 = p_ref[dx+3];
+                r1 = p_ref[dx+5];
+                r0 |= (r1 << 16);
+                r5 += r0;
+                r5 += 0x10001;
+                r5 = (r5 >> 1) & 0xFF00FF;
+
+                r4 |= (r5 << 8);    /* pack them together */
+                *p_cur++ = r4;
+                r1 = r3;
+                r0 = r2;
+            }
+            p_cur += curr_offset; /* move to the next line */
+            p_ref += ref_offset;  /*    ref_offset = inpitch-blkwidth; */
+
+            if (r13&0xFF000700) /* need clipping */
+            {
+                /* move back to the beginning of the line */
+                p_ref -= (ref_offset + blkwidth);   /* input */
+                p_cur -= (outpitch >> 2);
+
+                tmp = (uint32)(p_ref + blkwidth);
+                for (; (uint32)p_ref < tmp;)
+                {
+
+                    r0 = *p_ref++;
+                    r1 = *p_ref++;
+                    r2 = *p_ref++;
+                    r3 = *p_ref++;
+                    r4 = *p_ref++;
+                    /* first pixel */
+                    r5 = *p_ref++;
+                    result = (r0 + r5);
+                    r0 = (r1 + r4);
+                    result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                    r0 = (r2 + r3);
+                    result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    /* 3/4 pel,  no need to clip */
+                    result = (result + p_ref[dx] + 1);
+                    pkres = (result >> 1) ;
+                    /* second pixel */
+                    r0 = *p_ref++;
+                    result = (r1 + r0);
+                    r1 = (r2 + r5);
+                    result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                    r1 = (r3 + r4);
+                    result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    /* 3/4 pel,  no need to clip */
+                    result = (result + p_ref[dx] + 1);
+                    result = (result >> 1);
+                    pkres  |= (result << 8);
+                    /* third pixel */
+                    r1 = *p_ref++;
+                    result = (r2 + r1);
+                    r2 = (r3 + r0);
+                    result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                    r2 = (r4 + r5);
+                    result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    /* 3/4 pel,  no need to clip */
+                    result = (result + p_ref[dx] + 1);
+                    result = (result >> 1);
+                    pkres  |= (result << 16);
+                    /* fourth pixel */
+                    r2 = *p_ref++;
+                    result = (r3 + r2);
+                    r3 = (r4 + r1);
+                    result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                    r3 = (r5 + r0);
+                    result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    /* 3/4 pel,  no need to clip */
+                    result = (result + p_ref[dx] + 1);
+                    result = (result >> 1);
+                    pkres  |= (result << 24);
+                    *p_cur++ = pkres; /* write 4 pixels */
+                    p_ref -= 5;  /* offset back to the middle of filter */
+                }
+                p_cur += curr_offset;  /* move to the next line */
+                p_ref += ref_offset;    /* move to the next line */
+            }
+        }
+    }
+    else
+    {
+        p_ref -= 2;
+        r13 = 0;
+        for (j = blkheight; j > 0; j--)
+        {
+            tmp = (uint32)(p_ref + blkwidth);
+            r0 = p_ref[0];
+            r1 = p_ref[2];
+            r0 |= (r1 << 16);           /* 0,c,0,a */
+            r1 = p_ref[1];
+            r2 = p_ref[3];
+            r1 |= (r2 << 16);           /* 0,d,0,b */
+            while ((uint32)p_ref < tmp)
+            {
+                r2 = *(p_ref += 4); /* move pointer to e */
+                r3 = p_ref[2];
+                r2 |= (r3 << 16);           /* 0,g,0,e */
+                r3 = p_ref[1];
+                r4 = p_ref[3];
+                r3 |= (r4 << 16);           /* 0,h,0,f */
+
+                r4 = r0 + r3;       /* c+h, a+f */
+                r5 = r0 + r1;   /* c+d, a+b */
+                r6 = r2 + r3;   /* g+h, e+f */
+                r5 >>= 16;
+                r5 |= (r6 << 16);   /* e+f, c+d */
+                r4 += r5 * 20;      /* c+20*e+20*f+h, a+20*c+20*d+f */
+                r4 += 0x100010; /* +16, +16 */
+                r5 = r1 + r2;       /* d+g, b+e */
+                r4 -= r5 * 5;       /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */
+                r4 >>= 5;
+                r13 |= r4;      /* check clipping */
+                r4 &= 0xFF00FF; /* mask */
+
+                r5 = p_ref[4];  /* i */
+                r6 = (r5 << 16);
+                r5 = r6 | (r2 >> 16);/* 0,i,0,g */
+                r5 += r1;       /* d+i, b+g */ /* r5 not free */
+                r1 >>= 16;
+                r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */
+                r1 += r2;       /* f+g, d+e */
+                r5 += 20 * r1;  /* d+20f+20g+i, b+20d+20e+g */
+                r0 >>= 16;
+                r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */
+                r0 += r3;       /* e+h, c+f */
+                r5 += 0x100010; /* 16,16 */
+                r5 -= r0 * 5;       /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */
+                r5 >>= 5;
+                r13 |= r5;      /* check clipping */
+                r5 &= 0xFF00FF; /* mask */
+
+                r4 |= (r5 << 8);    /* pack them together */
+                *p_cur++ = r4;
+                r1 = r3;
+                r0 = r2;
+            }
+            p_cur += curr_offset; /* move to the next line */
+            p_ref += ref_offset;  /*    ref_offset = inpitch-blkwidth; */
+
+            if (r13&0xFF000700) /* need clipping */
+            {
+                /* move back to the beginning of the line */
+                p_ref -= (ref_offset + blkwidth);   /* input */
+                p_cur -= (outpitch >> 2);
+
+                tmp = (uint32)(p_ref + blkwidth);
+                for (; (uint32)p_ref < tmp;)
+                {
+
+                    r0 = *p_ref++;
+                    r1 = *p_ref++;
+                    r2 = *p_ref++;
+                    r3 = *p_ref++;
+                    r4 = *p_ref++;
+                    /* first pixel */
+                    r5 = *p_ref++;
+                    result = (r0 + r5);
+                    r0 = (r1 + r4);
+                    result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                    r0 = (r2 + r3);
+                    result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    pkres  = result;
+                    /* second pixel */
+                    r0 = *p_ref++;
+                    result = (r1 + r0);
+                    r1 = (r2 + r5);
+                    result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                    r1 = (r3 + r4);
+                    result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    pkres  |= (result << 8);
+                    /* third pixel */
+                    r1 = *p_ref++;
+                    result = (r2 + r1);
+                    r2 = (r3 + r0);
+                    result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                    r2 = (r4 + r5);
+                    result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    pkres  |= (result << 16);
+                    /* fourth pixel */
+                    r2 = *p_ref++;
+                    result = (r3 + r2);
+                    r3 = (r4 + r1);
+                    result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                    r3 = (r5 + r0);
+                    result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    pkres  |= (result << 24);
+                    *p_cur++ = pkres;   /* write 4 pixels */
+                    p_ref -= 5;
+                }
+                p_cur += curr_offset; /* move to the next line */
+                p_ref += ref_offset;
+            }
+        }
+    }
+
+    return ;
+}
+
+void eHorzInterp2MC(int *in, int inpitch, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight, int dx)
+{
+    int *p_ref;
+    uint32 *p_cur;
+    uint32 tmp, pkres;
+    int result, result2, curr_offset, ref_offset;
+    int j, r0, r1, r2, r3, r4, r5;
+
+    p_cur = (uint32*)out; /* assume it's word aligned */
+    curr_offset = (outpitch - blkwidth) >> 2;
+    p_ref = in;
+    ref_offset = inpitch - blkwidth;
+
+    if (dx&1)
+    {
+        dx = ((dx >> 1) ? -3 : -4); /* use in 3/4 pel */
+
+        for (j = blkheight; j > 0 ; j--)
+        {
+            tmp = (uint32)(p_ref + blkwidth);
+            for (; (uint32)p_ref < tmp;)
+            {
+
+                r0 = p_ref[-2];
+                r1 = p_ref[-1];
+                r2 = *p_ref++;
+                r3 = *p_ref++;
+                r4 = *p_ref++;
+                /* first pixel */
+                r5 = *p_ref++;
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dx] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                pkres = (result >> 1);
+                /* second pixel */
+                r0 = *p_ref++;
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dx] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                pkres  |= (result << 8);
+                /* third pixel */
+                r1 = *p_ref++;
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dx] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                pkres  |= (result << 16);
+                /* fourth pixel */
+                r2 = *p_ref++;
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dx] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                pkres  |= (result << 24);
+                *p_cur++ = pkres; /* write 4 pixels */
+                p_ref -= 3;  /* offset back to the middle of filter */
+            }
+            p_cur += curr_offset;  /* move to the next line */
+            p_ref += ref_offset;    /* move to the next line */
+        }
+    }
+    else
+    {
+        for (j = blkheight; j > 0 ; j--)
+        {
+            tmp = (uint32)(p_ref + blkwidth);
+            for (; (uint32)p_ref < tmp;)
+            {
+
+                r0 = p_ref[-2];
+                r1 = p_ref[-1];
+                r2 = *p_ref++;
+                r3 = *p_ref++;
+                r4 = *p_ref++;
+                /* first pixel */
+                r5 = *p_ref++;
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                pkres  = result;
+                /* second pixel */
+                r0 = *p_ref++;
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                pkres  |= (result << 8);
+                /* third pixel */
+                r1 = *p_ref++;
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                pkres  |= (result << 16);
+                /* fourth pixel */
+                r2 = *p_ref++;
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                pkres  |= (result << 24);
+                *p_cur++ = pkres; /* write 4 pixels */
+                p_ref -= 3;  /* offset back to the middle of filter */
+            }
+            p_cur += curr_offset;  /* move to the next line */
+            p_ref += ref_offset;    /* move to the next line */
+        }
+    }
+
+    return ;
+}
+
+void eHorzInterp3MC(uint8 *in, int inpitch, int *out, int outpitch,
+                    int blkwidth, int blkheight)
+{
+    uint8 *p_ref;
+    int   *p_cur;
+    uint32 tmp;
+    int result, curr_offset, ref_offset;
+    int j, r0, r1, r2, r3, r4, r5;
+
+    p_cur = out;
+    curr_offset = (outpitch - blkwidth);
+    p_ref = in;
+    ref_offset = inpitch - blkwidth;
+
+    for (j = blkheight; j > 0 ; j--)
+    {
+        tmp = (uint32)(p_ref + blkwidth);
+        for (; (uint32)p_ref < tmp;)
+        {
+
+            r0 = p_ref[-2];
+            r1 = p_ref[-1];
+            r2 = *p_ref++;
+            r3 = *p_ref++;
+            r4 = *p_ref++;
+            /* first pixel */
+            r5 = *p_ref++;
+            result = (r0 + r5);
+            r0 = (r1 + r4);
+            result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+            r0 = (r2 + r3);
+            result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+            *p_cur++ = result;
+            /* second pixel */
+            r0 = *p_ref++;
+            result = (r1 + r0);
+            r1 = (r2 + r5);
+            result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+            r1 = (r3 + r4);
+            result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+            *p_cur++ = result;
+            /* third pixel */
+            r1 = *p_ref++;
+            result = (r2 + r1);
+            r2 = (r3 + r0);
+            result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+            r2 = (r4 + r5);
+            result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+            *p_cur++ = result;
+            /* fourth pixel */
+            r2 = *p_ref++;
+            result = (r3 + r2);
+            r3 = (r4 + r1);
+            result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+            r3 = (r5 + r0);
+            result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+            *p_cur++ = result;
+            p_ref -= 3; /* move back to the middle of the filter */
+        }
+        p_cur += curr_offset; /* move to the next line */
+        p_ref += ref_offset;
+    }
+
+    return ;
+}
+void eVertInterp1MC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight, int dy)
+{
+    uint8 *p_cur, *p_ref;
+    uint32 tmp;
+    int result, curr_offset, ref_offset;
+    int j, i;
+    int32 r0, r1, r2, r3, r4, r5, r6, r7, r8, r13;
+    uint8  tmp_in[24][24];
+
+    /* not word-aligned */
+    if (((uint32)in)&0x3)
+    {
+        eCreateAlign(in, inpitch, -2, &tmp_in[0][0], blkwidth, blkheight + 5);
+        in = &tmp_in[2][0];
+        inpitch = 24;
+    }
+    p_cur = out;
+    curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */
+    ref_offset = blkheight * inpitch; /* for limit */
+
+    curr_offset += 3;
+
+    if (dy&1)
+    {
+        dy = (dy >> 1) ? 0 : -inpitch;
+
+        for (j = 0; j < blkwidth; j += 4, in += 4)
+        {
+            r13 = 0;
+            p_ref = in;
+            p_cur -= outpitch;  /* compensate for the first offset */
+            tmp = (uint32)(p_ref + ref_offset); /* limit */
+            while ((uint32)p_ref < tmp)  /* the loop un-rolled  */
+            {
+                r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */
+                p_ref += inpitch;
+                r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */
+                r0 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref + (inpitch << 1)));  /* r1, r7, ref[3] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+
+                r0 += r1;
+                r6 += r7;
+
+                r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */
+                r8 = (r2 >> 8) & 0xFF00FF;
+                r2 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r1 += r2;
+
+                r7 += r8;
+
+                r0 += 20 * r1;
+                r6 += 20 * r7;
+                r0 += 0x100010;
+                r6 += 0x100010;
+
+                r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */
+                r8 = (r2 >> 8) & 0xFF00FF;
+                r2 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r1 += r2;
+
+                r7 += r8;
+
+                r0 -= 5 * r1;
+                r6 -= 5 * r7;
+
+                r0 >>= 5;
+                r6 >>= 5;
+                /* clip */
+                r13 |= r6;
+                r13 |= r0;
+                //CLIPPACK(r6,result)
+
+                r1 = *((uint32*)(p_ref + dy));
+                r2 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r0 += r1;
+                r6 += r2;
+                r0 += 0x10001;
+                r6 += 0x10001;
+                r0 = (r0 >> 1) & 0xFF00FF;
+                r6 = (r6 >> 1) & 0xFF00FF;
+
+                r0 |= (r6 << 8);  /* pack it back */
+                *((uint32*)(p_cur += outpitch)) = r0;
+            }
+            p_cur += curr_offset; /* offset to the next pixel */
+            if (r13 & 0xFF000700) /* this column need clipping */
+            {
+                p_cur -= 4;
+                for (i = 0; i < 4; i++)
+                {
+                    p_ref = in + i;
+                    p_cur -= outpitch;  /* compensate for the first offset */
+
+                    tmp = (uint32)(p_ref + ref_offset); /* limit */
+                    while ((uint32)p_ref < tmp)
+                    {                           /* loop un-rolled */
+                        r0 = *(p_ref - (inpitch << 1));
+                        r1 = *(p_ref - inpitch);
+                        r2 = *p_ref;
+                        r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                        r4 = *(p_ref += inpitch);
+                        /* first pixel */
+                        r5 = *(p_ref += inpitch);
+                        result = (r0 + r5);
+                        r0 = (r1 + r4);
+                        result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                        r0 = (r2 + r3);
+                        result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        /* 3/4 pel,  no need to clip */
+                        result = (result + p_ref[dy-(inpitch<<1)] + 1);
+                        result = (result >> 1);
+                        *(p_cur += outpitch) = result;
+                        /* second pixel */
+                        r0 = *(p_ref += inpitch);
+                        result = (r1 + r0);
+                        r1 = (r2 + r5);
+                        result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                        r1 = (r3 + r4);
+                        result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        /* 3/4 pel,  no need to clip */
+                        result = (result + p_ref[dy-(inpitch<<1)] + 1);
+                        result = (result >> 1);
+                        *(p_cur += outpitch) = result;
+                        /* third pixel */
+                        r1 = *(p_ref += inpitch);
+                        result = (r2 + r1);
+                        r2 = (r3 + r0);
+                        result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                        r2 = (r4 + r5);
+                        result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        /* 3/4 pel,  no need to clip */
+                        result = (result + p_ref[dy-(inpitch<<1)] + 1);
+                        result = (result >> 1);
+                        *(p_cur += outpitch) = result;
+                        /* fourth pixel */
+                        r2 = *(p_ref += inpitch);
+                        result = (r3 + r2);
+                        r3 = (r4 + r1);
+                        result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                        r3 = (r5 + r0);
+                        result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        /* 3/4 pel,  no need to clip */
+                        result = (result + p_ref[dy-(inpitch<<1)] + 1);
+                        result = (result >> 1);
+                        *(p_cur += outpitch) = result;
+                        p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+                    }
+                    p_cur += (curr_offset - 3);
+                }
+            }
+        }
+    }
+    else
+    {
+        for (j = 0; j < blkwidth; j += 4, in += 4)
+        {
+            r13 = 0;
+            p_ref = in;
+            p_cur -= outpitch;  /* compensate for the first offset */
+            tmp = (uint32)(p_ref + ref_offset); /* limit */
+            while ((uint32)p_ref < tmp)  /* the loop un-rolled  */
+            {
+                r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */
+                p_ref += inpitch;
+                r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */
+                r0 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref + (inpitch << 1)));  /* r1, r7, ref[3] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+
+                r0 += r1;
+                r6 += r7;
+
+                r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */
+                r8 = (r2 >> 8) & 0xFF00FF;
+                r2 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r1 += r2;
+
+                r7 += r8;
+
+                r0 += 20 * r1;
+                r6 += 20 * r7;
+                r0 += 0x100010;
+                r6 += 0x100010;
+
+                r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */
+                r8 = (r2 >> 8) & 0xFF00FF;
+                r2 &= 0xFF00FF;
+
+                r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */
+                r7 = (r1 >> 8) & 0xFF00FF;
+                r1 &= 0xFF00FF;
+                r1 += r2;
+
+                r7 += r8;
+
+                r0 -= 5 * r1;
+                r6 -= 5 * r7;
+
+                r0 >>= 5;
+                r6 >>= 5;
+                /* clip */
+                r13 |= r6;
+                r13 |= r0;
+                //CLIPPACK(r6,result)
+                r0 &= 0xFF00FF;
+                r6 &= 0xFF00FF;
+                r0 |= (r6 << 8);  /* pack it back */
+                *((uint32*)(p_cur += outpitch)) = r0;
+            }
+            p_cur += curr_offset; /* offset to the next pixel */
+            if (r13 & 0xFF000700) /* this column need clipping */
+            {
+                p_cur -= 4;
+                for (i = 0; i < 4; i++)
+                {
+                    p_ref = in + i;
+                    p_cur -= outpitch;  /* compensate for the first offset */
+                    tmp = (uint32)(p_ref + ref_offset); /* limit */
+                    while ((uint32)p_ref < tmp)
+                    {                           /* loop un-rolled */
+                        r0 = *(p_ref - (inpitch << 1));
+                        r1 = *(p_ref - inpitch);
+                        r2 = *p_ref;
+                        r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                        r4 = *(p_ref += inpitch);
+                        /* first pixel */
+                        r5 = *(p_ref += inpitch);
+                        result = (r0 + r5);
+                        r0 = (r1 + r4);
+                        result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                        r0 = (r2 + r3);
+                        result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        *(p_cur += outpitch) = result;
+                        /* second pixel */
+                        r0 = *(p_ref += inpitch);
+                        result = (r1 + r0);
+                        r1 = (r2 + r5);
+                        result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                        r1 = (r3 + r4);
+                        result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        *(p_cur += outpitch) = result;
+                        /* third pixel */
+                        r1 = *(p_ref += inpitch);
+                        result = (r2 + r1);
+                        r2 = (r3 + r0);
+                        result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                        r2 = (r4 + r5);
+                        result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        *(p_cur += outpitch) = result;
+                        /* fourth pixel */
+                        r2 = *(p_ref += inpitch);
+                        result = (r3 + r2);
+                        r3 = (r4 + r1);
+                        result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                        r3 = (r5 + r0);
+                        result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                        result = (result + 16) >> 5;
+                        CLIP_RESULT(result)
+                        *(p_cur += outpitch) = result;
+                        p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+                    }
+                    p_cur += (curr_offset - 3);
+                }
+            }
+        }
+    }
+
+    return ;
+}
+
+void eVertInterp2MC(uint8 *in, int inpitch, int *out, int outpitch,
+                    int blkwidth, int blkheight)
+{
+    int *p_cur;
+    uint8 *p_ref;
+    uint32 tmp;
+    int result, curr_offset, ref_offset;
+    int j, r0, r1, r2, r3, r4, r5;
+
+    p_cur = out;
+    curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */
+    ref_offset = blkheight * inpitch; /* for limit */
+
+    for (j = 0; j < blkwidth; j++)
+    {
+        p_cur -= outpitch; /* compensate for the first offset */
+        p_ref = in++;
+
+        tmp = (uint32)(p_ref + ref_offset); /* limit */
+        while ((uint32)p_ref < tmp)
+        {                           /* loop un-rolled */
+            r0 = *(p_ref - (inpitch << 1));
+            r1 = *(p_ref - inpitch);
+            r2 = *p_ref;
+            r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+            r4 = *(p_ref += inpitch);
+            /* first pixel */
+            r5 = *(p_ref += inpitch);
+            result = (r0 + r5);
+            r0 = (r1 + r4);
+            result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+            r0 = (r2 + r3);
+            result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+            *(p_cur += outpitch) = result;
+            /* second pixel */
+            r0 = *(p_ref += inpitch);
+            result = (r1 + r0);
+            r1 = (r2 + r5);
+            result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+            r1 = (r3 + r4);
+            result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+            *(p_cur += outpitch) = result;
+            /* third pixel */
+            r1 = *(p_ref += inpitch);
+            result = (r2 + r1);
+            r2 = (r3 + r0);
+            result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+            r2 = (r4 + r5);
+            result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+            *(p_cur += outpitch) = result;
+            /* fourth pixel */
+            r2 = *(p_ref += inpitch);
+            result = (r3 + r2);
+            r3 = (r4 + r1);
+            result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+            r3 = (r5 + r0);
+            result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+            *(p_cur += outpitch) = result;
+            p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+        }
+        p_cur += curr_offset;
+    }
+
+    return ;
+}
+
+void eVertInterp3MC(int *in, int inpitch, uint8 *out, int outpitch,
+                    int blkwidth, int blkheight, int dy)
+{
+    uint8 *p_cur;
+    int *p_ref;
+    uint32 tmp;
+    int result, result2, curr_offset, ref_offset;
+    int j, r0, r1, r2, r3, r4, r5;
+
+    p_cur = out;
+    curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically back up and one pixel to right */
+    ref_offset = blkheight * inpitch; /* for limit */
+
+    if (dy&1)
+    {
+        dy = (dy >> 1) ? -(inpitch << 1) : -(inpitch << 1) - inpitch;
+
+        for (j = 0; j < blkwidth; j++)
+        {
+            p_cur -= outpitch; /* compensate for the first offset */
+            p_ref = in++;
+
+            tmp = (uint32)(p_ref + ref_offset); /* limit */
+            while ((uint32)p_ref < tmp)
+            {                           /* loop un-rolled */
+                r0 = *(p_ref - (inpitch << 1));
+                r1 = *(p_ref - inpitch);
+                r2 = *p_ref;
+                r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                r4 = *(p_ref += inpitch);
+                /* first pixel */
+                r5 = *(p_ref += inpitch);
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dy] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                *(p_cur += outpitch) = result;
+                /* second pixel */
+                r0 = *(p_ref += inpitch);
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dy] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                *(p_cur += outpitch) = result;
+                /* third pixel */
+                r1 = *(p_ref += inpitch);
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dy] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                *(p_cur += outpitch) = result;
+                /* fourth pixel */
+                r2 = *(p_ref += inpitch);
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                result2 = ((p_ref[dy] + 16) >> 5);
+                CLIP_RESULT(result2)
+                /* 3/4 pel,  no need to clip */
+                result = (result + result2 + 1);
+                result = (result >> 1);
+                *(p_cur += outpitch) = result;
+                p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+            }
+            p_cur += curr_offset;
+        }
+    }
+    else
+    {
+        for (j = 0; j < blkwidth; j++)
+        {
+            p_cur -= outpitch; /* compensate for the first offset */
+            p_ref = in++;
+
+            tmp = (uint32)(p_ref + ref_offset); /* limit */
+            while ((uint32)p_ref < tmp)
+            {                           /* loop un-rolled */
+                r0 = *(p_ref - (inpitch << 1));
+                r1 = *(p_ref - inpitch);
+                r2 = *p_ref;
+                r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                r4 = *(p_ref += inpitch);
+                /* first pixel */
+                r5 = *(p_ref += inpitch);
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                *(p_cur += outpitch) = result;
+                /* second pixel */
+                r0 = *(p_ref += inpitch);
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                *(p_cur += outpitch) = result;
+                /* third pixel */
+                r1 = *(p_ref += inpitch);
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                *(p_cur += outpitch) = result;
+                /* fourth pixel */
+                r2 = *(p_ref += inpitch);
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 512) >> 10;
+                CLIP_RESULT(result)
+                *(p_cur += outpitch) = result;
+                p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+            }
+            p_cur += curr_offset;
+        }
+    }
+
+    return ;
+}
+
+void eDiagonalInterpMC(uint8 *in1, uint8 *in2, int inpitch,
+                       uint8 *out, int outpitch,
+                       int blkwidth, int blkheight)
+{
+    int j, i;
+    int result;
+    uint8 *p_cur, *p_ref, *p_tmp8;
+    int curr_offset, ref_offset;
+    uint8 tmp_res[24][24], tmp_in[24][24];
+    uint32 *p_tmp;
+    uint32 tmp, pkres, tmp_result;
+    int32 r0, r1, r2, r3, r4, r5;
+    int32 r6, r7, r8, r9, r10, r13;
+
+    ref_offset = inpitch - blkwidth;
+    p_ref = in1 - 2;
+    /* perform horizontal interpolation */
+    /* not word-aligned */
+    /* It is faster to read 1 byte at time to avoid calling CreateAlign */
+    /*  if(((uint32)p_ref)&0x3)
+        {
+            CreateAlign(p_ref,inpitch,0,&tmp_in[0][0],blkwidth+8,blkheight);
+            p_ref = &tmp_in[0][0];
+            ref_offset = 24-blkwidth;
+        }*/
+
+    p_tmp = (uint32*) & (tmp_res[0][0]);
+    for (j = blkheight; j > 0; j--)
+    {
+        r13 = 0;
+        tmp = (uint32)(p_ref + blkwidth);
+
+        //r0 = *((uint32*)p_ref);   /* d,c,b,a */
+        //r1 = (r0>>8)&0xFF00FF;    /* 0,d,0,b */
+        //r0 &= 0xFF00FF;           /* 0,c,0,a */
+        /* It is faster to read 1 byte at a time */
+        r0 = p_ref[0];
+        r1 = p_ref[2];
+        r0 |= (r1 << 16);           /* 0,c,0,a */
+        r1 = p_ref[1];
+        r2 = p_ref[3];
+        r1 |= (r2 << 16);           /* 0,d,0,b */
+
+        while ((uint32)p_ref < tmp)
+        {
+            //r2 = *((uint32*)(p_ref+=4));/* h,g,f,e */
+            //r3 = (r2>>8)&0xFF00FF;  /* 0,h,0,f */
+            //r2 &= 0xFF00FF;           /* 0,g,0,e */
+            /* It is faster to read 1 byte at a time */
+            r2 = *(p_ref += 4);
+            r3 = p_ref[2];
+            r2 |= (r3 << 16);           /* 0,g,0,e */
+            r3 = p_ref[1];
+            r4 = p_ref[3];
+            r3 |= (r4 << 16);           /* 0,h,0,f */
+
+            r4 = r0 + r3;       /* c+h, a+f */
+            r5 = r0 + r1;   /* c+d, a+b */
+            r6 = r2 + r3;   /* g+h, e+f */
+            r5 >>= 16;
+            r5 |= (r6 << 16);   /* e+f, c+d */
+            r4 += r5 * 20;      /* c+20*e+20*f+h, a+20*c+20*d+f */
+            r4 += 0x100010; /* +16, +16 */
+            r5 = r1 + r2;       /* d+g, b+e */
+            r4 -= r5 * 5;       /* c-5*d+20*e+20*f-5*g+h, a-5*b+20*c+20*d-5*e+f */
+            r4 >>= 5;
+            r13 |= r4;      /* check clipping */
+            r4 &= 0xFF00FF; /* mask */
+
+            r5 = p_ref[4];  /* i */
+            r6 = (r5 << 16);
+            r5 = r6 | (r2 >> 16);/* 0,i,0,g */
+            r5 += r1;       /* d+i, b+g */ /* r5 not free */
+            r1 >>= 16;
+            r1 |= (r3 << 16); /* 0,f,0,d */ /* r1 has changed */
+            r1 += r2;       /* f+g, d+e */
+            r5 += 20 * r1;  /* d+20f+20g+i, b+20d+20e+g */
+            r0 >>= 16;
+            r0 |= (r2 << 16); /* 0,e,0,c */ /* r0 has changed */
+            r0 += r3;       /* e+h, c+f */
+            r5 += 0x100010; /* 16,16 */
+            r5 -= r0 * 5;       /* d-5e+20f+20g-5h+i, b-5c+20d+20e-5f+g */
+            r5 >>= 5;
+            r13 |= r5;      /* check clipping */
+            r5 &= 0xFF00FF; /* mask */
+
+            r4 |= (r5 << 8);    /* pack them together */
+            *p_tmp++ = r4;
+            r1 = r3;
+            r0 = r2;
+        }
+        p_tmp += ((24 - blkwidth) >> 2); /* move to the next line */
+        p_ref += ref_offset;  /*    ref_offset = inpitch-blkwidth; */
+
+        if (r13&0xFF000700) /* need clipping */
+        {
+            /* move back to the beginning of the line */
+            p_ref -= (ref_offset + blkwidth);   /* input */
+            p_tmp -= 6; /* intermediate output */
+            tmp = (uint32)(p_ref + blkwidth);
+            while ((uint32)p_ref < tmp)
+            {
+                r0 = *p_ref++;
+                r1 = *p_ref++;
+                r2 = *p_ref++;
+                r3 = *p_ref++;
+                r4 = *p_ref++;
+                /* first pixel */
+                r5 = *p_ref++;
+                result = (r0 + r5);
+                r0 = (r1 + r4);
+                result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                r0 = (r2 + r3);
+                result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                result = (result + 16) >> 5;
+                CLIP_RESULT(result)
+                pkres = result;
+                /* second pixel */
+                r0 = *p_ref++;
+                result = (r1 + r0);
+                r1 = (r2 + r5);
+                result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                r1 = (r3 + r4);
+                result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                result = (result + 16) >> 5;
+                CLIP_RESULT(result)
+                pkres |= (result << 8);
+                /* third pixel */
+                r1 = *p_ref++;
+                result = (r2 + r1);
+                r2 = (r3 + r0);
+                result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                r2 = (r4 + r5);
+                result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                result = (result + 16) >> 5;
+                CLIP_RESULT(result)
+                pkres |= (result << 16);
+                /* fourth pixel */
+                r2 = *p_ref++;
+                result = (r3 + r2);
+                r3 = (r4 + r1);
+                result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                r3 = (r5 + r0);
+                result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                result = (result + 16) >> 5;
+                CLIP_RESULT(result)
+                pkres |= (result << 24);
+
+                *p_tmp++ = pkres; /* write 4 pixel */
+                p_ref -= 5;
+            }
+            p_tmp += ((24 - blkwidth) >> 2); /* move to the next line */
+            p_ref += ref_offset;  /*    ref_offset = inpitch-blkwidth; */
+        }
+    }
+
+    /*  perform vertical interpolation */
+    /* not word-aligned */
+    if (((uint32)in2)&0x3)
+    {
+        eCreateAlign(in2, inpitch, -2, &tmp_in[0][0], blkwidth, blkheight + 5);
+        in2 = &tmp_in[2][0];
+        inpitch = 24;
+    }
+
+    p_cur = out;
+    curr_offset = 1 - outpitch * (blkheight - 1); /* offset vertically up and one pixel right */
+    pkres = blkheight * inpitch; /* reuse it for limit */
+
+    curr_offset += 3;
+
+    for (j = 0; j < blkwidth; j += 4, in2 += 4)
+    {
+        r13 = 0;
+        p_ref = in2;
+        p_tmp8 = &(tmp_res[0][j]); /* intermediate result */
+        p_tmp8 -= 24;  /* compensate for the first offset */
+        p_cur -= outpitch;  /* compensate for the first offset */
+        tmp = (uint32)(p_ref + pkres); /* limit */
+        while ((uint32)p_ref < tmp)  /* the loop un-rolled  */
+        {
+            /* Read 1 byte at a time is too slow, too many read and pack ops, need to call CreateAlign */
+            /*p_ref8 = p_ref-(inpitch<<1);          r0 = p_ref8[0];         r1 = p_ref8[2];
+            r0 |= (r1<<16);         r6 = p_ref8[1];         r1 = p_ref8[3];
+            r6 |= (r1<<16);         p_ref+=inpitch; */
+            r0 = *((uint32*)(p_ref - (inpitch << 1))); /* load 4 bytes */
+            p_ref += inpitch;
+            r6 = (r0 >> 8) & 0xFF00FF; /* second and fourth byte */
+            r0 &= 0xFF00FF;
+
+            /*p_ref8 = p_ref+(inpitch<<1);
+            r1 = p_ref8[0];         r7 = p_ref8[2];         r1 |= (r7<<16);
+            r7 = p_ref8[1];         r2 = p_ref8[3];         r7 |= (r2<<16);*/
+            r1 = *((uint32*)(p_ref + (inpitch << 1)));  /* r1, r7, ref[3] */
+            r7 = (r1 >> 8) & 0xFF00FF;
+            r1 &= 0xFF00FF;
+
+            r0 += r1;
+            r6 += r7;
+
+            /*r2 = p_ref[0];            r8 = p_ref[2];          r2 |= (r8<<16);
+            r8 = p_ref[1];          r1 = p_ref[3];          r8 |= (r1<<16);*/
+            r2 = *((uint32*)p_ref); /* r2, r8, ref[1] */
+            r8 = (r2 >> 8) & 0xFF00FF;
+            r2 &= 0xFF00FF;
+
+            /*p_ref8 = p_ref-inpitch;           r1 = p_ref8[0];         r7 = p_ref8[2];
+            r1 |= (r7<<16);         r1 += r2;           r7 = p_ref8[1];
+            r2 = p_ref8[3];         r7 |= (r2<<16);*/
+            r1 = *((uint32*)(p_ref - inpitch)); /* r1, r7, ref[0] */
+            r7 = (r1 >> 8) & 0xFF00FF;
+            r1 &= 0xFF00FF;
+            r1 += r2;
+
+            r7 += r8;
+
+            r0 += 20 * r1;
+            r6 += 20 * r7;
+            r0 += 0x100010;
+            r6 += 0x100010;
+
+            /*p_ref8 = p_ref-(inpitch<<1);          r2 = p_ref8[0];         r8 = p_ref8[2];
+            r2 |= (r8<<16);         r8 = p_ref8[1];         r1 = p_ref8[3];         r8 |= (r1<<16);*/
+            r2 = *((uint32*)(p_ref - (inpitch << 1))); /* r2, r8, ref[-1] */
+            r8 = (r2 >> 8) & 0xFF00FF;
+            r2 &= 0xFF00FF;
+
+            /*p_ref8 = p_ref+inpitch;           r1 = p_ref8[0];         r7 = p_ref8[2];
+            r1 |= (r7<<16);         r1 += r2;           r7 = p_ref8[1];
+            r2 = p_ref8[3];         r7 |= (r2<<16);*/
+            r1 = *((uint32*)(p_ref + inpitch)); /* r1, r7, ref[2] */
+            r7 = (r1 >> 8) & 0xFF00FF;
+            r1 &= 0xFF00FF;
+            r1 += r2;
+
+            r7 += r8;
+
+            r0 -= 5 * r1;
+            r6 -= 5 * r7;
+
+            r0 >>= 5;
+            r6 >>= 5;
+            /* clip */
+            r13 |= r6;
+            r13 |= r0;
+            //CLIPPACK(r6,result)
+            /* add with horizontal results */
+            r10 = *((uint32*)(p_tmp8 += 24));
+            r9 = (r10 >> 8) & 0xFF00FF;
+            r10 &= 0xFF00FF;
+
+            r0 += r10;
+            r0 += 0x10001;
+            r0 = (r0 >> 1) & 0xFF00FF;   /* mask to 8 bytes */
+
+            r6 += r9;
+            r6 += 0x10001;
+            r6 = (r6 >> 1) & 0xFF00FF;   /* mask to 8 bytes */
+
+            r0 |= (r6 << 8);  /* pack it back */
+            *((uint32*)(p_cur += outpitch)) = r0;
+        }
+        p_cur += curr_offset; /* offset to the next pixel */
+        if (r13 & 0xFF000700) /* this column need clipping */
+        {
+            p_cur -= 4;
+            for (i = 0; i < 4; i++)
+            {
+                p_ref = in2 + i;
+                p_tmp8 = &(tmp_res[0][j+i]); /* intermediate result */
+                p_tmp8 -= 24;  /* compensate for the first offset */
+                p_cur -= outpitch;  /* compensate for the first offset */
+                tmp = (uint32)(p_ref + pkres); /* limit */
+                while ((uint32)p_ref < tmp)  /* the loop un-rolled  */
+                {
+                    r0 = *(p_ref - (inpitch << 1));
+                    r1 = *(p_ref - inpitch);
+                    r2 = *p_ref;
+                    r3 = *(p_ref += inpitch);  /* modify pointer before loading */
+                    r4 = *(p_ref += inpitch);
+                    /* first pixel */
+                    r5 = *(p_ref += inpitch);
+                    result = (r0 + r5);
+                    r0 = (r1 + r4);
+                    result -= (r0 * 5);//result -= r0;  result -= (r0<<2);
+                    r0 = (r2 + r3);
+                    result += (r0 * 20);//result += (r0<<4);    result += (r0<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    tmp_result = *(p_tmp8 += 24);  /* modify pointer before loading */
+                    result = (result + tmp_result + 1);  /* no clip */
+                    result = (result >> 1);
+                    *(p_cur += outpitch) = result;
+                    /* second pixel */
+                    r0 = *(p_ref += inpitch);
+                    result = (r1 + r0);
+                    r1 = (r2 + r5);
+                    result -= (r1 * 5);//result -= r1;  result -= (r1<<2);
+                    r1 = (r3 + r4);
+                    result += (r1 * 20);//result += (r1<<4);    result += (r1<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    tmp_result = *(p_tmp8 += 24);  /* intermediate result */
+                    result = (result + tmp_result + 1);  /* no clip */
+                    result = (result >> 1);
+                    *(p_cur += outpitch) = result;
+                    /* third pixel */
+                    r1 = *(p_ref += inpitch);
+                    result = (r2 + r1);
+                    r2 = (r3 + r0);
+                    result -= (r2 * 5);//result -= r2;  result -= (r2<<2);
+                    r2 = (r4 + r5);
+                    result += (r2 * 20);//result += (r2<<4);    result += (r2<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    tmp_result = *(p_tmp8 += 24);  /* intermediate result */
+                    result = (result + tmp_result + 1);  /* no clip */
+                    result = (result >> 1);
+                    *(p_cur += outpitch) = result;
+                    /* fourth pixel */
+                    r2 = *(p_ref += inpitch);
+                    result = (r3 + r2);
+                    r3 = (r4 + r1);
+                    result -= (r3 * 5);//result -= r3;  result -= (r3<<2);
+                    r3 = (r5 + r0);
+                    result += (r3 * 20);//result += (r3<<4);    result += (r3<<2);
+                    result = (result + 16) >> 5;
+                    CLIP_RESULT(result)
+                    tmp_result = *(p_tmp8 += 24);  /* intermediate result */
+                    result = (result + tmp_result + 1);  /* no clip */
+                    result = (result >> 1);
+                    *(p_cur += outpitch) = result;
+                    p_ref -= (inpitch << 1);  /* move back to center of the filter of the next one */
+                }
+                p_cur += (curr_offset - 3);
+            }
+        }
+    }
+
+    return ;
+}
+
+/* position G */
+void eFullPelMC(uint8 *in, int inpitch, uint8 *out, int outpitch,
+                int blkwidth, int blkheight)
+{
+    int i, j;
+    int offset_in = inpitch - blkwidth;
+    int offset_out = outpitch - blkwidth;
+    uint32 temp;
+    uint8 byte;
+
+    if (((uint32)in)&3)
+    {
+        for (j = blkheight; j > 0; j--)
+        {
+            for (i = blkwidth; i > 0; i -= 4)
+            {
+                temp = *in++;
+                byte = *in++;
+                temp |= (byte << 8);
+                byte = *in++;
+                temp |= (byte << 16);
+                byte = *in++;
+                temp |= (byte << 24);
+
+                *((uint32*)out) = temp; /* write 4 bytes */
+                out += 4;
+            }
+            out += offset_out;
+            in += offset_in;
+        }
+    }
+    else
+    {
+        for (j = blkheight; j > 0; j--)
+        {
+            for (i = blkwidth; i > 0; i -= 4)
+            {
+                temp = *((uint32*)in);
+                *((uint32*)out) = temp;
+                in += 4;
+                out += 4;
+            }
+            out += offset_out;
+            in += offset_in;
+        }
+    }
+    return ;
+}
+
+void ePadChroma(uint8 *ref, int picwidth, int picheight, int picpitch, int x_pos, int y_pos)
+{
+    int pad_height;
+    int pad_width;
+    uint8 *start;
+    uint32 word1, word2, word3;
+    int offset, j;
+
+
+    pad_height = 8 + ((y_pos & 7) ? 1 : 0);
+    pad_width = 8 + ((x_pos & 7) ? 1 : 0);
+
+    y_pos >>= 3;
+    x_pos >>= 3;
+    // pad vertical first
+    if (y_pos < 0) // need to pad up
+    {
+        if (x_pos < -8) start = ref - 8;
+        else if (x_pos + pad_width > picwidth + 7) start = ref + picwidth + 7 - pad_width;
+        else start = ref + x_pos;
+
+        /* word-align start */
+        offset = (uint32)start & 0x3;
+        if (offset) start -= offset;
+
+        word1 = *((uint32*)start);
+        word2 = *((uint32*)(start + 4));
+        word3 = *((uint32*)(start + 8));
+
+        /* pad up N rows */
+        j = -y_pos;
+        if (j > 8) j = 8;
+        while (j--)
+        {
+            *((uint32*)(start -= picpitch)) = word1;
+            *((uint32*)(start + 4)) = word2;
+            *((uint32*)(start + 8)) = word3;
+        }
+
+    }
+    else if (y_pos + pad_height >= picheight) /* pad down */
+    {
+        if (x_pos < -8) start = ref + picpitch * (picheight - 1) - 8;
+        else if (x_pos + pad_width > picwidth + 7) start = ref + picpitch * (picheight - 1) +
+                    picwidth + 7 - pad_width;
+        else    start = ref + picpitch * (picheight - 1) + x_pos;
+
+        /* word-align start */
+        offset = (uint32)start & 0x3;
+        if (offset) start -= offset;
+
+        word1 = *((uint32*)start);
+        word2 = *((uint32*)(start + 4));
+        word3 = *((uint32*)(start + 8));
+
+        /* pad down N rows */
+        j = y_pos + pad_height - picheight;
+        if (j > 8) j = 8;
+        while (j--)
+        {
+            *((uint32*)(start += picpitch)) = word1;
+            *((uint32*)(start + 4)) = word2;
+            *((uint32*)(start + 8)) = word3;
+        }
+    }
+
+    /* now pad horizontal */
+    if (x_pos < 0) // pad left
+    {
+        if (y_pos < -8) start = ref - (picpitch << 3);
+        else if (y_pos + pad_height > picheight + 7) start = ref + (picheight + 7 - pad_height) * picpitch;
+        else start = ref + y_pos * picpitch;
+
+        // now pad left 8 pixels for pad_height rows */
+        j = pad_height;
+        start -= picpitch;
+        while (j--)
+        {
+            word1 = *(start += picpitch);
+            word1 |= (word1 << 8);
+            word1 |= (word1 << 16);
+            *((uint32*)(start - 8)) = word1;
+            *((uint32*)(start - 4)) = word1;
+        }
+    }
+    else if (x_pos + pad_width >= picwidth) /* pad right */
+    {
+        if (y_pos < -8) start = ref - (picpitch << 3) + picwidth - 1;
+        else if (y_pos + pad_height > picheight + 7) start = ref + (picheight + 7 - pad_height) * picpitch + picwidth - 1;
+        else start = ref + y_pos * picpitch + picwidth - 1;
+
+        // now pad right 8 pixels for pad_height rows */
+        j = pad_height;
+        start -= picpitch;
+        while (j--)
+        {
+            word1 = *(start += picpitch);
+            word1 |= (word1 << 8);
+            word1 |= (word1 << 16);
+            *((uint32*)(start + 1)) = word1;
+            *((uint32*)(start + 5)) = word1;
+        }
+    }
+
+    return ;
+}
+
+
+void eChromaMotionComp(uint8 *ref, int picwidth, int picheight,
+                       int x_pos, int y_pos,
+                       uint8 *pred, int picpitch,
+                       int blkwidth, int blkheight)
+{
+    int dx, dy;
+    int offset_dx, offset_dy;
+    int index;
+
+    ePadChroma(ref, picwidth, picheight, picpitch, x_pos, y_pos);
+
+    dx = x_pos & 7;
+    dy = y_pos & 7;
+    offset_dx = (dx + 7) >> 3;
+    offset_dy = (dy + 7) >> 3;
+    x_pos = x_pos >> 3;  /* round it to full-pel resolution */
+    y_pos = y_pos >> 3;
+
+    ref += y_pos * picpitch + x_pos;
+
+    index = offset_dx + (offset_dy << 1) + ((blkwidth << 1) & 0x7);
+
+    (*(eChromaMC_SIMD[index]))(ref, picpitch , dx, dy, pred, picpitch, blkwidth, blkheight);
+    return ;
+}
+
+
+/* SIMD routines, unroll the loops in vertical direction, decreasing loops (things to be done) */
+void eChromaDiagonalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                            uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    int32 r0, r1, r2, r3, result0, result1;
+    uint8 temp[288];
+    uint8 *ref, *out;
+    int i, j;
+    int dx_8 = 8 - dx;
+    int dy_8 = 8 - dy;
+
+    /* horizontal first */
+    out = temp;
+    for (i = 0; i < blkheight + 1; i++)
+    {
+        ref = pRef;
+        r0 = ref[0];
+        for (j = 0; j < blkwidth; j += 4)
+        {
+            r0 |= (ref[2] << 16);
+            result0 = dx_8 * r0;
+
+            r1 = ref[1] | (ref[3] << 16);
+            result0 += dx * r1;
+            *(int32 *)out = result0;
+
+            result0 = dx_8 * r1;
+
+            r2 = ref[4];
+            r0 = r0 >> 16;
+            r1 = r0 | (r2 << 16);
+            result0 += dx * r1;
+            *(int32 *)(out + 16) = result0;
+
+            ref += 4;
+            out += 4;
+            r0 = r2;
+        }
+        pRef += srcPitch;
+        out += (32 - blkwidth);
+    }
+
+//  pRef -= srcPitch*(blkheight+1);
+    ref = temp;
+
+    for (j = 0; j < blkwidth; j += 4)
+    {
+        r0 = *(int32 *)ref;
+        r1 = *(int32 *)(ref + 16);
+        ref += 32;
+        out = pOut;
+        for (i = 0; i < (blkheight >> 1); i++)
+        {
+            result0 = dy_8 * r0 + 0x00200020;
+            r2 = *(int32 *)ref;
+            result0 += dy * r2;
+            result0 >>= 6;
+            result0 &= 0x00FF00FF;
+            r0 = r2;
+
+            result1 = dy_8 * r1 + 0x00200020;
+            r3 = *(int32 *)(ref + 16);
+            result1 += dy * r3;
+            result1 >>= 6;
+            result1 &= 0x00FF00FF;
+            r1 = r3;
+            *(int32 *)out = result0 | (result1 << 8);
+            out += predPitch;
+            ref += 32;
+
+            result0 = dy_8 * r0 + 0x00200020;
+            r2 = *(int32 *)ref;
+            result0 += dy * r2;
+            result0 >>= 6;
+            result0 &= 0x00FF00FF;
+            r0 = r2;
+
+            result1 = dy_8 * r1 + 0x00200020;
+            r3 = *(int32 *)(ref + 16);
+            result1 += dy * r3;
+            result1 >>= 6;
+            result1 &= 0x00FF00FF;
+            r1 = r3;
+            *(int32 *)out = result0 | (result1 << 8);
+            out += predPitch;
+            ref += 32;
+        }
+        pOut += 4;
+        ref = temp + 4; /* since it can only iterate twice max */
+    }
+    return;
+}
+
+void eChromaHorizontalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                              uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dy);
+
+    int32 r0, r1, r2, result0, result1;
+    uint8 *ref, *out;
+    int i, j;
+    int dx_8 = 8 - dx;
+
+    /* horizontal first */
+    for (i = 0; i < blkheight; i++)
+    {
+        ref = pRef;
+        out = pOut;
+
+        r0 = ref[0];
+        for (j = 0; j < blkwidth; j += 4)
+        {
+            r0 |= (ref[2] << 16);
+            result0 = dx_8 * r0 + 0x00040004;
+
+            r1 = ref[1] | (ref[3] << 16);
+            result0 += dx * r1;
+            result0 >>= 3;
+            result0 &= 0x00FF00FF;
+
+            result1 = dx_8 * r1 + 0x00040004;
+
+            r2 = ref[4];
+            r0 = r0 >> 16;
+            r1 = r0 | (r2 << 16);
+            result1 += dx * r1;
+            result1 >>= 3;
+            result1 &= 0x00FF00FF;
+
+            *(int32 *)out = result0 | (result1 << 8);
+
+            ref += 4;
+            out += 4;
+            r0 = r2;
+        }
+
+        pRef += srcPitch;
+        pOut += predPitch;
+    }
+    return;
+}
+
+void eChromaVerticalMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                            uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dx);
+
+    int32 r0, r1, r2, r3, result0, result1;
+    int i, j;
+    uint8 *ref, *out;
+    int dy_8 = 8 - dy;
+    /* vertical first */
+    for (i = 0; i < blkwidth; i += 4)
+    {
+        ref = pRef;
+        out = pOut;
+
+        r0 = ref[0] | (ref[2] << 16);
+        r1 = ref[1] | (ref[3] << 16);
+        ref += srcPitch;
+        for (j = 0; j < blkheight; j++)
+        {
+            result0 = dy_8 * r0 + 0x00040004;
+            r2 = ref[0] | (ref[2] << 16);
+            result0 += dy * r2;
+            result0 >>= 3;
+            result0 &= 0x00FF00FF;
+            r0 = r2;
+
+            result1 = dy_8 * r1 + 0x00040004;
+            r3 = ref[1] | (ref[3] << 16);
+            result1 += dy * r3;
+            result1 >>= 3;
+            result1 &= 0x00FF00FF;
+            r1 = r3;
+            *(int32 *)out = result0 | (result1 << 8);
+            ref += srcPitch;
+            out += predPitch;
+        }
+        pOut += 4;
+        pRef += 4;
+    }
+    return;
+}
+
+void eChromaDiagonalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                             uint8 *pOut,  int predPitch, int blkwidth, int blkheight)
+{
+    (void)(blkwidth);
+
+    int32 r0, r1, temp0, temp1, result;
+    int32 temp[9];
+    int32 *out;
+    int i, r_temp;
+    int dy_8 = 8 - dy;
+
+    /* horizontal first */
+    out = temp;
+    for (i = 0; i < blkheight + 1; i++)
+    {
+        r_temp = pRef[1];
+        temp0 = (pRef[0] << 3) + dx * (r_temp - pRef[0]);
+        temp1 = (r_temp << 3) + dx * (pRef[2] - r_temp);
+        r0 = temp0 | (temp1 << 16);
+        *out++ = r0;
+        pRef += srcPitch;
+    }
+
+    pRef -= srcPitch * (blkheight + 1);
+
+    out = temp;
+
+    r0 = *out++;
+
+    for (i = 0; i < blkheight; i++)
+    {
+        result = dy_8 * r0 + 0x00200020;
+        r1 = *out++;
+        result += dy * r1;
+        result >>= 6;
+        result &= 0x00FF00FF;
+        *(int16 *)pOut = (result >> 8) | (result & 0xFF);
+        r0 = r1;
+        pOut += predPitch;
+    }
+    return;
+}
+
+void eChromaHorizontalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                               uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dy);
+    (void)(blkwidth);
+
+    int i, temp, temp0, temp1;
+
+    /* horizontal first */
+    for (i = 0; i < blkheight; i++)
+    {
+        temp = pRef[1];
+        temp0 = ((pRef[0] << 3) + dx * (temp - pRef[0]) + 4) >> 3;
+        temp1 = ((temp << 3) + dx * (pRef[2] - temp) + 4) >> 3;
+
+        *(int16 *)pOut = temp0 | (temp1 << 8);
+        pRef += srcPitch;
+        pOut += predPitch;
+
+    }
+    return;
+}
+void eChromaVerticalMC2_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                             uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dx);
+    (void)(blkwidth);
+
+    int32 r0, r1, result;
+    int i;
+    int dy_8 = 8 - dy;
+    r0 = pRef[0] | (pRef[1] << 16);
+    pRef += srcPitch;
+    for (i = 0; i < blkheight; i++)
+    {
+        result = dy_8 * r0 + 0x00040004;
+        r1 = pRef[0] | (pRef[1] << 16);
+        result += dy * r1;
+        result >>= 3;
+        result &= 0x00FF00FF;
+        *(int16 *)pOut = (result >> 8) | (result & 0xFF);
+        r0 = r1;
+        pRef += srcPitch;
+        pOut += predPitch;
+    }
+    return;
+}
+
+void eChromaFullMC_SIMD(uint8 *pRef, int srcPitch, int dx, int dy,
+                        uint8 *pOut, int predPitch, int blkwidth, int blkheight)
+{
+    (void)(dx);
+    (void)(dy);
+
+    int i, j;
+    int offset_in = srcPitch - blkwidth;
+    int offset_out = predPitch - blkwidth;
+    uint16 temp;
+    uint8 byte;
+
+    if (((uint32)pRef)&1)
+    {
+        for (j = blkheight; j > 0; j--)
+        {
+            for (i = blkwidth; i > 0; i -= 2)
+            {
+                temp = *pRef++;
+                byte = *pRef++;
+                temp |= (byte << 8);
+                *((uint16*)pOut) = temp; /* write 2 bytes */
+                pOut += 2;
+            }
+            pOut += offset_out;
+            pRef += offset_in;
+        }
+    }
+    else
+    {
+        for (j = blkheight; j > 0; j--)
+        {
+            for (i = blkwidth; i > 0; i -= 2)
+            {
+                temp = *((uint16*)pRef);
+                *((uint16*)pOut) = temp;
+                pRef += 2;
+                pOut += 2;
+            }
+            pOut += offset_out;
+            pRef += offset_in;
+        }
+    }
+    return ;
+}
diff --git a/media/libstagefright/codecs/avc/enc/src/motion_est.cpp b/media/libstagefright/codecs/avc/enc/src/motion_est.cpp
new file mode 100644
index 0000000..f650ef9
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/motion_est.cpp
@@ -0,0 +1,1774 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+
+#define MIN_GOP     1   /* minimum size of GOP, 1/23/01, need to be tested */
+
+#define DEFAULT_REF_IDX     0  /* always from the first frame in the reflist */
+
+#define ALL_CAND_EQUAL  10  /*  any number greater than 5 will work */
+
+
+/* from TMN 3.2 */
+#define PREF_NULL_VEC 129   /* zero vector bias */
+#define PREF_16_VEC 129     /* 1MV bias versus 4MVs*/
+#define PREF_INTRA  3024//512       /* bias for INTRA coding */
+
+const static int tab_exclude[9][9] =  // [last_loc][curr_loc]
+{
+    {0, 0, 0, 0, 0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 1, 1, 1, 0, 0},
+    {0, 0, 0, 0, 1, 1, 1, 1, 1},
+    {0, 0, 0, 0, 0, 0, 1, 1, 1},
+    {0, 1, 1, 0, 0, 0, 1, 1, 1},
+    {0, 1, 1, 0, 0, 0, 0, 0, 1},
+    {0, 1, 1, 1, 1, 0, 0, 0, 1},
+    {0, 0, 1, 1, 1, 0, 0, 0, 0},
+    {0, 0, 1, 1, 1, 1, 1, 0, 0}
+}; //to decide whether to continue or compute
+
+const static int refine_next[8][2] =    /* [curr_k][increment] */
+{
+    {0, 0}, {2, 0}, {1, 1}, {0, 2}, { -1, 1}, { -2, 0}, { -1, -1}, {0, -2}
+};
+
+#ifdef _SAD_STAT
+uint32 num_MB = 0;
+uint32 num_cand = 0;
+#endif
+
+/************************************************************************/
+#define TH_INTER_2  100  /* temporary for now */
+
+//#define FIXED_INTERPRED_MODE  AVC_P16
+#define FIXED_REF_IDX   0
+#define FIXED_MVX 0
+#define FIXED_MVY 0
+
+// only use when AVC_P8 or AVC_P8ref0
+#define FIXED_SUBMB_MODE    AVC_4x4
+/*************************************************************************/
+
+/* Initialize arrays necessary for motion search */
+AVCEnc_Status InitMotionSearchModule(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    int search_range = rateCtrl->mvRange;
+    int number_of_subpel_positions = 4 * (2 * search_range + 3);
+    int max_mv_bits, max_mvd;
+    int temp_bits = 0;
+    uint8 *mvbits;
+    int bits, imax, imin, i;
+    uint8* subpel_pred = (uint8*) encvid->subpel_pred; // all 16 sub-pel positions
+
+
+    while (number_of_subpel_positions > 0)
+    {
+        temp_bits++;
+        number_of_subpel_positions >>= 1;
+    }
+
+    max_mv_bits = 3 + 2 * temp_bits;
+    max_mvd  = (1 << (max_mv_bits >> 1)) - 1;
+
+    encvid->mvbits_array = (uint8*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
+                           sizeof(uint8) * (2 * max_mvd + 1), DEFAULT_ATTR);
+
+    if (encvid->mvbits_array == NULL)
+    {
+        return AVCENC_MEMORY_FAIL;
+    }
+
+    mvbits = encvid->mvbits  = encvid->mvbits_array + max_mvd;
+
+    mvbits[0] = 1;
+    for (bits = 3; bits <= max_mv_bits; bits += 2)
+    {
+        imax = 1    << (bits >> 1);
+        imin = imax >> 1;
+
+        for (i = imin; i < imax; i++)   mvbits[-i] = mvbits[i] = bits;
+    }
+
+    /* initialize half-pel search */
+    encvid->hpel_cand[0] = subpel_pred + REF_CENTER;
+    encvid->hpel_cand[1] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1 ;
+    encvid->hpel_cand[2] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->hpel_cand[3] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->hpel_cand[4] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->hpel_cand[5] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->hpel_cand[6] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->hpel_cand[7] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->hpel_cand[8] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+
+    /* For quarter-pel interpolation around best half-pel result */
+
+    encvid->bilin_base[0][0] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[0][1] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[0][2] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[0][3] = subpel_pred + REF_CENTER;
+
+
+    encvid->bilin_base[1][0] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[1][1] = subpel_pred + REF_CENTER - 24;
+    encvid->bilin_base[1][2] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[1][3] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1;
+
+    encvid->bilin_base[2][0] = subpel_pred + REF_CENTER - 24;
+    encvid->bilin_base[2][1] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[2][2] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[2][3] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 1;
+
+    encvid->bilin_base[3][0] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[3][1] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 1;
+    encvid->bilin_base[3][2] = subpel_pred + REF_CENTER;
+    encvid->bilin_base[3][3] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+
+    encvid->bilin_base[4][0] = subpel_pred + REF_CENTER;
+    encvid->bilin_base[4][1] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->bilin_base[4][2] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 25;
+    encvid->bilin_base[4][3] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 25;
+
+    encvid->bilin_base[5][0] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[5][1] = subpel_pred + REF_CENTER;
+    encvid->bilin_base[5][2] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[5][3] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 25;
+
+    encvid->bilin_base[6][0] = subpel_pred + REF_CENTER - 1;
+    encvid->bilin_base[6][1] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[6][2] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE + 24;
+    encvid->bilin_base[6][3] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+
+    encvid->bilin_base[7][0] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[7][1] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[7][2] = subpel_pred + REF_CENTER - 1;
+    encvid->bilin_base[7][3] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE + 24;
+
+    encvid->bilin_base[8][0] = subpel_pred + REF_CENTER - 25;
+    encvid->bilin_base[8][1] = subpel_pred + V0Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[8][2] = subpel_pred + V2Q_H0Q * SUBPEL_PRED_BLK_SIZE;
+    encvid->bilin_base[8][3] = subpel_pred + V2Q_H2Q * SUBPEL_PRED_BLK_SIZE;
+
+
+    return AVCENC_SUCCESS;
+}
+
+/* Clean-up memory */
+void CleanMotionSearchModule(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+
+    if (encvid->mvbits_array)
+    {
+        avcHandle->CBAVC_Free(avcHandle->userData, (int)(encvid->mvbits_array));
+        encvid->mvbits = NULL;
+    }
+
+    return ;
+}
+
+
+bool IntraDecisionABE(int *min_cost, uint8 *cur, int pitch, bool ave)
+{
+    int j;
+    uint8 *out;
+    int temp, SBE;
+    OsclFloat ABE;
+    bool intra = true;
+
+    SBE = 0;
+    /* top neighbor */
+    out = cur - pitch;
+    for (j = 0; j < 16; j++)
+    {
+        temp = out[j] - cur[j];
+        SBE += ((temp >= 0) ? temp : -temp);
+    }
+
+    /* left neighbor */
+    out = cur - 1;
+    out -= pitch;
+    cur -= pitch;
+    for (j = 0; j < 16; j++)
+    {
+        temp = *(out += pitch) - *(cur += pitch);
+        SBE += ((temp >= 0) ? temp : -temp);
+    }
+
+    /* compare mincost/384 and SBE/64 */
+    ABE = SBE / 32.0; //ABE = SBE/64.0; //
+    if (ABE >= *min_cost / 256.0) //if( ABE*0.8 >= min_cost/384.0) //
+    {
+        intra = false; // no possibility of intra, just use inter
+    }
+    else
+    {
+        if (ave == true)
+        {
+            *min_cost = (*min_cost + (int)(SBE * 8)) >> 1; // possibility of intra, averaging the cost
+        }
+        else
+        {
+            *min_cost = (int)(SBE * 8);
+        }
+    }
+
+    return intra;
+}
+
+/******* main function for macroblock prediction for the entire frame ***/
+/* if turns out to be IDR frame, set video->nal_unit_type to AVC_NALTYPE_IDR */
+void AVCMotionEstimation(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    int slice_type = video->slice_type;
+    AVCFrameIO *currInput = encvid->currInput;
+    AVCPictureData *refPic = video->RefPicList0[0];
+    int i, j, k;
+    int mbwidth = video->PicWidthInMbs;
+    int mbheight = video->PicHeightInMbs;
+    int totalMB = video->PicSizeInMbs;
+    int pitch = currInput->pitch;
+    AVCMacroblock *currMB, *mblock = video->mblock;
+    AVCMV *mot_mb_16x16, *mot16x16 = encvid->mot16x16;
+    // AVCMV *mot_mb_16x8, *mot_mb_8x16, *mot_mb_8x8, etc;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    uint8 *intraSearch = encvid->intraSearch;
+    uint FS_en = encvid->fullsearch_enable;
+
+    int NumIntraSearch, start_i, numLoop, incr_i;
+    int mbnum, offset;
+    uint8 *cur, *best_cand[5];
+    int totalSAD = 0;   /* average SAD for rate control */
+    int type_pred;
+    int abe_cost;
+
+#ifdef HTFM
+    /***** HYPOTHESIS TESTING ********/  /* 2/28/01 */
+    int collect = 0;
+    HTFM_Stat htfm_stat;
+    double newvar[16];
+    double exp_lamda[15];
+    /*********************************/
+#endif
+    int hp_guess = 0;
+    uint32 mv_uint32;
+
+    offset = 0;
+
+    if (slice_type == AVC_I_SLICE)
+    {
+        /* cannot do I16 prediction here because it needs full decoding. */
+        for (i = 0; i < totalMB; i++)
+        {
+            encvid->min_cost[i] = 0x7FFFFFFF;  /* max value for int */
+        }
+
+        memset(intraSearch, 1, sizeof(uint8)*totalMB);
+
+        encvid->firstIntraRefreshMBIndx = 0; /* reset this */
+
+        return ;
+    }
+    else   // P_SLICE
+    {
+        for (i = 0; i < totalMB; i++)
+        {
+            mblock[i].mb_intra = 0;
+        }
+        memset(intraSearch, 1, sizeof(uint8)*totalMB);
+    }
+
+    if (refPic->padded == 0)
+    {
+        AVCPaddingEdge(refPic);
+        refPic->padded = 1;
+    }
+    /* Random INTRA update */
+    if (rateCtrl->intraMBRate)
+    {
+        AVCRasterIntraUpdate(encvid, mblock, totalMB, rateCtrl->intraMBRate);
+    }
+
+    encvid->sad_extra_info = NULL;
+#ifdef HTFM
+    /***** HYPOTHESIS TESTING ********/
+    InitHTFM(video, &htfm_stat, newvar, &collect);
+    /*********************************/
+#endif
+
+    if ((rateCtrl->scdEnable == 1)
+            && ((rateCtrl->frame_rate < 5.0) || (video->sliceHdr->frame_num > MIN_GOP)))
+        /* do not try to detect a new scene if low frame rate and too close to previous I-frame */
+    {
+        incr_i = 2;
+        numLoop = 2;
+        start_i = 1;
+        type_pred = 0; /* for initial candidate selection */
+    }
+    else
+    {
+        incr_i = 1;
+        numLoop = 1;
+        start_i = 0;
+        type_pred = 2;
+    }
+
+    /* First pass, loop thru half the macroblock */
+    /* determine scene change */
+    /* Second pass, for the rest of macroblocks */
+    NumIntraSearch = 0; // to be intra searched in the encoding loop.
+    while (numLoop--)
+    {
+        for (j = 0; j < mbheight; j++)
+        {
+            if (incr_i > 1)
+                start_i = (start_i == 0 ? 1 : 0) ; /* toggle 0 and 1 */
+
+            offset = pitch * (j << 4) + (start_i << 4);
+
+            mbnum = j * mbwidth + start_i;
+
+            for (i = start_i; i < mbwidth; i += incr_i)
+            {
+                video->mbNum = mbnum;
+                video->currMB = currMB = mblock + mbnum;
+                mot_mb_16x16 = mot16x16 + mbnum;
+
+                cur = currInput->YCbCr[0] + offset;
+
+                if (currMB->mb_intra == 0) /* for INTER mode */
+                {
+#if defined(HTFM)
+                    HTFMPrepareCurMB_AVC(encvid, &htfm_stat, cur, pitch);
+#else
+                    AVCPrepareCurMB(encvid, cur, pitch);
+#endif
+                    /************************************************************/
+                    /******** full-pel 1MV search **********************/
+
+                    AVCMBMotionSearch(encvid, cur, best_cand, i << 4, j << 4, type_pred,
+                                      FS_en, &hp_guess);
+
+                    abe_cost = encvid->min_cost[mbnum] = mot_mb_16x16->sad;
+
+                    /* set mbMode and MVs */
+                    currMB->mbMode = AVC_P16;
+                    currMB->MBPartPredMode[0][0] = AVC_Pred_L0;
+                    mv_uint32 = ((mot_mb_16x16->y) << 16) | ((mot_mb_16x16->x) & 0xffff);
+                    for (k = 0; k < 32; k += 2)
+                    {
+                        currMB->mvL0[k>>1] = mv_uint32;
+                    }
+
+                    /* make a decision whether it should be tested for intra or not */
+                    if (i != mbwidth - 1 && j != mbheight - 1 && i != 0 && j != 0)
+                    {
+                        if (false == IntraDecisionABE(&abe_cost, cur, pitch, true))
+                        {
+                            intraSearch[mbnum] = 0;
+                        }
+                        else
+                        {
+                            NumIntraSearch++;
+                            rateCtrl->MADofMB[mbnum] = abe_cost;
+                        }
+                    }
+                    else // boundary MBs, always do intra search
+                    {
+                        NumIntraSearch++;
+                    }
+
+                    totalSAD += (int) rateCtrl->MADofMB[mbnum];//mot_mb_16x16->sad;
+                }
+                else    /* INTRA update, use for prediction */
+                {
+                    mot_mb_16x16[0].x = mot_mb_16x16[0].y = 0;
+
+                    /* reset all other MVs to zero */
+                    /* mot_mb_16x8, mot_mb_8x16, mot_mb_8x8, etc. */
+                    abe_cost = encvid->min_cost[mbnum] = 0x7FFFFFFF;  /* max value for int */
+
+                    if (i != mbwidth - 1 && j != mbheight - 1 && i != 0 && j != 0)
+                    {
+                        IntraDecisionABE(&abe_cost, cur, pitch, false);
+
+                        rateCtrl->MADofMB[mbnum] = abe_cost;
+                        totalSAD += abe_cost;
+                    }
+
+                    NumIntraSearch++ ;
+                    /* cannot do I16 prediction here because it needs full decoding. */
+                    // intraSearch[mbnum] = 1;
+
+                }
+
+                mbnum += incr_i;
+                offset += (incr_i << 4);
+
+            } /* for i */
+        } /* for j */
+
+        /* since we cannot do intra/inter decision here, the SCD has to be
+        based on other criteria such as motion vectors coherency or the SAD */
+        if (incr_i > 1 && numLoop) /* scene change on and first loop */
+        {
+            //if(NumIntraSearch > ((totalMB>>3)<<1) + (totalMB>>3)) /* 75% of 50%MBs */
+            if (NumIntraSearch*99 > (48*totalMB)) /* 20% of 50%MBs */
+                /* need to do more investigation about this threshold since the NumIntraSearch
+                only show potential intra MBs, not the actual one */
+            {
+                /* we can choose to just encode I_SLICE without IDR */
+                //video->nal_unit_type = AVC_NALTYPE_IDR;
+                video->nal_unit_type = AVC_NALTYPE_SLICE;
+                video->sliceHdr->slice_type = AVC_I_ALL_SLICE;
+                video->slice_type = AVC_I_SLICE;
+                memset(intraSearch, 1, sizeof(uint8)*totalMB);
+                i = totalMB;
+                while (i--)
+                {
+                    mblock[i].mb_intra = 1;
+                    encvid->min_cost[i] = 0x7FFFFFFF;  /* max value for int */
+                }
+
+                rateCtrl->totalSAD = totalSAD * 2;  /* SAD */
+
+                return ;
+            }
+        }
+        /******** no scene change, continue motion search **********************/
+        start_i = 0;
+        type_pred++; /* second pass */
+    }
+
+    rateCtrl->totalSAD = totalSAD;  /* SAD */
+
+#ifdef HTFM
+    /***** HYPOTHESIS TESTING ********/
+    if (collect)
+    {
+        collect = 0;
+        UpdateHTFM(encvid, newvar, exp_lamda, &htfm_stat);
+    }
+    /*********************************/
+#endif
+
+    return ;
+}
+
+/*=====================================================================
+    Function:   PaddingEdge
+    Date:       09/16/2000
+    Purpose:    Pad edge of a Vop
+=====================================================================*/
+
+void  AVCPaddingEdge(AVCPictureData *refPic)
+{
+    uint8 *src, *dst;
+    int i;
+    int pitch, width, height;
+    uint32 temp1, temp2;
+
+    width = refPic->width;
+    height = refPic->height;
+    pitch = refPic->pitch;
+
+    /* pad top */
+    src = refPic->Sl;
+
+    temp1 = *src; /* top-left corner */
+    temp2 = src[width-1]; /* top-right corner */
+    temp1 |= (temp1 << 8);
+    temp1 |= (temp1 << 16);
+    temp2 |= (temp2 << 8);
+    temp2 |= (temp2 << 16);
+
+    dst = src - (pitch << 4);
+
+    *((uint32*)(dst - 16)) = temp1;
+    *((uint32*)(dst - 12)) = temp1;
+    *((uint32*)(dst - 8)) = temp1;
+    *((uint32*)(dst - 4)) = temp1;
+
+    memcpy(dst, src, width);
+
+    *((uint32*)(dst += width)) = temp2;
+    *((uint32*)(dst + 4)) = temp2;
+    *((uint32*)(dst + 8)) = temp2;
+    *((uint32*)(dst + 12)) = temp2;
+
+    dst = dst - width - 16;
+
+    i = 15;
+    while (i--)
+    {
+        memcpy(dst + pitch, dst, pitch);
+        dst += pitch;
+    }
+
+    /* pad sides */
+    dst += (pitch + 16);
+    src = dst;
+    i = height;
+    while (i--)
+    {
+        temp1 = *src;
+        temp2 = src[width-1];
+        temp1 |= (temp1 << 8);
+        temp1 |= (temp1 << 16);
+        temp2 |= (temp2 << 8);
+        temp2 |= (temp2 << 16);
+
+        *((uint32*)(dst - 16)) = temp1;
+        *((uint32*)(dst - 12)) = temp1;
+        *((uint32*)(dst - 8)) = temp1;
+        *((uint32*)(dst - 4)) = temp1;
+
+        *((uint32*)(dst += width)) = temp2;
+        *((uint32*)(dst + 4)) = temp2;
+        *((uint32*)(dst + 8)) = temp2;
+        *((uint32*)(dst + 12)) = temp2;
+
+        src += pitch;
+        dst = src;
+    }
+
+    /* pad bottom */
+    dst -= 16;
+    i = 16;
+    while (i--)
+    {
+        memcpy(dst, dst - pitch, pitch);
+        dst += pitch;
+    }
+
+
+    return ;
+}
+
+/*===========================================================================
+    Function:   AVCRasterIntraUpdate
+    Date:       2/26/01
+    Purpose:    To raster-scan assign INTRA-update .
+                N macroblocks are updated (also was programmable).
+===========================================================================*/
+void AVCRasterIntraUpdate(AVCEncObject *encvid, AVCMacroblock *mblock, int totalMB, int numRefresh)
+{
+    int indx, i;
+
+    indx = encvid->firstIntraRefreshMBIndx;
+    for (i = 0; i < numRefresh && indx < totalMB; i++)
+    {
+        (mblock + indx)->mb_intra = 1;
+        encvid->intraSearch[indx++] = 1;
+    }
+
+    /* if read the end of frame, reset and loop around */
+    if (indx >= totalMB - 1)
+    {
+        indx = 0;
+        while (i < numRefresh && indx < totalMB)
+        {
+            (mblock + indx)->mb_intra = 1;
+            encvid->intraSearch[indx++] = 1;
+            i++;
+        }
+    }
+
+    encvid->firstIntraRefreshMBIndx = indx; /* update with a new value */
+
+    return ;
+}
+
+
+#ifdef HTFM
+void InitHTFM(VideoEncData *encvid, HTFM_Stat *htfm_stat, double *newvar, int *collect)
+{
+    AVCCommonObj *video = encvid->common;
+    int i;
+    int lx = video->currPic->width; // padding
+    int lx2 = lx << 1;
+    int lx3 = lx2 + lx;
+    int rx = video->currPic->pitch;
+    int rx2 = rx << 1;
+    int rx3 = rx2 + rx;
+
+    int *offset, *offset2;
+
+    /* 4/11/01, collect data every 30 frames, doesn't have to be base layer */
+    if (((int)video->sliceHdr->frame_num) % 30 == 1)
+    {
+
+        *collect = 1;
+
+        htfm_stat->countbreak = 0;
+        htfm_stat->abs_dif_mad_avg = 0;
+
+        for (i = 0; i < 16; i++)
+        {
+            newvar[i] = 0.0;
+        }
+//      encvid->functionPointer->SAD_MB_PADDING = &SAD_MB_PADDING_HTFM_Collect;
+        encvid->functionPointer->SAD_Macroblock = &SAD_MB_HTFM_Collect;
+        encvid->functionPointer->SAD_MB_HalfPel[0] = NULL;
+        encvid->functionPointer->SAD_MB_HalfPel[1] = &SAD_MB_HP_HTFM_Collectxh;
+        encvid->functionPointer->SAD_MB_HalfPel[2] = &SAD_MB_HP_HTFM_Collectyh;
+        encvid->functionPointer->SAD_MB_HalfPel[3] = &SAD_MB_HP_HTFM_Collectxhyh;
+        encvid->sad_extra_info = (void*)(htfm_stat);
+        offset = htfm_stat->offsetArray;
+        offset2 = htfm_stat->offsetRef;
+    }
+    else
+    {
+//      encvid->functionPointer->SAD_MB_PADDING = &SAD_MB_PADDING_HTFM;
+        encvid->functionPointer->SAD_Macroblock = &SAD_MB_HTFM;
+        encvid->functionPointer->SAD_MB_HalfPel[0] = NULL;
+        encvid->functionPointer->SAD_MB_HalfPel[1] = &SAD_MB_HP_HTFMxh;
+        encvid->functionPointer->SAD_MB_HalfPel[2] = &SAD_MB_HP_HTFMyh;
+        encvid->functionPointer->SAD_MB_HalfPel[3] = &SAD_MB_HP_HTFMxhyh;
+        encvid->sad_extra_info = (void*)(encvid->nrmlz_th);
+        offset = encvid->nrmlz_th + 16;
+        offset2 = encvid->nrmlz_th + 32;
+    }
+
+    offset[0] = 0;
+    offset[1] = lx2 + 2;
+    offset[2] = 2;
+    offset[3] = lx2;
+    offset[4] = lx + 1;
+    offset[5] = lx3 + 3;
+    offset[6] = lx + 3;
+    offset[7] = lx3 + 1;
+    offset[8] = lx;
+    offset[9] = lx3 + 2;
+    offset[10] = lx3 ;
+    offset[11] = lx + 2 ;
+    offset[12] = 1;
+    offset[13] = lx2 + 3;
+    offset[14] = lx2 + 1;
+    offset[15] = 3;
+
+    offset2[0] = 0;
+    offset2[1] = rx2 + 2;
+    offset2[2] = 2;
+    offset2[3] = rx2;
+    offset2[4] = rx + 1;
+    offset2[5] = rx3 + 3;
+    offset2[6] = rx + 3;
+    offset2[7] = rx3 + 1;
+    offset2[8] = rx;
+    offset2[9] = rx3 + 2;
+    offset2[10] = rx3 ;
+    offset2[11] = rx + 2 ;
+    offset2[12] = 1;
+    offset2[13] = rx2 + 3;
+    offset2[14] = rx2 + 1;
+    offset2[15] = 3;
+
+    return ;
+}
+
+void UpdateHTFM(AVCEncObject *encvid, double *newvar, double *exp_lamda, HTFM_Stat *htfm_stat)
+{
+    if (htfm_stat->countbreak == 0)
+        htfm_stat->countbreak = 1;
+
+    newvar[0] = (double)(htfm_stat->abs_dif_mad_avg) / (htfm_stat->countbreak * 16.);
+
+    if (newvar[0] < 0.001)
+    {
+        newvar[0] = 0.001; /* to prevent floating overflow */
+    }
+    exp_lamda[0] =  1 / (newvar[0] * 1.4142136);
+    exp_lamda[1] = exp_lamda[0] * 1.5825;
+    exp_lamda[2] = exp_lamda[0] * 2.1750;
+    exp_lamda[3] = exp_lamda[0] * 3.5065;
+    exp_lamda[4] = exp_lamda[0] * 3.1436;
+    exp_lamda[5] = exp_lamda[0] * 3.5315;
+    exp_lamda[6] = exp_lamda[0] * 3.7449;
+    exp_lamda[7] = exp_lamda[0] * 4.5854;
+    exp_lamda[8] = exp_lamda[0] * 4.6191;
+    exp_lamda[9] = exp_lamda[0] * 5.4041;
+    exp_lamda[10] = exp_lamda[0] * 6.5974;
+    exp_lamda[11] = exp_lamda[0] * 10.5341;
+    exp_lamda[12] = exp_lamda[0] * 10.0719;
+    exp_lamda[13] = exp_lamda[0] * 12.0516;
+    exp_lamda[14] = exp_lamda[0] * 15.4552;
+
+    CalcThreshold(HTFM_Pf, exp_lamda, encvid->nrmlz_th);
+    return ;
+}
+
+
+void CalcThreshold(double pf, double exp_lamda[], int nrmlz_th[])
+{
+    int i;
+    double temp[15];
+    //  printf("\nLamda: ");
+
+    /* parametric PREMODELling */
+    for (i = 0; i < 15; i++)
+    {
+        //    printf("%g ",exp_lamda[i]);
+        if (pf < 0.5)
+            temp[i] = 1 / exp_lamda[i] * M4VENC_LOG(2 * pf);
+        else
+            temp[i] = -1 / exp_lamda[i] * M4VENC_LOG(2 * (1 - pf));
+    }
+
+    nrmlz_th[15] = 0;
+    for (i = 0; i < 15; i++)        /* scale upto no.pixels */
+        nrmlz_th[i] = (int)(temp[i] * ((i + 1) << 4) + 0.5);
+
+    return ;
+}
+
+void    HTFMPrepareCurMB_AVC(AVCEncObject *encvid, HTFM_Stat *htfm_stat, uint8 *cur, int pitch)
+{
+    AVCCommonObj *video = encvid->common;
+    uint32 *htfmMB = (uint32*)(encvid->currYMB);
+    uint8 *ptr, byte;
+    int *offset;
+    int i;
+    uint32 word;
+
+    if (((int)video->sliceHdr->frame_num) % 30 == 1)
+    {
+        offset = htfm_stat->offsetArray;
+    }
+    else
+    {
+        offset = encvid->nrmlz_th + 16;
+    }
+
+    for (i = 0; i < 16; i++)
+    {
+        ptr = cur + offset[i];
+        word = ptr[0];
+        byte = ptr[4];
+        word |= (byte << 8);
+        byte = ptr[8];
+        word |= (byte << 16);
+        byte = ptr[12];
+        word |= (byte << 24);
+        *htfmMB++ = word;
+
+        word = *(ptr += (pitch << 2));
+        byte = ptr[4];
+        word |= (byte << 8);
+        byte = ptr[8];
+        word |= (byte << 16);
+        byte = ptr[12];
+        word |= (byte << 24);
+        *htfmMB++ = word;
+
+        word = *(ptr += (pitch << 2));
+        byte = ptr[4];
+        word |= (byte << 8);
+        byte = ptr[8];
+        word |= (byte << 16);
+        byte = ptr[12];
+        word |= (byte << 24);
+        *htfmMB++ = word;
+
+        word = *(ptr += (pitch << 2));
+        byte = ptr[4];
+        word |= (byte << 8);
+        byte = ptr[8];
+        word |= (byte << 16);
+        byte = ptr[12];
+        word |= (byte << 24);
+        *htfmMB++ = word;
+    }
+
+    return ;
+}
+
+
+#endif // HTFM
+
+void    AVCPrepareCurMB(AVCEncObject *encvid, uint8 *cur, int pitch)
+{
+    void* tmp = (void*)(encvid->currYMB);
+    uint32 *currYMB = (uint32*) tmp;
+    int i;
+
+    cur -= pitch;
+
+    for (i = 0; i < 16; i++)
+    {
+        *currYMB++ = *((uint32*)(cur += pitch));
+        *currYMB++ = *((uint32*)(cur + 4));
+        *currYMB++ = *((uint32*)(cur + 8));
+        *currYMB++ = *((uint32*)(cur + 12));
+    }
+
+    return ;
+}
+
+#ifdef FIXED_INTERPRED_MODE
+
+/* due to the complexity of the predicted motion vector, we may not decide to skip
+a macroblock here just yet. */
+/* We will find the best motion vector and the best intra prediction mode for each block. */
+/* output are
+    currMB->NumMbPart,  currMB->MbPartWidth, currMB->MbPartHeight,
+    currMB->NumSubMbPart[], currMB->SubMbPartWidth[], currMB->SubMbPartHeight,
+    currMB->MBPartPredMode[][] (L0 or L1 or BiPred)
+    currMB->RefIdx[], currMB->ref_idx_L0[],
+    currMB->mvL0[], currMB->mvL1[]
+    */
+
+AVCEnc_Status AVCMBMotionSearch(AVCEncObject *encvid, AVCMacroblock *currMB, int mbNum,
+                                int num_pass)
+{
+    AVCCommonObj *video = encvid->common;
+    int mbPartIdx, subMbPartIdx;
+    int16 *mv;
+    int i;
+    int SubMbPartHeight, SubMbPartWidth, NumSubMbPart;
+
+    /* assign value to currMB->MBPartPredMode[][x],subMbMode[],NumSubMbPart[],SubMbPartWidth[],SubMbPartHeight[] */
+
+    currMB->mbMode = FIXED_INTERPRED_MODE;
+    currMB->mb_intra = 0;
+
+    if (currMB->mbMode == AVC_P16)
+    {
+        currMB->NumMbPart = 1;
+        currMB->MbPartWidth = 16;
+        currMB->MbPartHeight = 16;
+        currMB->SubMbPartHeight[0] = 16;
+        currMB->SubMbPartWidth[0] = 16;
+        currMB->NumSubMbPart[0] =  1;
+    }
+    else if (currMB->mbMode == AVC_P16x8)
+    {
+        currMB->NumMbPart = 2;
+        currMB->MbPartWidth = 16;
+        currMB->MbPartHeight = 8;
+        for (i = 0; i < 2; i++)
+        {
+            currMB->SubMbPartWidth[i] = 16;
+            currMB->SubMbPartHeight[i] = 8;
+            currMB->NumSubMbPart[i] = 1;
+        }
+    }
+    else if (currMB->mbMode == AVC_P8x16)
+    {
+        currMB->NumMbPart = 2;
+        currMB->MbPartWidth = 8;
+        currMB->MbPartHeight = 16;
+        for (i = 0; i < 2; i++)
+        {
+            currMB->SubMbPartWidth[i] = 8;
+            currMB->SubMbPartHeight[i] = 16;
+            currMB->NumSubMbPart[i] = 1;
+        }
+    }
+    else if (currMB->mbMode == AVC_P8 || currMB->mbMode == AVC_P8ref0)
+    {
+        currMB->NumMbPart = 4;
+        currMB->MbPartWidth = 8;
+        currMB->MbPartHeight = 8;
+        if (FIXED_SUBMB_MODE == AVC_8x8)
+        {
+            SubMbPartHeight = 8;
+            SubMbPartWidth = 8;
+            NumSubMbPart = 1;
+        }
+        else if (FIXED_SUBMB_MODE == AVC_8x4)
+        {
+            SubMbPartHeight = 4;
+            SubMbPartWidth = 8;
+            NumSubMbPart = 2;
+        }
+        else if (FIXED_SUBMB_MODE == AVC_4x8)
+        {
+            SubMbPartHeight = 8;
+            SubMbPartWidth = 4;
+            NumSubMbPart = 2;
+        }
+        else if (FIXED_SUBMB_MODE == AVC_4x4)
+        {
+            SubMbPartHeight = 4;
+            SubMbPartWidth = 4;
+            NumSubMbPart = 4;
+        }
+
+        for (i = 0; i < 4; i++)
+        {
+            currMB->subMbMode[i] = FIXED_SUBMB_MODE;
+            currMB->SubMbPartHeight[i] = SubMbPartHeight;
+            currMB->SubMbPartWidth[i] = SubMbPartWidth;
+            currMB->NumSubMbPart[i] = NumSubMbPart;
+        }
+    }
+    else /* it's probably intra mode */
+    {
+        return AVCENC_SUCCESS;
+    }
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        currMB->MBPartPredMode[mbPartIdx][0]  = AVC_Pred_L0;
+        currMB->ref_idx_L0[mbPartIdx] = FIXED_REF_IDX;
+        currMB->RefIdx[mbPartIdx] = video->RefPicList0[FIXED_REF_IDX]->RefIdx;
+
+        for (subMbPartIdx = 0; subMbPartIdx < 4; subMbPartIdx++)
+        {
+            mv = (int16*)(currMB->mvL0 + (mbPartIdx << 2) + subMbPartIdx);
+
+            *mv++ = FIXED_MVX;
+            *mv = FIXED_MVY;
+        }
+    }
+
+    encvid->min_cost = 0;
+
+    return AVCENC_SUCCESS;
+}
+
+#else /* perform the search */
+
+/* This option #1 search is very similar to PV's MPEG4 motion search algorithm.
+  The search is done in hierarchical manner from 16x16 MB down to smaller and smaller
+  partition. At each level, a decision can be made to stop the search if the expected
+  prediction gain is not worth the computation. The decision can also be made at the finest
+  level for more fullsearch-like behavior with the price of heavier computation. */
+void AVCMBMotionSearch(AVCEncObject *encvid, uint8 *cur, uint8 *best_cand[],
+                       int i0, int j0, int type_pred, int FS_en, int *hp_guess)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCPictureData *currPic = video->currPic;
+    AVCSeqParamSet *currSPS = video->currSeqParams;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCMacroblock *currMB = video->currMB;
+    uint8 *ref, *cand, *ncand;
+    void *extra_info = encvid->sad_extra_info;
+    int mbnum = video->mbNum;
+    int width = currPic->width; /* 6/12/01, must be multiple of 16 */
+    int height = currPic->height;
+    AVCMV *mot16x16 = encvid->mot16x16;
+    int (*SAD_Macroblock)(uint8*, uint8*, int, void*) = encvid->functionPointer->SAD_Macroblock;
+
+    int range = rateCtrl->mvRange;
+
+    int lx = currPic->pitch; /*  padding */
+    int i, j, imin, jmin, ilow, ihigh, jlow, jhigh;
+    int d, dmin, dn[9];
+    int k;
+    int mvx[5], mvy[5];
+    int num_can, center_again;
+    int last_loc, new_loc = 0;
+    int step, max_step = range >> 1;
+    int next;
+
+    int cmvx, cmvy; /* estimated predicted MV */
+    int lev_idx;
+    int lambda_motion = encvid->lambda_motion;
+    uint8 *mvbits = encvid->mvbits;
+    int mvshift = 2;
+    int mvcost;
+
+    int min_sad = 65535;
+
+    ref = video->RefPicList0[DEFAULT_REF_IDX]->Sl; /* origin of actual frame */
+
+    /* have to initialize these params, necessary for interprediction part */
+    currMB->NumMbPart = 1;
+    currMB->SubMbPartHeight[0] = 16;
+    currMB->SubMbPartWidth[0] = 16;
+    currMB->NumSubMbPart[0] = 1;
+    currMB->ref_idx_L0[0] = currMB->ref_idx_L0[1] =
+                                currMB->ref_idx_L0[2] = currMB->ref_idx_L0[3] = DEFAULT_REF_IDX;
+    currMB->ref_idx_L1[0] = currMB->ref_idx_L1[1] =
+                                currMB->ref_idx_L1[2] = currMB->ref_idx_L1[3] = DEFAULT_REF_IDX;
+    currMB->RefIdx[0] = currMB->RefIdx[1] =
+                            currMB->RefIdx[2] = currMB->RefIdx[3] = video->RefPicList0[DEFAULT_REF_IDX]->RefIdx;
+
+    cur = encvid->currYMB; /* use smaller memory space for current MB */
+
+    /*  find limit of the search (adjusting search range)*/
+    lev_idx = mapLev2Idx[currSPS->level_idc];
+
+    /* we can make this part dynamic based on previous statistics */
+    ilow = i0 - range;
+    if (i0 - ilow > 2047) /* clip to conform with the standard */
+    {
+        ilow = i0 - 2047;
+    }
+    if (ilow < -13)  // change it from -15 to -13 because of 6-tap filter needs extra 2 lines.
+    {
+        ilow = -13;
+    }
+
+    ihigh = i0 + range - 1;
+    if (ihigh - i0 > 2047) /* clip to conform with the standard */
+    {
+        ihigh = i0 + 2047;
+    }
+    if (ihigh > width - 3)
+    {
+        ihigh = width - 3;  // change from width-1 to width-3 for the same reason as above
+    }
+
+    jlow = j0 - range;
+    if (j0 - jlow > MaxVmvR[lev_idx] - 1) /* clip to conform with the standard */
+    {
+        jlow = j0 - MaxVmvR[lev_idx] + 1;
+    }
+    if (jlow < -13)     // same reason as above
+    {
+        jlow = -13;
+    }
+
+    jhigh = j0 + range - 1;
+    if (jhigh - j0 > MaxVmvR[lev_idx] - 1) /* clip to conform with the standard */
+    {
+        jhigh = j0 + MaxVmvR[lev_idx] - 1;
+    }
+    if (jhigh > height - 3) // same reason as above
+    {
+        jhigh = height - 3;
+    }
+
+    /* find initial motion vector & predicted MV*/
+    AVCCandidateSelection(mvx, mvy, &num_can, i0 >> 4, j0 >> 4, encvid, type_pred, &cmvx, &cmvy);
+
+    imin = i0;
+    jmin = j0; /* needed for fullsearch */
+    ncand = ref + i0 + j0 * lx;
+
+    /* for first row of MB, fullsearch can be used */
+    if (FS_en)
+    {
+        *hp_guess = 0; /* no guess for fast half-pel */
+
+        dmin =  AVCFullSearch(encvid, ref, cur, &imin, &jmin, ilow, ihigh, jlow, jhigh, cmvx, cmvy);
+
+        ncand = ref + imin + jmin * lx;
+    }
+    else
+    {   /*       fullsearch the top row to only upto (0,3) MB */
+        /*       upto 30% complexity saving with the same complexity */
+        if (video->PrevRefFrameNum == 0 && j0 == 0 && i0 <= 64 && type_pred != 1)
+        {
+            *hp_guess = 0; /* no guess for fast half-pel */
+            dmin =  AVCFullSearch(encvid, ref, cur, &imin, &jmin, ilow, ihigh, jlow, jhigh, cmvx, cmvy);
+            ncand = ref + imin + jmin * lx;
+        }
+        else
+        {
+            /************** initialize candidate **************************/
+
+            dmin = 65535;
+
+            /* check if all are equal */
+            if (num_can == ALL_CAND_EQUAL)
+            {
+                i = i0 + mvx[0];
+                j = j0 + mvy[0];
+
+                if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+                {
+                    cand = ref + i + j * lx;
+
+                    d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+                    mvcost = MV_COST(lambda_motion, mvshift, i - i0, j - j0, cmvx, cmvy);
+                    d +=  mvcost;
+
+                    if (d < dmin)
+                    {
+                        dmin = d;
+                        imin = i;
+                        jmin = j;
+                        ncand = cand;
+                        min_sad = d - mvcost; // for rate control
+                    }
+                }
+            }
+            else
+            {
+                /************** evaluate unique candidates **********************/
+                for (k = 0; k < num_can; k++)
+                {
+                    i = i0 + mvx[k];
+                    j = j0 + mvy[k];
+
+                    if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+                    {
+                        cand = ref + i + j * lx;
+                        d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+                        mvcost = MV_COST(lambda_motion, mvshift, i - i0, j - j0, cmvx, cmvy);
+                        d +=  mvcost;
+
+                        if (d < dmin)
+                        {
+                            dmin = d;
+                            imin = i;
+                            jmin = j;
+                            ncand = cand;
+                            min_sad = d - mvcost; // for rate control
+                        }
+                    }
+                }
+            }
+
+            /******************* local refinement ***************************/
+            center_again = 0;
+            last_loc = new_loc = 0;
+            //          ncand = ref + jmin*lx + imin;  /* center of the search */
+            step = 0;
+            dn[0] = dmin;
+            while (!center_again && step <= max_step)
+            {
+
+                AVCMoveNeighborSAD(dn, last_loc);
+
+                center_again = 1;
+                i = imin;
+                j = jmin - 1;
+                cand = ref + i + j * lx;
+
+                /*  starting from [0,-1] */
+                /* spiral check one step at a time*/
+                for (k = 2; k <= 8; k += 2)
+                {
+                    if (!tab_exclude[last_loc][k]) /* exclude last step computation */
+                    {       /* not already computed */
+                        if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+                        {
+                            d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, extra_info);
+                            mvcost = MV_COST(lambda_motion, mvshift, i - i0, j - j0, cmvx, cmvy);
+                            d += mvcost;
+
+                            dn[k] = d; /* keep it for half pel use */
+
+                            if (d < dmin)
+                            {
+                                ncand = cand;
+                                dmin = d;
+                                imin = i;
+                                jmin = j;
+                                center_again = 0;
+                                new_loc = k;
+                                min_sad = d - mvcost; // for rate control
+                            }
+                        }
+                    }
+                    if (k == 8)  /* end side search*/
+                    {
+                        if (!center_again)
+                        {
+                            k = -1; /* start diagonal search */
+                            cand -= lx;
+                            j--;
+                        }
+                    }
+                    else
+                    {
+                        next = refine_next[k][0];
+                        i += next;
+                        cand += next;
+                        next = refine_next[k][1];
+                        j += next;
+                        cand += lx * next;
+                    }
+                }
+                last_loc = new_loc;
+                step ++;
+            }
+            if (!center_again)
+                AVCMoveNeighborSAD(dn, last_loc);
+
+            *hp_guess = AVCFindMin(dn);
+
+            encvid->rateCtrl->MADofMB[mbnum] = min_sad / 256.0;
+        }
+    }
+
+    mot16x16[mbnum].sad = dmin;
+    mot16x16[mbnum].x = (imin - i0) << 2;
+    mot16x16[mbnum].y = (jmin - j0) << 2;
+    best_cand[0] = ncand;
+
+    if (rateCtrl->subPelEnable) // always enable half-pel search
+    {
+        /* find half-pel resolution motion vector */
+        min_sad = AVCFindHalfPelMB(encvid, cur, mot16x16 + mbnum, best_cand[0], i0, j0, *hp_guess, cmvx, cmvy);
+
+        encvid->rateCtrl->MADofMB[mbnum] = min_sad / 256.0;
+
+
+        if (encvid->best_qpel_pos == -1)
+        {
+            ncand = encvid->hpel_cand[encvid->best_hpel_pos];
+        }
+        else
+        {
+            ncand = encvid->qpel_cand[encvid->best_qpel_pos];
+        }
+    }
+    else
+    {
+        encvid->rateCtrl->MADofMB[mbnum] = min_sad / 256.0;
+    }
+
+    /** do motion comp here for now */
+    ref = currPic->Sl + i0 + j0 * lx;
+    /* copy from the best result to current Picture */
+    for (j = 0; j < 16; j++)
+    {
+        for (i = 0; i < 16; i++)
+        {
+            *ref++ = *ncand++;
+        }
+        ref += (lx - 16);
+        ncand += 8;
+    }
+
+    return ;
+}
+
+#endif
+
+/*===============================================================================
+    Function:   AVCFullSearch
+    Date:       09/16/2000
+    Purpose:    Perform full-search motion estimation over the range of search
+                region in a spiral-outward manner.
+    Input/Output:   VideoEncData, current Vol, previou Vop, pointer to the left corner of
+                current VOP, current coord (also output), boundaries.
+===============================================================================*/
+int AVCFullSearch(AVCEncObject *encvid, uint8 *prev, uint8 *cur,
+                  int *imin, int *jmin, int ilow, int ihigh, int jlow, int jhigh,
+                  int cmvx, int cmvy)
+{
+    int range = encvid->rateCtrl->mvRange;
+    AVCPictureData *currPic = encvid->common->currPic;
+    uint8 *cand;
+    int i, j, k, l;
+    int d, dmin;
+    int i0 = *imin; /* current position */
+    int j0 = *jmin;
+    int (*SAD_Macroblock)(uint8*, uint8*, int, void*) = encvid->functionPointer->SAD_Macroblock;
+    void *extra_info = encvid->sad_extra_info;
+    int lx = currPic->pitch; /* with padding */
+
+    int offset = i0 + j0 * lx;
+
+    int lambda_motion = encvid->lambda_motion;
+    uint8 *mvbits = encvid->mvbits;
+    int mvshift = 2;
+    int mvcost;
+    int min_sad;
+
+    cand = prev + offset;
+
+    dmin  = (*SAD_Macroblock)(cand, cur, (65535 << 16) | lx, (void*)extra_info);
+    mvcost = MV_COST(lambda_motion, mvshift, 0, 0, cmvx, cmvy);
+    min_sad = dmin;
+    dmin += mvcost;
+
+    /* perform spiral search */
+    for (k = 1; k <= range; k++)
+    {
+
+        i = i0 - k;
+        j = j0 - k;
+
+        cand = prev + i + j * lx;
+
+        for (l = 0; l < 8*k; l++)
+        {
+            /* no need for boundary checking again */
+            if (i >= ilow && i <= ihigh && j >= jlow && j <= jhigh)
+            {
+                d = (*SAD_Macroblock)(cand, cur, (dmin << 16) | lx, (void*)extra_info);
+                mvcost = MV_COST(lambda_motion, mvshift, i - i0, j - j0, cmvx, cmvy);
+                d +=  mvcost;
+
+                if (d < dmin)
+                {
+                    dmin = d;
+                    *imin = i;
+                    *jmin = j;
+                    min_sad = d - mvcost;
+                }
+            }
+
+            if (l < (k << 1))
+            {
+                i++;
+                cand++;
+            }
+            else if (l < (k << 2))
+            {
+                j++;
+                cand += lx;
+            }
+            else if (l < ((k << 2) + (k << 1)))
+            {
+                i--;
+                cand--;
+            }
+            else
+            {
+                j--;
+                cand -= lx;
+            }
+        }
+    }
+
+    encvid->rateCtrl->MADofMB[encvid->common->mbNum] = (min_sad / 256.0); // for rate control
+
+    return dmin;
+}
+
+/*===============================================================================
+    Function:   AVCCandidateSelection
+    Date:       09/16/2000
+    Purpose:    Fill up the list of candidate using spatio-temporal correlation
+                among neighboring blocks.
+    Input/Output:   type_pred = 0: first pass, 1: second pass, or no SCD
+    Modified:   , 09/23/01, get rid of redundant candidates before passing back.
+                , 09/11/07, added return for modified predicted MV, this will be
+                    needed for both fast search and fullsearch.
+===============================================================================*/
+
+void AVCCandidateSelection(int *mvx, int *mvy, int *num_can, int imb, int jmb,
+                           AVCEncObject *encvid, int type_pred, int *cmvx, int *cmvy)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMV *mot16x16 = encvid->mot16x16;
+    AVCMV *pmot;
+    int mbnum = video->mbNum;
+    int mbwidth = video->PicWidthInMbs;
+    int mbheight = video->PicHeightInMbs;
+    int i, j, same, num1;
+
+    /* this part is for predicted MV */
+    int pmvA_x = 0, pmvA_y = 0, pmvB_x = 0, pmvB_y = 0, pmvC_x = 0, pmvC_y = 0;
+    int availA = 0, availB = 0, availC = 0;
+
+    *num_can = 0;
+
+    if (video->PrevRefFrameNum != 0) // previous frame is an IDR frame
+    {
+        /* Spatio-Temporal Candidate (five candidates) */
+        if (type_pred == 0) /* first pass */
+        {
+            pmot = &mot16x16[mbnum]; /* same coordinate previous frame */
+            mvx[(*num_can)] = (pmot->x) >> 2;
+            mvy[(*num_can)++] = (pmot->y) >> 2;
+            if (imb >= (mbwidth >> 1) && imb > 0)  /*left neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum-1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            else if (imb + 1 < mbwidth)   /*right neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum+1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+
+            if (jmb < mbheight - 1)  /*bottom neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum+mbwidth];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            else if (jmb > 0)   /*upper neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum-mbwidth];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+
+            if (imb > 0 && jmb > 0)  /* upper-left neighbor current frame*/
+            {
+                pmot = &mot16x16[mbnum-mbwidth-1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (jmb > 0 && imb < mbheight - 1)  /* upper right neighbor current frame*/
+            {
+                pmot = &mot16x16[mbnum-mbwidth+1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+        }
+        else    /* second pass */
+            /* original ST1 algorithm */
+        {
+            pmot = &mot16x16[mbnum]; /* same coordinate previous frame */
+            mvx[(*num_can)] = (pmot->x) >> 2;
+            mvy[(*num_can)++] = (pmot->y) >> 2;
+
+            if (imb > 0)  /*left neighbor current frame */
+            {
+                pmot = &mot16x16[mbnum-1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (jmb > 0)  /*upper neighbor current frame */
+            {
+                pmot = &mot16x16[mbnum-mbwidth];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (imb < mbwidth - 1)  /*right neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum+1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (jmb < mbheight - 1)  /*bottom neighbor previous frame */
+            {
+                pmot = &mot16x16[mbnum+mbwidth];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+        }
+
+        /* get predicted MV */
+        if (imb > 0)    /* get MV from left (A) neighbor either on current or previous frame */
+        {
+            availA = 1;
+            pmot = &mot16x16[mbnum-1];
+            pmvA_x = pmot->x;
+            pmvA_y = pmot->y;
+        }
+
+        if (jmb > 0) /* get MV from top (B) neighbor either on current or previous frame */
+        {
+            availB = 1;
+            pmot = &mot16x16[mbnum-mbwidth];
+            pmvB_x = pmot->x;
+            pmvB_y = pmot->y;
+
+            availC = 1;
+
+            if (imb < mbwidth - 1) /* get MV from top-right (C) neighbor of current frame */
+            {
+                pmot = &mot16x16[mbnum-mbwidth+1];
+            }
+            else /* get MV from top-left (D) neighbor of current frame */
+            {
+                pmot = &mot16x16[mbnum-mbwidth-1];
+            }
+            pmvC_x = pmot->x;
+            pmvC_y = pmot->y;
+        }
+
+    }
+    else  /* only Spatial Candidate (four candidates)*/
+    {
+        if (type_pred == 0) /*first pass*/
+        {
+            if (imb > 1)  /* neighbor two blocks away to the left */
+            {
+                pmot = &mot16x16[mbnum-2];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (imb > 0 && jmb > 0)  /* upper-left neighbor */
+            {
+                pmot = &mot16x16[mbnum-mbwidth-1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+            if (jmb > 0 && imb < mbheight - 1)  /* upper right neighbor */
+            {
+                pmot = &mot16x16[mbnum-mbwidth+1];
+                mvx[(*num_can)] = (pmot->x) >> 2;
+                mvy[(*num_can)++] = (pmot->y) >> 2;
+            }
+
+            /* get predicted MV */
+            if (imb > 1)    /* get MV from 2nd left (A) neighbor either of current frame */
+            {
+                availA = 1;
+                pmot = &mot16x16[mbnum-2];
+                pmvA_x = pmot->x;
+                pmvA_y = pmot->y;
+            }
+
+            if (jmb > 0 && imb > 0) /* get MV from top-left (B) neighbor of current frame */
+            {
+                availB = 1;
+                pmot = &mot16x16[mbnum-mbwidth-1];
+                pmvB_x = pmot->x;
+                pmvB_y = pmot->y;
+            }
+
+            if (jmb > 0 && imb < mbwidth - 1)
+            {
+                availC = 1;
+                pmot = &mot16x16[mbnum-mbwidth+1];
+                pmvC_x = pmot->x;
+                pmvC_y = pmot->y;
+            }
+        }
+//#ifdef SCENE_CHANGE_DETECTION
+        /* second pass (ST2 algorithm)*/
+        else
+        {
+            if (type_pred == 1) /*  4/7/01 */
+            {
+                if (imb > 0)  /*left neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum-1];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+                }
+                if (jmb > 0)  /*upper neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum-mbwidth];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+                }
+                if (imb < mbwidth - 1)  /*right neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum+1];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+                }
+                if (jmb < mbheight - 1)  /*bottom neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum+mbwidth];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+                }
+            }
+            //#else
+            else /* original ST1 algorithm */
+            {
+                if (imb > 0)  /*left neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum-1];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+
+                    if (jmb > 0)  /*upper-left neighbor current frame */
+                    {
+                        pmot = &mot16x16[mbnum-mbwidth-1];
+                        mvx[(*num_can)] = (pmot->x) >> 2;
+                        mvy[(*num_can)++] = (pmot->y) >> 2;
+                    }
+
+                }
+                if (jmb > 0)  /*upper neighbor current frame */
+                {
+                    pmot = &mot16x16[mbnum-mbwidth];
+                    mvx[(*num_can)] = (pmot->x) >> 2;
+                    mvy[(*num_can)++] = (pmot->y) >> 2;
+
+                    if (imb < mbheight - 1)  /*upper-right neighbor current frame */
+                    {
+                        pmot = &mot16x16[mbnum-mbwidth+1];
+                        mvx[(*num_can)] = (pmot->x) >> 2;
+                        mvy[(*num_can)++] = (pmot->y) >> 2;
+                    }
+                }
+            }
+
+            /* get predicted MV */
+            if (imb > 0)    /* get MV from left (A) neighbor either on current or previous frame */
+            {
+                availA = 1;
+                pmot = &mot16x16[mbnum-1];
+                pmvA_x = pmot->x;
+                pmvA_y = pmot->y;
+            }
+
+            if (jmb > 0) /* get MV from top (B) neighbor either on current or previous frame */
+            {
+                availB = 1;
+                pmot = &mot16x16[mbnum-mbwidth];
+                pmvB_x = pmot->x;
+                pmvB_y = pmot->y;
+
+                availC = 1;
+
+                if (imb < mbwidth - 1) /* get MV from top-right (C) neighbor of current frame */
+                {
+                    pmot = &mot16x16[mbnum-mbwidth+1];
+                }
+                else /* get MV from top-left (D) neighbor of current frame */
+                {
+                    pmot = &mot16x16[mbnum-mbwidth-1];
+                }
+                pmvC_x = pmot->x;
+                pmvC_y = pmot->y;
+            }
+        }
+//#endif
+    }
+
+    /*  3/23/01, remove redundant candidate (possible k-mean) */
+    num1 = *num_can;
+    *num_can = 1;
+    for (i = 1; i < num1; i++)
+    {
+        same = 0;
+        j = 0;
+        while (!same && j < *num_can)
+        {
+#if (CANDIDATE_DISTANCE==0)
+            if (mvx[i] == mvx[j] && mvy[i] == mvy[j])
+#else
+            // modified k-mean,  3/24/01, shouldn't be greater than 3
+            if (AVC_ABS(mvx[i] - mvx[j]) + AVC_ABS(mvy[i] - mvy[j]) < CANDIDATE_DISTANCE)
+#endif
+                same = 1;
+            j++;
+        }
+        if (!same)
+        {
+            mvx[*num_can] = mvx[i];
+            mvy[*num_can] = mvy[i];
+            (*num_can)++;
+        }
+    }
+
+    if (num1 == 5 && *num_can == 1)
+        *num_can = ALL_CAND_EQUAL; /* all are equal */
+
+    /* calculate predicted MV */
+
+    if (availA && !(availB || availC))
+    {
+        *cmvx = pmvA_x;
+        *cmvy = pmvA_y;
+    }
+    else
+    {
+        *cmvx = AVC_MEDIAN(pmvA_x, pmvB_x, pmvC_x);
+        *cmvy = AVC_MEDIAN(pmvA_y, pmvB_y, pmvC_y);
+    }
+
+    return ;
+}
+
+
+/*************************************************************
+    Function:   AVCMoveNeighborSAD
+    Date:       3/27/01
+    Purpose:    Move neighboring SAD around when center has shifted
+*************************************************************/
+
+void AVCMoveNeighborSAD(int dn[], int new_loc)
+{
+    int tmp[9];
+    tmp[0] = dn[0];
+    tmp[1] = dn[1];
+    tmp[2] = dn[2];
+    tmp[3] = dn[3];
+    tmp[4] = dn[4];
+    tmp[5] = dn[5];
+    tmp[6] = dn[6];
+    tmp[7] = dn[7];
+    tmp[8] = dn[8];
+    dn[0] = dn[1] = dn[2] = dn[3] = dn[4] = dn[5] = dn[6] = dn[7] = dn[8] = 65536;
+
+    switch (new_loc)
+    {
+        case 0:
+            break;
+        case 1:
+            dn[4] = tmp[2];
+            dn[5] = tmp[0];
+            dn[6] = tmp[8];
+            break;
+        case 2:
+            dn[4] = tmp[3];
+            dn[5] = tmp[4];
+            dn[6] = tmp[0];
+            dn[7] = tmp[8];
+            dn[8] = tmp[1];
+            break;
+        case 3:
+            dn[6] = tmp[4];
+            dn[7] = tmp[0];
+            dn[8] = tmp[2];
+            break;
+        case 4:
+            dn[1] = tmp[2];
+            dn[2] = tmp[3];
+            dn[6] = tmp[5];
+            dn[7] = tmp[6];
+            dn[8] = tmp[0];
+            break;
+        case 5:
+            dn[1] = tmp[0];
+            dn[2] = tmp[4];
+            dn[8] = tmp[6];
+            break;
+        case 6:
+            dn[1] = tmp[8];
+            dn[2] = tmp[0];
+            dn[3] = tmp[4];
+            dn[4] = tmp[5];
+            dn[8] = tmp[7];
+            break;
+        case 7:
+            dn[2] = tmp[8];
+            dn[3] = tmp[0];
+            dn[4] = tmp[6];
+            break;
+        case 8:
+            dn[2] = tmp[1];
+            dn[3] = tmp[2];
+            dn[4] = tmp[0];
+            dn[5] = tmp[6];
+            dn[6] = tmp[7];
+            break;
+    }
+    dn[0] = tmp[new_loc];
+
+    return ;
+}
+
+/*  3/28/01, find minimal of dn[9] */
+
+int AVCFindMin(int dn[])
+{
+    int min, i;
+    int dmin;
+
+    dmin = dn[1];
+    min = 1;
+    for (i = 2; i < 9; i++)
+    {
+        if (dn[i] < dmin)
+        {
+            dmin = dn[i];
+            min = i;
+        }
+    }
+
+    return min;
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/rate_control.cpp b/media/libstagefright/codecs/avc/enc/src/rate_control.cpp
new file mode 100644
index 0000000..15b55fb
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/rate_control.cpp
@@ -0,0 +1,981 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+#include <math.h>
+
+/* rate control variables */
+#define RC_MAX_QUANT 51
+#define RC_MIN_QUANT 0   //cap to 10 to prevent rate fluctuation    
+
+#define MAD_MIN 1 /* handle the case of devision by zero in RC */
+
+
+/* local functions */
+double QP2Qstep(int QP);
+int Qstep2QP(double Qstep);
+
+double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl);
+
+void targetBitCalculation(AVCEncObject *encvid, AVCCommonObj *video, AVCRateControl *rateCtrl, MultiPass *pMP);
+
+void calculateQuantizer_Multipass(AVCEncObject *encvid, AVCCommonObj *video,
+                                  AVCRateControl *rateCtrl, MultiPass *pMP);
+
+void updateRC_PostProc(AVCRateControl *rateCtrl, MultiPass *pMP);
+
+void AVCSaveRDSamples(MultiPass *pMP, int counter_samples);
+
+void updateRateControl(AVCRateControl *rateControl, int nal_type);
+
+int GetAvgFrameQP(AVCRateControl *rateCtrl)
+{
+    return rateCtrl->Qc;
+}
+
+AVCEnc_Status RCDetermineFrameNum(AVCEncObject *encvid, AVCRateControl *rateCtrl, uint32 modTime, uint *frameNum)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    uint32 modTimeRef = encvid->modTimeRef;
+    int32  currFrameNum ;
+    int  frameInc;
+
+
+    /* check with the buffer fullness to make sure that we have enough bits to encode this frame */
+    /* we can use a threshold to guarantee minimum picture quality */
+    /**********************************/
+
+    /* for now, the default is to encode every frame, To Be Changed */
+    if (rateCtrl->first_frame)
+    {
+        encvid->modTimeRef = modTime;
+        encvid->wrapModTime = 0;
+        encvid->prevFrameNum = 0;
+        encvid->prevProcFrameNum = 0;
+
+        *frameNum = 0;
+
+        /* set frame type to IDR-frame */
+        video->nal_unit_type = AVC_NALTYPE_IDR;
+        sliceHdr->slice_type = AVC_I_ALL_SLICE;
+        video->slice_type = AVC_I_SLICE;
+
+        return AVCENC_SUCCESS;
+    }
+    else
+    {
+        if (modTime < modTimeRef) /* modTime wrapped around */
+        {
+            encvid->wrapModTime += ((uint32)0xFFFFFFFF - modTimeRef) + 1;
+            encvid->modTimeRef = modTimeRef = 0;
+        }
+        modTime += encvid->wrapModTime; /* wrapModTime is non zero after wrap-around */
+
+        currFrameNum = (int32)(((modTime - modTimeRef) * rateCtrl->frame_rate + 200) / 1000); /* add small roundings */
+
+        if (currFrameNum <= (int32)encvid->prevProcFrameNum)
+        {
+            return AVCENC_FAIL;  /* this is a late frame do not encode it */
+        }
+
+        frameInc = currFrameNum - encvid->prevProcFrameNum;
+
+        if (frameInc < rateCtrl->skip_next_frame + 1)
+        {
+            return AVCENC_FAIL;  /* frame skip required to maintain the target bit rate. */
+        }
+
+        RCUpdateBuffer(video, rateCtrl, frameInc - rateCtrl->skip_next_frame);  /* in case more frames dropped */
+
+        *frameNum = currFrameNum;
+
+        /* This part would be similar to DetermineVopType of m4venc */
+        if ((*frameNum >= (uint)rateCtrl->idrPeriod && rateCtrl->idrPeriod > 0) || (*frameNum > video->MaxFrameNum)) /* first frame or IDR*/
+        {
+            /* set frame type to IDR-frame */
+            if (rateCtrl->idrPeriod)
+            {
+                encvid->modTimeRef += (uint32)(rateCtrl->idrPeriod * 1000 / rateCtrl->frame_rate);
+                *frameNum -= rateCtrl->idrPeriod;
+            }
+            else
+            {
+                encvid->modTimeRef += (uint32)(video->MaxFrameNum * 1000 / rateCtrl->frame_rate);
+                *frameNum -= video->MaxFrameNum;
+            }
+
+            video->nal_unit_type = AVC_NALTYPE_IDR;
+            sliceHdr->slice_type = AVC_I_ALL_SLICE;
+            video->slice_type = AVC_I_SLICE;
+            encvid->prevProcFrameNum = *frameNum;
+        }
+        else
+        {
+            video->nal_unit_type = AVC_NALTYPE_SLICE;
+            sliceHdr->slice_type = AVC_P_ALL_SLICE;
+            video->slice_type = AVC_P_SLICE;
+            encvid->prevProcFrameNum = currFrameNum;
+        }
+
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+void RCUpdateBuffer(AVCCommonObj *video, AVCRateControl *rateCtrl, int frameInc)
+{
+    int tmp;
+    MultiPass *pMP = rateCtrl->pMP;
+
+    OSCL_UNUSED_ARG(video);
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        if (frameInc > 1)
+        {
+            tmp = rateCtrl->bitsPerFrame * (frameInc - 1);
+            rateCtrl->VBV_fullness -= tmp;
+            pMP->counter_BTsrc += 10 * (frameInc - 1);
+
+            /* Check buffer underflow */
+            if (rateCtrl->VBV_fullness < rateCtrl->low_bound)
+            {
+                rateCtrl->VBV_fullness = rateCtrl->low_bound; // -rateCtrl->Bs/2;
+                rateCtrl->TMN_W = rateCtrl->VBV_fullness - rateCtrl->low_bound;
+                pMP->counter_BTsrc = pMP->counter_BTdst + (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
+            }
+        }
+    }
+}
+
+
+AVCEnc_Status InitRateControlModule(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    double L1, L2, L3, bpp;
+    int qp;
+    int i, j;
+
+    rateCtrl->basicUnit = video->PicSizeInMbs;
+
+    rateCtrl->MADofMB = (double*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData,
+                        video->PicSizeInMbs * sizeof(double), DEFAULT_ATTR);
+
+    if (!rateCtrl->MADofMB)
+    {
+        goto CLEANUP_RC;
+    }
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        rateCtrl->pMP = (MultiPass*) avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, sizeof(MultiPass), DEFAULT_ATTR);
+        if (!rateCtrl->pMP)
+        {
+            goto CLEANUP_RC;
+        }
+        memset(rateCtrl->pMP, 0, sizeof(MultiPass));
+        rateCtrl->pMP->encoded_frames = -1; /* forget about the very first I frame */
+
+        /* RDInfo **pRDSamples */
+        rateCtrl->pMP->pRDSamples = (RDInfo **)avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, (30 * sizeof(RDInfo *)), DEFAULT_ATTR);
+        if (!rateCtrl->pMP->pRDSamples)
+        {
+            goto CLEANUP_RC;
+        }
+
+        for (i = 0; i < 30; i++)
+        {
+            rateCtrl->pMP->pRDSamples[i] = (RDInfo *)avcHandle->CBAVC_Malloc(encvid->avcHandle->userData, (32 * sizeof(RDInfo)), DEFAULT_ATTR);
+            if (!rateCtrl->pMP->pRDSamples[i])
+            {
+                goto CLEANUP_RC;
+            }
+            for (j = 0; j < 32; j++)    memset(&(rateCtrl->pMP->pRDSamples[i][j]), 0, sizeof(RDInfo));
+        }
+        rateCtrl->pMP->frameRange = (int)(rateCtrl->frame_rate * 1.0); /* 1.0s time frame*/
+        rateCtrl->pMP->frameRange = AVC_MAX(rateCtrl->pMP->frameRange, 5);
+        rateCtrl->pMP->frameRange = AVC_MIN(rateCtrl->pMP->frameRange, 30);
+
+        rateCtrl->pMP->framePos = -1;
+
+
+        rateCtrl->bitsPerFrame = (int32)(rateCtrl->bitRate / rateCtrl->frame_rate);
+
+        /* BX rate control */
+        rateCtrl->skip_next_frame = 0; /* must be initialized */
+
+        rateCtrl->Bs = rateCtrl->cpbSize;
+        rateCtrl->TMN_W = 0;
+        rateCtrl->VBV_fullness = (int)(rateCtrl->Bs * 0.5); /* rateCtrl->Bs */
+        rateCtrl->encoded_frames = 0;
+
+        rateCtrl->TMN_TH = rateCtrl->bitsPerFrame;
+
+        rateCtrl->max_BitVariance_num = (int)((OsclFloat)(rateCtrl->Bs - rateCtrl->VBV_fullness) / (rateCtrl->bitsPerFrame / 10.0)) - 5;
+        if (rateCtrl->max_BitVariance_num < 0) rateCtrl->max_BitVariance_num += 5;
+
+        // Set the initial buffer fullness
+        /* According to the spec, the initial buffer fullness needs to be set to 1/3 */
+        rateCtrl->VBV_fullness = (int)(rateCtrl->Bs / 3.0 - rateCtrl->Bs / 2.0); /* the buffer range is [-Bs/2, Bs/2] */
+        rateCtrl->pMP->counter_BTsrc = (int)((rateCtrl->Bs / 2.0 - rateCtrl->Bs / 3.0) / (rateCtrl->bitsPerFrame / 10.0));
+        rateCtrl->TMN_W = (int)(rateCtrl->VBV_fullness + rateCtrl->pMP->counter_BTsrc * (rateCtrl->bitsPerFrame / 10.0));
+
+        rateCtrl->low_bound = -rateCtrl->Bs / 2;
+        rateCtrl->VBV_fullness_offset = 0;
+
+        /* Setting the bitrate and framerate */
+        rateCtrl->pMP->bitrate = rateCtrl->bitRate;
+        rateCtrl->pMP->framerate = rateCtrl->frame_rate;
+        rateCtrl->pMP->target_bits_per_frame = rateCtrl->pMP->bitrate / rateCtrl->pMP->framerate;
+
+        /*compute the initial QP*/
+        bpp = 1.0 * rateCtrl->bitRate / (rateCtrl->frame_rate * (video->PicSizeInMbs << 8));
+        if (video->PicWidthInSamplesL == 176)
+        {
+            L1 = 0.1;
+            L2 = 0.3;
+            L3 = 0.6;
+        }
+        else if (video->PicWidthInSamplesL == 352)
+        {
+            L1 = 0.2;
+            L2 = 0.6;
+            L3 = 1.2;
+        }
+        else
+        {
+            L1 = 0.6;
+            L2 = 1.4;
+            L3 = 2.4;
+        }
+
+        if (rateCtrl->initQP == 0)
+        {
+            if (bpp <= L1)
+                qp = 35;
+            else if (bpp <= L2)
+                qp = 25;
+            else if (bpp <= L3)
+                qp = 20;
+            else
+                qp = 15;
+            rateCtrl->initQP = qp;
+        }
+
+        rateCtrl->Qc = rateCtrl->initQP;
+    }
+
+    return AVCENC_SUCCESS;
+
+CLEANUP_RC:
+
+    CleanupRateControlModule(avcHandle);
+    return AVCENC_MEMORY_FAIL;
+
+}
+
+
+void CleanupRateControlModule(AVCHandle *avcHandle)
+{
+    AVCEncObject *encvid = (AVCEncObject*) avcHandle->AVCObject;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    int i;
+
+    if (rateCtrl->MADofMB)
+    {
+        avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->MADofMB));
+    }
+
+    if (rateCtrl->pMP)
+    {
+        if (rateCtrl->pMP->pRDSamples)
+        {
+            for (i = 0; i < 30; i++)
+            {
+                if (rateCtrl->pMP->pRDSamples[i])
+                {
+                    avcHandle->CBAVC_Free(avcHandle->userData, (int)rateCtrl->pMP->pRDSamples[i]);
+                }
+            }
+            avcHandle->CBAVC_Free(avcHandle->userData, (int)rateCtrl->pMP->pRDSamples);
+        }
+        avcHandle->CBAVC_Free(avcHandle->userData, (int)(rateCtrl->pMP));
+    }
+
+    return ;
+}
+
+void RCInitGOP(AVCEncObject *encvid)
+{
+    /* in BX RC, there's no GOP-level RC */
+
+    OSCL_UNUSED_ARG(encvid);
+
+    return ;
+}
+
+
+void RCInitFrameQP(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCPicParamSet *picParam = video->currPicParams;
+    MultiPass *pMP = rateCtrl->pMP;
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        /* frame layer rate control */
+        if (rateCtrl->encoded_frames == 0)
+        {
+            video->QPy = rateCtrl->Qc = rateCtrl->initQP;
+        }
+        else
+        {
+            calculateQuantizer_Multipass(encvid, video, rateCtrl, pMP);
+            video->QPy = rateCtrl->Qc;
+        }
+
+        rateCtrl->NumberofHeaderBits = 0;
+        rateCtrl->NumberofTextureBits = 0;
+        rateCtrl->numFrameBits = 0; // reset
+
+        /* update pMP->framePos */
+        if (++pMP->framePos == pMP->frameRange) pMP->framePos = 0;
+
+        if (rateCtrl->T == 0)
+        {
+            pMP->counter_BTdst = (int)(rateCtrl->frame_rate * 7.5 + 0.5); /* 0.75s time frame */
+            pMP->counter_BTdst = AVC_MIN(pMP->counter_BTdst, (int)(rateCtrl->max_BitVariance_num / 2 * 0.40)); /* 0.75s time frame may go beyond VBV buffer if we set the buffer size smaller than 0.75s */
+            pMP->counter_BTdst = AVC_MAX(pMP->counter_BTdst, (int)((rateCtrl->Bs / 2 - rateCtrl->VBV_fullness) * 0.30 / (rateCtrl->TMN_TH / 10.0) + 0.5)); /* At least 30% of VBV buffer size/2 */
+            pMP->counter_BTdst = AVC_MIN(pMP->counter_BTdst, 20); /* Limit the target to be smaller than 3C */
+
+            pMP->target_bits = rateCtrl->T = rateCtrl->TMN_TH = (int)(rateCtrl->TMN_TH * (1.0 + pMP->counter_BTdst * 0.1));
+            pMP->diff_counter = pMP->counter_BTdst;
+        }
+
+        /* collect the necessary data: target bits, actual bits, mad and QP */
+        pMP->target_bits = rateCtrl->T;
+        pMP->QP  = video->QPy;
+
+        pMP->mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; //ComputeFrameMAD(video, rateCtrl);
+        if (pMP->mad < MAD_MIN) pMP->mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
+
+        pMP->bitrate = rateCtrl->bitRate; /* calculated in RCVopQPSetting */
+        pMP->framerate = rateCtrl->frame_rate;
+
+        /* first pass encoding */
+        pMP->nRe_Quantized = 0;
+
+    } // rcEnable
+    else
+    {
+        video->QPy = rateCtrl->initQP;
+    }
+
+//  printf(" %d ",video->QPy);
+
+    if (video->CurrPicNum == 0 && encvid->outOfBandParamSet == FALSE)
+    {
+        picParam->pic_init_qs_minus26 = 0;
+        picParam->pic_init_qp_minus26 = video->QPy - 26;
+    }
+
+    // need this for motion estimation
+    encvid->lambda_mode = QP2QUANT[AVC_MAX(0, video->QPy-SHIFT_QP)];
+    encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode);
+    return ;
+}
+
+/* Mad based variable bit allocation + QP calculation with a new quadratic method */
+void calculateQuantizer_Multipass(AVCEncObject *encvid, AVCCommonObj *video,
+                                  AVCRateControl *rateCtrl, MultiPass *pMP)
+{
+    int prev_actual_bits = 0, curr_target, /*pos=0,*/i, j;
+    OsclFloat Qstep, prev_QP = 0.625;
+
+    OsclFloat curr_mad, prev_mad, curr_RD, prev_RD, average_mad, aver_QP;
+
+    /* Mad based variable bit allocation */
+    targetBitCalculation(encvid, video, rateCtrl, pMP);
+
+    if (rateCtrl->T <= 0 || rateCtrl->totalSAD == 0)
+    {
+        if (rateCtrl->T < 0)    rateCtrl->Qc = RC_MAX_QUANT;
+        return;
+    }
+
+    /* ---------------------------------------------------------------------------------------------------*/
+    /* current frame QP estimation */
+    curr_target = rateCtrl->T;
+    curr_mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs;
+    if (curr_mad < MAD_MIN) curr_mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
+    curr_RD  = (OsclFloat)curr_target / curr_mad;
+
+    if (rateCtrl->skip_next_frame == -1) // previous was skipped
+    {
+        i = pMP->framePos;
+        prev_mad = pMP->pRDSamples[i][0].mad;
+        prev_QP = pMP->pRDSamples[i][0].QP;
+        prev_actual_bits = pMP->pRDSamples[i][0].actual_bits;
+    }
+    else
+    {
+        /* Another version of search the optimal point */
+        prev_mad = 0.0;
+        i = 0;
+        while (i < pMP->frameRange && prev_mad < 0.001) /* find first one with nonzero prev_mad */
+        {
+            prev_mad = pMP->pRDSamples[i][0].mad;
+            i++;
+        }
+
+        if (i < pMP->frameRange)
+        {
+            prev_actual_bits = pMP->pRDSamples[i-1][0].actual_bits;
+
+            for (j = 0; i < pMP->frameRange; i++)
+            {
+                if (pMP->pRDSamples[i][0].mad != 0 &&
+                        AVC_ABS(prev_mad - curr_mad) > AVC_ABS(pMP->pRDSamples[i][0].mad - curr_mad))
+                {
+                    prev_mad = pMP->pRDSamples[i][0].mad;
+                    prev_actual_bits = pMP->pRDSamples[i][0].actual_bits;
+                    j = i;
+                }
+            }
+            prev_QP = QP2Qstep(pMP->pRDSamples[j][0].QP);
+
+            for (i = 1; i < pMP->samplesPerFrame[j]; i++)
+            {
+                if (AVC_ABS(prev_actual_bits - curr_target) > AVC_ABS(pMP->pRDSamples[j][i].actual_bits - curr_target))
+                {
+                    prev_actual_bits = pMP->pRDSamples[j][i].actual_bits;
+                    prev_QP = QP2Qstep(pMP->pRDSamples[j][i].QP);
+                }
+            }
+        }
+    }
+
+    // quadratic approximation
+    if (prev_mad > 0.001) // only when prev_mad is greater than 0, otherwise keep using the same QP
+    {
+        prev_RD = (OsclFloat)prev_actual_bits / prev_mad;
+        //rateCtrl->Qc = (Int)(prev_QP * sqrt(prev_actual_bits/curr_target) + 0.4);
+        if (prev_QP == 0.625) // added this to allow getting out of QP = 0 easily
+        {
+            Qstep = (int)(prev_RD / curr_RD + 0.5);
+        }
+        else
+        {
+            //      rateCtrl->Qc =(Int)(prev_QP * M4VENC_SQRT(prev_RD/curr_RD) + 0.9);
+
+            if (prev_RD / curr_RD > 0.5 && prev_RD / curr_RD < 2.0)
+                Qstep = (int)(prev_QP * (sqrt(prev_RD / curr_RD) + prev_RD / curr_RD) / 2.0 + 0.9); /* Quadratic and linear approximation */
+            else
+                Qstep = (int)(prev_QP * (sqrt(prev_RD / curr_RD) + pow(prev_RD / curr_RD, 1.0 / 3.0)) / 2.0 + 0.9);
+        }
+        // lower bound on Qc should be a function of curr_mad
+        // When mad is already low, lower bound on Qc doesn't have to be small.
+        // Note, this doesn't work well for low complexity clip encoded at high bit rate
+        // it doesn't hit the target bit rate due to this QP lower bound.
+        /// if((curr_mad < 8) && (rateCtrl->Qc < 12))   rateCtrl->Qc = 12;
+        //  else    if((curr_mad < 128) && (rateCtrl->Qc < 3)) rateCtrl->Qc = 3;
+
+        rateCtrl->Qc = Qstep2QP(Qstep);
+
+        if (rateCtrl->Qc < RC_MIN_QUANT) rateCtrl->Qc = RC_MIN_QUANT;
+        if (rateCtrl->Qc > RC_MAX_QUANT)    rateCtrl->Qc = RC_MAX_QUANT;
+    }
+
+    /* active bit resource protection */
+    aver_QP = (pMP->encoded_frames == 0 ? 0 : pMP->sum_QP / (OsclFloat)pMP->encoded_frames);
+    average_mad = (pMP->encoded_frames == 0 ? 0 : pMP->sum_mad / (OsclFloat)pMP->encoded_frames); /* this function is called from the scond encoded frame*/
+    if (pMP->diff_counter == 0 &&
+            ((OsclFloat)rateCtrl->Qc <= aver_QP*1.1 || curr_mad <= average_mad*1.1) &&
+            pMP->counter_BTsrc <= (pMP->counter_BTdst + (int)(pMP->framerate*1.0 + 0.5)))
+    {
+        rateCtrl->TMN_TH -= (int)(pMP->target_bits_per_frame / 10.0);
+        rateCtrl->T = rateCtrl->TMN_TH - rateCtrl->TMN_W;
+        pMP->counter_BTsrc++;
+        pMP->diff_counter--;
+    }
+
+}
+
+void targetBitCalculation(AVCEncObject *encvid, AVCCommonObj *video, AVCRateControl *rateCtrl, MultiPass *pMP)
+{
+    OSCL_UNUSED_ARG(encvid);
+    OsclFloat curr_mad;//, average_mad;
+    int diff_counter_BTsrc, diff_counter_BTdst, prev_counter_diff, curr_counter_diff, bound;
+    /* BT = Bit Transfer, for pMP->counter_BTsrc, pMP->counter_BTdst */
+
+    /* some stuff about frame dropping remained here to be done because pMP cannot be inserted into updateRateControl()*/
+    updateRC_PostProc(rateCtrl, pMP);
+
+    /* update pMP->counter_BTsrc and pMP->counter_BTdst to avoid interger overflow */
+    if (pMP->counter_BTsrc > 1000 && pMP->counter_BTdst > 1000)
+    {
+        pMP->counter_BTsrc -= 1000;
+        pMP->counter_BTdst -= 1000;
+    }
+
+    /* ---------------------------------------------------------------------------------------------------*/
+    /* target calculation */
+    curr_mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs;
+    if (curr_mad < MAD_MIN) curr_mad = MAD_MIN; /* MAD_MIN is defined as 1 in mp4def.h */
+    diff_counter_BTsrc = diff_counter_BTdst = 0;
+    pMP->diff_counter = 0;
+
+
+    /*1.calculate average mad */
+    pMP->sum_mad += curr_mad;
+    //average_mad = (pMP->encoded_frames < 1 ? curr_mad : pMP->sum_mad/(OsclFloat)(pMP->encoded_frames+1)); /* this function is called from the scond encoded frame*/
+    //pMP->aver_mad = average_mad;
+    if (pMP->encoded_frames >= 0) /* pMP->encoded_frames is set to -1 initially, so forget about the very first I frame */
+        pMP->aver_mad = (pMP->aver_mad * pMP->encoded_frames + curr_mad) / (pMP->encoded_frames + 1);
+
+    if (pMP->overlapped_win_size > 0 && pMP->encoded_frames_prev >= 0)
+        pMP->aver_mad_prev = (pMP->aver_mad_prev * pMP->encoded_frames_prev + curr_mad) / (pMP->encoded_frames_prev + 1);
+
+    /*2.average_mad, mad ==> diff_counter_BTsrc, diff_counter_BTdst */
+    if (pMP->overlapped_win_size == 0)
+    {
+        /* original verison */
+        if (curr_mad > pMP->aver_mad*1.1)
+        {
+            if (curr_mad / (pMP->aver_mad + 0.0001) > 2)
+                diff_counter_BTdst = (int)(sqrt(curr_mad / (pMP->aver_mad + 0.0001)) * 10 + 0.4) - 10;
+            //diff_counter_BTdst = (int)((sqrt(curr_mad/pMP->aver_mad)*2+curr_mad/pMP->aver_mad)/(3*0.1) + 0.4) - 10;
+            else
+                diff_counter_BTdst = (int)(curr_mad / (pMP->aver_mad + 0.0001) * 10 + 0.4) - 10;
+        }
+        else /* curr_mad <= average_mad*1.1 */
+            //diff_counter_BTsrc = 10 - (int)((sqrt(curr_mad/pMP->aver_mad) + pow(curr_mad/pMP->aver_mad, 1.0/3.0))/(2.0*0.1) + 0.4);
+            diff_counter_BTsrc = 10 - (int)(sqrt(curr_mad / (pMP->aver_mad + 0.0001)) * 10 + 0.5);
+
+        /* actively fill in the possible gap */
+        if (diff_counter_BTsrc == 0 && diff_counter_BTdst == 0 &&
+                curr_mad <= pMP->aver_mad*1.1 && pMP->counter_BTsrc < pMP->counter_BTdst)
+            diff_counter_BTsrc = 1;
+
+    }
+    else if (pMP->overlapped_win_size > 0)
+    {
+        /* transition time: use previous average mad "pMP->aver_mad_prev" instead of the current average mad "pMP->aver_mad" */
+        if (curr_mad > pMP->aver_mad_prev*1.1)
+        {
+            if (curr_mad / pMP->aver_mad_prev > 2)
+                diff_counter_BTdst = (int)(sqrt(curr_mad / (pMP->aver_mad_prev + 0.0001)) * 10 + 0.4) - 10;
+            //diff_counter_BTdst = (int)((M4VENC_SQRT(curr_mad/pMP->aver_mad_prev)*2+curr_mad/pMP->aver_mad_prev)/(3*0.1) + 0.4) - 10;
+            else
+                diff_counter_BTdst = (int)(curr_mad / (pMP->aver_mad_prev + 0.0001) * 10 + 0.4) - 10;
+        }
+        else /* curr_mad <= average_mad*1.1 */
+            //diff_counter_BTsrc = 10 - (Int)((sqrt(curr_mad/pMP->aver_mad_prev) + pow(curr_mad/pMP->aver_mad_prev, 1.0/3.0))/(2.0*0.1) + 0.4);
+            diff_counter_BTsrc = 10 - (int)(sqrt(curr_mad / (pMP->aver_mad_prev + 0.0001)) * 10 + 0.5);
+
+        /* actively fill in the possible gap */
+        if (diff_counter_BTsrc == 0 && diff_counter_BTdst == 0 &&
+                curr_mad <= pMP->aver_mad_prev*1.1 && pMP->counter_BTsrc < pMP->counter_BTdst)
+            diff_counter_BTsrc = 1;
+
+        if (--pMP->overlapped_win_size <= 0)    pMP->overlapped_win_size = 0;
+    }
+
+
+    /* if difference is too much, do clipping */
+    /* First, set the upper bound for current bit allocation variance: 80% of available buffer */
+    bound = (int)((rateCtrl->Bs / 2 - rateCtrl->VBV_fullness) * 0.6 / (pMP->target_bits_per_frame / 10)); /* rateCtrl->Bs */
+    diff_counter_BTsrc =  AVC_MIN(diff_counter_BTsrc, bound);
+    diff_counter_BTdst =  AVC_MIN(diff_counter_BTdst, bound);
+
+    /* Second, set another upper bound for current bit allocation: 4-5*bitrate/framerate */
+    bound = 50;
+//  if(video->encParams->RC_Type == CBR_LOWDELAY)
+//  not necessary       bound = 10;  -- For Low delay */
+
+    diff_counter_BTsrc =  AVC_MIN(diff_counter_BTsrc, bound);
+    diff_counter_BTdst =  AVC_MIN(diff_counter_BTdst, bound);
+
+
+    /* Third, check the buffer */
+    prev_counter_diff = pMP->counter_BTdst - pMP->counter_BTsrc;
+    curr_counter_diff = prev_counter_diff + (diff_counter_BTdst - diff_counter_BTsrc);
+
+    if (AVC_ABS(prev_counter_diff) >= rateCtrl->max_BitVariance_num || AVC_ABS(curr_counter_diff) >= rateCtrl->max_BitVariance_num)
+    {   //diff_counter_BTsrc = diff_counter_BTdst = 0;
+
+        if (curr_counter_diff > rateCtrl->max_BitVariance_num && diff_counter_BTdst)
+        {
+            diff_counter_BTdst = (rateCtrl->max_BitVariance_num - prev_counter_diff) + diff_counter_BTsrc;
+            if (diff_counter_BTdst < 0) diff_counter_BTdst = 0;
+        }
+
+        else if (curr_counter_diff < -rateCtrl->max_BitVariance_num && diff_counter_BTsrc)
+        {
+            diff_counter_BTsrc = diff_counter_BTdst - (-rateCtrl->max_BitVariance_num - prev_counter_diff);
+            if (diff_counter_BTsrc < 0) diff_counter_BTsrc = 0;
+        }
+    }
+
+
+    /*3.diff_counter_BTsrc, diff_counter_BTdst ==> TMN_TH */
+    rateCtrl->TMN_TH = (int)(pMP->target_bits_per_frame);
+    pMP->diff_counter = 0;
+
+    if (diff_counter_BTsrc)
+    {
+        rateCtrl->TMN_TH -= (int)(pMP->target_bits_per_frame * diff_counter_BTsrc * 0.1);
+        pMP->diff_counter = -diff_counter_BTsrc;
+    }
+    else if (diff_counter_BTdst)
+    {
+        rateCtrl->TMN_TH += (int)(pMP->target_bits_per_frame * diff_counter_BTdst * 0.1);
+        pMP->diff_counter = diff_counter_BTdst;
+    }
+
+
+    /*4.update pMP->counter_BTsrc, pMP->counter_BTdst */
+    pMP->counter_BTsrc += diff_counter_BTsrc;
+    pMP->counter_BTdst += diff_counter_BTdst;
+
+
+    /*5.target bit calculation */
+    rateCtrl->T = rateCtrl->TMN_TH - rateCtrl->TMN_W;
+
+    return ;
+}
+
+void updateRC_PostProc(AVCRateControl *rateCtrl, MultiPass *pMP)
+{
+    if (rateCtrl->skip_next_frame > 0) /* skip next frame */
+    {
+        pMP->counter_BTsrc += 10 * rateCtrl->skip_next_frame;
+
+    }
+    else if (rateCtrl->skip_next_frame == -1) /* skip current frame */
+    {
+        pMP->counter_BTdst -= pMP->diff_counter;
+        pMP->counter_BTsrc += 10;
+
+        pMP->sum_mad -= pMP->mad;
+        pMP->aver_mad = (pMP->aver_mad * pMP->encoded_frames - pMP->mad) / (pMP->encoded_frames - 1 + 0.0001);
+        pMP->sum_QP  -= pMP->QP;
+        pMP->encoded_frames --;
+    }
+    /* some stuff in update VBV_fullness remains here */
+    //if(rateCtrl->VBV_fullness < -rateCtrl->Bs/2) /* rateCtrl->Bs */
+    if (rateCtrl->VBV_fullness < rateCtrl->low_bound)
+    {
+        rateCtrl->VBV_fullness = rateCtrl->low_bound; // -rateCtrl->Bs/2;
+        rateCtrl->TMN_W = rateCtrl->VBV_fullness - rateCtrl->low_bound;
+        pMP->counter_BTsrc = pMP->counter_BTdst + (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
+    }
+}
+
+
+void RCInitChromaQP(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+    int q_bits;
+
+    /* we have to do the same thing for AVC_CLIP3(0,51,video->QSy) */
+
+    video->QPy_div_6 = (currMB->QPy * 43) >> 8;
+    video->QPy_mod_6 = currMB->QPy - 6 * video->QPy_div_6;
+    currMB->QPc = video->QPc = mapQPi2QPc[AVC_CLIP3(0, 51, currMB->QPy + video->currPicParams->chroma_qp_index_offset)];
+    video->QPc_div_6 = (video->QPc * 43) >> 8;
+    video->QPc_mod_6 = video->QPc - 6 * video->QPc_div_6;
+
+    /* pre-calculate this to save computation */
+    q_bits = 4 + video->QPy_div_6;
+    if (video->slice_type == AVC_I_SLICE)
+    {
+        encvid->qp_const = 682 << q_bits;       // intra
+    }
+    else
+    {
+        encvid->qp_const = 342 << q_bits;       // inter
+    }
+
+    q_bits = 4 + video->QPc_div_6;
+    if (video->slice_type == AVC_I_SLICE)
+    {
+        encvid->qp_const_c = 682 << q_bits;    // intra
+    }
+    else
+    {
+        encvid->qp_const_c = 342 << q_bits;    // inter
+    }
+
+    encvid->lambda_mode = QP2QUANT[AVC_MAX(0, currMB->QPy-SHIFT_QP)];
+    encvid->lambda_motion = LAMBDA_FACTOR(encvid->lambda_mode);
+
+    return ;
+}
+
+
+void RCInitMBQP(AVCEncObject *encvid)
+{
+    AVCCommonObj *video =  encvid->common;
+    AVCMacroblock *currMB = video->currMB;
+
+    currMB->QPy = video->QPy; /* set to previous value or picture level */
+
+    RCInitChromaQP(encvid);
+
+}
+
+void RCPostMB(AVCCommonObj *video, AVCRateControl *rateCtrl, int num_header_bits, int num_texture_bits)
+{
+    OSCL_UNUSED_ARG(video);
+    rateCtrl->numMBHeaderBits = num_header_bits;
+    rateCtrl->numMBTextureBits = num_texture_bits;
+    rateCtrl->NumberofHeaderBits += rateCtrl->numMBHeaderBits;
+    rateCtrl->NumberofTextureBits += rateCtrl->numMBTextureBits;
+}
+
+void RCRestoreQP(AVCMacroblock *currMB, AVCCommonObj *video, AVCEncObject *encvid)
+{
+    currMB->QPy = video->QPy; /* use previous QP */
+    RCInitChromaQP(encvid);
+
+    return ;
+}
+
+
+void RCCalculateMAD(AVCEncObject *encvid, AVCMacroblock *currMB, uint8 *orgL, int orgPitch)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    uint32 dmin_lx;
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        if (currMB->mb_intra)
+        {
+            if (currMB->mbMode == AVC_I16)
+            {
+                dmin_lx = (0xFFFF << 16) | orgPitch;
+                rateCtrl->MADofMB[video->mbNum] = AVCSAD_Macroblock_C(orgL,
+                                                  encvid->pred_i16[currMB->i16Mode], dmin_lx, NULL);
+            }
+            else /* i4 */
+            {
+                rateCtrl->MADofMB[video->mbNum] = encvid->i4_sad / 256.;
+            }
+        }
+        /* for INTER, we have already saved it with the MV search */
+    }
+
+    return ;
+}
+
+
+
+AVCEnc_Status RCUpdateFrame(AVCEncObject *encvid)
+{
+    AVCCommonObj *video = encvid->common;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    MultiPass *pMP = rateCtrl->pMP;
+    int diff_BTCounter;
+    int nal_type = video->nal_unit_type;
+
+    /* update the complexity weight of I, P, B frame */
+
+    if (rateCtrl->rcEnable == TRUE)
+    {
+        pMP->actual_bits = rateCtrl->numFrameBits;
+        pMP->mad = (OsclFloat)rateCtrl->totalSAD / video->PicSizeInMbs; //ComputeFrameMAD(video, rateCtrl);
+
+        AVCSaveRDSamples(pMP, 0);
+
+        pMP->encoded_frames++;
+
+        /* for pMP->samplesPerFrame */
+        pMP->samplesPerFrame[pMP->framePos] = 0;
+
+        pMP->sum_QP += pMP->QP;
+
+        /* update pMP->counter_BTsrc, pMP->counter_BTdst */
+        /* re-allocate the target bit again and then stop encoding */
+        diff_BTCounter = (int)((OsclFloat)(rateCtrl->TMN_TH - rateCtrl->TMN_W - pMP->actual_bits) /
+                               (pMP->bitrate / (pMP->framerate + 0.0001) + 0.0001) / 0.1);
+        if (diff_BTCounter >= 0)
+            pMP->counter_BTsrc += diff_BTCounter; /* pMP->actual_bits is smaller */
+        else
+            pMP->counter_BTdst -= diff_BTCounter; /* pMP->actual_bits is bigger */
+
+        rateCtrl->TMN_TH -= (int)((OsclFloat)pMP->bitrate / (pMP->framerate + 0.0001) * (diff_BTCounter * 0.1));
+        rateCtrl->T = pMP->target_bits = rateCtrl->TMN_TH - rateCtrl->TMN_W;
+        pMP->diff_counter -= diff_BTCounter;
+
+        rateCtrl->Rc = rateCtrl->numFrameBits;  /* Total Bits for current frame */
+        rateCtrl->Hc = rateCtrl->NumberofHeaderBits;    /* Total Bits in Header and Motion Vector */
+
+        /* BX_RC */
+        updateRateControl(rateCtrl, nal_type);
+        if (rateCtrl->skip_next_frame == -1) // skip current frame
+        {
+            status = AVCENC_SKIPPED_PICTURE;
+        }
+    }
+
+    rateCtrl->first_frame = 0;  // reset here after we encode the first frame.
+
+    return status;
+}
+
+void AVCSaveRDSamples(MultiPass *pMP, int counter_samples)
+{
+    /* for pMP->pRDSamples */
+    pMP->pRDSamples[pMP->framePos][counter_samples].QP    = pMP->QP;
+    pMP->pRDSamples[pMP->framePos][counter_samples].actual_bits = pMP->actual_bits;
+    pMP->pRDSamples[pMP->framePos][counter_samples].mad   = pMP->mad;
+    pMP->pRDSamples[pMP->framePos][counter_samples].R_D = (OsclFloat)pMP->actual_bits / (pMP->mad + 0.0001);
+
+    return ;
+}
+
+void updateRateControl(AVCRateControl *rateCtrl, int nal_type)
+{
+    int  frame_bits;
+    MultiPass *pMP = rateCtrl->pMP;
+
+    /* BX rate contro\l */
+    frame_bits = (int)(rateCtrl->bitRate / rateCtrl->frame_rate);
+    rateCtrl->TMN_W += (rateCtrl->Rc - rateCtrl->TMN_TH);
+    rateCtrl->VBV_fullness += (rateCtrl->Rc - frame_bits); //rateCtrl->Rp);
+    //if(rateCtrl->VBV_fullness < 0) rateCtrl->VBV_fullness = -1;
+
+    rateCtrl->encoded_frames++;
+
+    /* frame dropping */
+    rateCtrl->skip_next_frame = 0;
+
+    if ((rateCtrl->VBV_fullness > rateCtrl->Bs / 2) && nal_type != AVC_NALTYPE_IDR) /* skip the current frame */ /* rateCtrl->Bs */
+    {
+        rateCtrl->TMN_W -= (rateCtrl->Rc - rateCtrl->TMN_TH);
+        rateCtrl->VBV_fullness -= rateCtrl->Rc;
+        rateCtrl->skip_next_frame = -1;
+    }
+    else if ((OsclFloat)(rateCtrl->VBV_fullness - rateCtrl->VBV_fullness_offset) > (rateCtrl->Bs / 2 - rateCtrl->VBV_fullness_offset)*0.95) /* skip next frame */
+    {
+        rateCtrl->VBV_fullness -= frame_bits; //rateCtrl->Rp;
+        rateCtrl->skip_next_frame = 1;
+        pMP->counter_BTsrc -= (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
+        /* BX_1, skip more than 1 frames  */
+        //while(rateCtrl->VBV_fullness > rateCtrl->Bs*0.475)
+        while ((rateCtrl->VBV_fullness - rateCtrl->VBV_fullness_offset) > (rateCtrl->Bs / 2 - rateCtrl->VBV_fullness_offset)*0.95)
+        {
+            rateCtrl->VBV_fullness -= frame_bits; //rateCtrl->Rp;
+            rateCtrl->skip_next_frame++;
+            pMP->counter_BTsrc -= (int)((OsclFloat)(rateCtrl->Bs / 2 - rateCtrl->low_bound) / 2.0 / (pMP->target_bits_per_frame / 10));
+        }
+
+        /* END BX_1 */
+    }
+}
+
+
+double ComputeFrameMAD(AVCCommonObj *video, AVCRateControl *rateCtrl)
+{
+    double TotalMAD;
+    int i;
+    TotalMAD = 0.0;
+    for (i = 0; i < (int)video->PicSizeInMbs; i++)
+        TotalMAD += rateCtrl->MADofMB[i];
+    TotalMAD /= video->PicSizeInMbs;
+    return TotalMAD;
+}
+
+
+
+
+
+/* convert from QP to Qstep */
+double QP2Qstep(int QP)
+{
+    int i;
+    double Qstep;
+    static const double QP2QSTEP[6] = { 0.625, 0.6875, 0.8125, 0.875, 1.0, 1.125 };
+
+    Qstep = QP2QSTEP[QP % 6];
+    for (i = 0; i < (QP / 6); i++)
+        Qstep *= 2;
+
+    return Qstep;
+}
+
+/* convert from step size to QP */
+int Qstep2QP(double Qstep)
+{
+    int q_per = 0, q_rem = 0;
+
+    //  assert( Qstep >= QP2Qstep(0) && Qstep <= QP2Qstep(51) );
+    if (Qstep < QP2Qstep(0))
+        return 0;
+    else if (Qstep > QP2Qstep(51))
+        return 51;
+
+    while (Qstep > QP2Qstep(5))
+    {
+        Qstep /= 2;
+        q_per += 1;
+    }
+
+    if (Qstep <= (0.625 + 0.6875) / 2)
+    {
+        Qstep = 0.625;
+        q_rem = 0;
+    }
+    else if (Qstep <= (0.6875 + 0.8125) / 2)
+    {
+        Qstep = 0.6875;
+        q_rem = 1;
+    }
+    else if (Qstep <= (0.8125 + 0.875) / 2)
+    {
+        Qstep = 0.8125;
+        q_rem = 2;
+    }
+    else if (Qstep <= (0.875 + 1.0) / 2)
+    {
+        Qstep = 0.875;
+        q_rem = 3;
+    }
+    else if (Qstep <= (1.0 + 1.125) / 2)
+    {
+        Qstep = 1.0;
+        q_rem = 4;
+    }
+    else
+    {
+        Qstep = 1.125;
+        q_rem = 5;
+    }
+
+    return (q_per * 6 + q_rem);
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/residual.cpp b/media/libstagefright/codecs/avc/enc/src/residual.cpp
new file mode 100644
index 0000000..42eb910
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/residual.cpp
@@ -0,0 +1,389 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+
+AVCEnc_Status EncodeIntraPCM(AVCEncObject *encvid)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCCommonObj *video = encvid->common;
+    AVCFrameIO  *currInput = encvid->currInput;
+    AVCEncBitstream *stream = encvid->bitstream;
+    int x_position = (video->mb_x << 4);
+    int y_position = (video->mb_y << 4);
+    int orgPitch = currInput->pitch;
+    int offset1 = y_position * orgPitch + x_position;
+    int i, j;
+    int offset;
+    uint8 *pDst, *pSrc;
+    uint code;
+
+    ue_v(stream, 25);
+
+    i = stream->bit_left & 0x7;
+    if (i) /* not byte-aligned */
+    {
+        BitstreamWriteBits(stream, 0, i);
+    }
+
+    pSrc = currInput->YCbCr[0] + offset1;
+    pDst = video->currPic->Sl + offset1;
+    offset = video->PicWidthInSamplesL - 16;
+
+    /* at this point bitstream is byte-aligned */
+    j = 16;
+    while (j > 0)
+    {
+#if (WORD_SIZE==32)
+        for (i = 0; i < 4; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 4;
+            *((uint*)pDst) = code;
+            pDst += 4;
+            status = BitstreamWriteBits(stream, 32, code);
+        }
+#else
+        for (i = 0; i < 8; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 2;
+            *((uint*)pDst) = code;
+            pDst += 2;
+            status = BitstreamWriteBits(stream, 16, code);
+        }
+#endif
+        pDst += offset;
+        pSrc += offset;
+        j--;
+    }
+    if (status != AVCENC_SUCCESS)  /* check only once per line */
+        return status;
+
+    pDst = video->currPic->Scb + ((offset1 + x_position) >> 2);
+    pSrc = currInput->YCbCr[1] + ((offset1 + x_position) >> 2);
+    offset >>= 1;
+
+    j = 8;
+    while (j > 0)
+    {
+#if (WORD_SIZE==32)
+        for (i = 0; i < 2; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 4;
+            *((uint*)pDst) = code;
+            pDst += 4;
+            status = BitstreamWriteBits(stream, 32, code);
+        }
+#else
+        for (i = 0; i < 4; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 2;
+            *((uint*)pDst) = code;
+            pDst += 2;
+            status = BitstreamWriteBits(stream, 16, code);
+        }
+#endif
+        pDst += offset;
+        pSrc += offset;
+        j--;
+    }
+
+    if (status != AVCENC_SUCCESS)  /* check only once per line */
+        return status;
+
+    pDst = video->currPic->Scr + ((offset1 + x_position) >> 2);
+    pSrc = currInput->YCbCr[2] + ((offset1 + x_position) >> 2);
+
+    j = 8;
+    while (j > 0)
+    {
+#if (WORD_SIZE==32)
+        for (i = 0; i < 2; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 4;
+            *((uint*)pDst) = code;
+            pDst += 4;
+            status = BitstreamWriteBits(stream, 32, code);
+        }
+#else
+        for (i = 0; i < 4; i++)
+        {
+            code = *((uint*)pSrc);
+            pSrc += 2;
+            *((uint*)pDst) = code;
+            pDst += 2;
+            status = BitstreamWriteBits(stream, 16, code);
+        }
+#endif
+        pDst += offset;
+        pSrc += offset;
+        j--;
+    }
+
+    return status;
+}
+
+
+AVCEnc_Status enc_residual_block(AVCEncObject *encvid, AVCResidualType type, int cindx, AVCMacroblock *currMB)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCCommonObj *video = encvid->common;
+    int i, maxNumCoeff, nC;
+    int cdc = 0, cac = 0;
+    int TrailingOnes;
+    AVCEncBitstream *stream = encvid->bitstream;
+    uint trailing_ones_sign_flag;
+    int zerosLeft;
+    int *level, *run;
+    int TotalCoeff;
+    const static int incVlc[] = {0, 3, 6, 12, 24, 48, 32768};  // maximum vlc = 6
+    int escape, numPrefix, sufmask, suffix, shift, sign, value, absvalue, vlcnum, level_two_or_higher;
+    int bindx = blkIdx2blkXY[cindx>>2][cindx&3] ; // raster scan index
+
+    switch (type)
+    {
+        case AVC_Luma:
+            maxNumCoeff = 16;
+            level = encvid->level[cindx];
+            run = encvid->run[cindx];
+            TotalCoeff = currMB->nz_coeff[bindx];
+            break;
+        case AVC_Intra16DC:
+            maxNumCoeff = 16;
+            level = encvid->leveldc;
+            run = encvid->rundc;
+            TotalCoeff = cindx; /* special case */
+            bindx = 0;
+            cindx = 0;
+            break;
+        case AVC_Intra16AC:
+            maxNumCoeff = 15;
+            level = encvid->level[cindx];
+            run = encvid->run[cindx];
+            TotalCoeff = currMB->nz_coeff[bindx];
+            break;
+        case AVC_ChromaDC:  /* how to differentiate Cb from Cr */
+            maxNumCoeff = 4;
+            cdc = 1;
+            if (cindx >= 8)
+            {
+                level = encvid->levelcdc + 4;
+                run = encvid->runcdc + 4;
+                TotalCoeff = cindx - 8;  /* special case */
+            }
+            else
+            {
+                level = encvid->levelcdc;
+                run = encvid->runcdc;
+                TotalCoeff = cindx;  /* special case */
+            }
+            break;
+        case AVC_ChromaAC:
+            maxNumCoeff = 15;
+            cac = 1;
+            level = encvid->level[cindx];
+            run = encvid->run[cindx];
+            cindx -= 16;
+            bindx = 16 + blkIdx2blkXY[cindx>>2][cindx&3];
+            cindx += 16;
+            TotalCoeff = currMB->nz_coeff[bindx];
+            break;
+        default:
+            return AVCENC_FAIL;
+    }
+
+
+    /* find TrailingOnes */
+    TrailingOnes = 0;
+    zerosLeft = 0;
+    i = TotalCoeff - 1;
+    nC = 1;
+    while (i >= 0)
+    {
+        zerosLeft += run[i];
+        if (nC && (level[i] == 1 || level[i] == -1))
+        {
+            TrailingOnes++;
+        }
+        else
+        {
+            nC = 0;
+        }
+        i--;
+    }
+    if (TrailingOnes > 3)
+    {
+        TrailingOnes = 3; /* clip it */
+    }
+
+    if (!cdc)
+    {
+        if (!cac)  /* not chroma */
+        {
+            nC = predict_nnz(video, bindx & 3, bindx >> 2);
+        }
+        else /* chroma ac but not chroma dc */
+        {
+            nC = predict_nnz_chroma(video, bindx & 3, bindx >> 2);
+        }
+
+        status = ce_TotalCoeffTrailingOnes(stream, TrailingOnes, TotalCoeff, nC);
+    }
+    else
+    {
+        nC = -1; /* Chroma DC level */
+        status = ce_TotalCoeffTrailingOnesChromaDC(stream, TrailingOnes, TotalCoeff);
+    }
+
+    /* This part is done quite differently in ReadCoef4x4_CAVLC() */
+    if (TotalCoeff > 0)
+    {
+
+        i = TotalCoeff - 1;
+
+        if (TrailingOnes) /* keep reading the sign of those trailing ones */
+        {
+            nC = TrailingOnes;
+            trailing_ones_sign_flag = 0;
+            while (nC)
+            {
+                trailing_ones_sign_flag <<= 1;
+                trailing_ones_sign_flag |= ((uint32)level[i--] >> 31); /* 0 or positive, 1 for negative */
+                nC--;
+            }
+
+            /* instead of writing one bit at a time, read the whole thing at once */
+            status = BitstreamWriteBits(stream, TrailingOnes, trailing_ones_sign_flag);
+        }
+
+        level_two_or_higher = 1;
+        if (TotalCoeff > 3 && TrailingOnes == 3)
+        {
+            level_two_or_higher = 0;
+        }
+
+        if (TotalCoeff > 10 && TrailingOnes < 3)
+        {
+            vlcnum = 1;
+        }
+        else
+        {
+            vlcnum = 0;
+        }
+
+        /* then do this TotalCoeff-TrailingOnes times */
+        for (i = TotalCoeff - TrailingOnes - 1; i >= 0; i--)
+        {
+            value = level[i];
+            absvalue = (value >= 0) ? value : -value;
+
+            if (level_two_or_higher)
+            {
+                if (value > 0) value--;
+                else    value++;
+                level_two_or_higher = 0;
+            }
+
+            if (value >= 0)
+            {
+                sign = 0;
+            }
+            else
+            {
+                sign = 1;
+                value = -value;
+            }
+
+            if (vlcnum == 0) // VLC1
+            {
+                if (value < 8)
+                {
+                    status = BitstreamWriteBits(stream, value * 2 + sign - 1, 1);
+                }
+                else if (value < 8 + 8)
+                {
+                    status = BitstreamWriteBits(stream, 14 + 1 + 4, (1 << 4) | ((value - 8) << 1) | sign);
+                }
+                else
+                {
+                    status = BitstreamWriteBits(stream, 14 + 2 + 12, (1 << 12) | ((value - 16) << 1) | sign) ;
+                }
+            }
+            else  // VLCN
+            {
+                shift = vlcnum - 1;
+                escape = (15 << shift) + 1;
+                numPrefix = (value - 1) >> shift;
+                sufmask = ~((0xffffffff) << shift);
+                suffix = (value - 1) & sufmask;
+                if (value < escape)
+                {
+                    status = BitstreamWriteBits(stream, numPrefix + vlcnum + 1, (1 << (shift + 1)) | (suffix << 1) | sign);
+                }
+                else
+                {
+                    status = BitstreamWriteBits(stream, 28, (1 << 12) | ((value - escape) << 1) | sign);
+                }
+
+            }
+
+            if (absvalue > incVlc[vlcnum])
+                vlcnum++;
+
+            if (i == TotalCoeff - TrailingOnes - 1 && absvalue > 3)
+                vlcnum = 2;
+        }
+
+        if (status != AVCENC_SUCCESS)  /* occasionally check the bitstream */
+        {
+            return status;
+        }
+        if (TotalCoeff < maxNumCoeff)
+        {
+            if (!cdc)
+            {
+                ce_TotalZeros(stream, zerosLeft, TotalCoeff);
+            }
+            else
+            {
+                ce_TotalZerosChromaDC(stream, zerosLeft, TotalCoeff);
+            }
+        }
+        else
+        {
+            zerosLeft = 0;
+        }
+
+        i = TotalCoeff - 1;
+        while (i > 0) /* don't do the last one */
+        {
+            if (zerosLeft > 0)
+            {
+                ce_RunBefore(stream, run[i], zerosLeft);
+            }
+
+            zerosLeft = zerosLeft - run[i];
+            i--;
+        }
+    }
+
+    return status;
+}
diff --git a/media/libstagefright/codecs/avc/enc/src/sad.cpp b/media/libstagefright/codecs/avc/enc/src/sad.cpp
new file mode 100644
index 0000000..ae7acd2
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad.cpp
@@ -0,0 +1,290 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+#include "sad_inline.h"
+
+#define Cached_lx 176
+
+#ifdef _SAD_STAT
+uint32 num_sad_MB = 0;
+uint32 num_sad_Blk = 0;
+uint32 num_sad_MB_call = 0;
+uint32 num_sad_Blk_call = 0;
+
+#define NUM_SAD_MB_CALL()       num_sad_MB_call++
+#define NUM_SAD_MB()            num_sad_MB++
+#define NUM_SAD_BLK_CALL()      num_sad_Blk_call++
+#define NUM_SAD_BLK()           num_sad_Blk++
+
+#else
+
+#define NUM_SAD_MB_CALL()
+#define NUM_SAD_MB()
+#define NUM_SAD_BLK_CALL()
+#define NUM_SAD_BLK()
+
+#endif
+
+
+/* consist of
+int AVCSAD_Macroblock_C(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
+int AVCSAD_MB_HTFM_Collect(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
+int AVCSAD_MB_HTFM(uint8 *ref,uint8 *blk,int dmin,int lx,void *extra_info)
+*/
+
+
+/*==================================================================
+    Function:   SAD_Macroblock
+    Date:       09/07/2000
+    Purpose:    Compute SAD 16x16 between blk and ref.
+    To do:      Uniform subsampling will be inserted later!
+                Hypothesis Testing Fast Matching to be used later!
+    Changes:
+    11/7/00:    implemented MMX
+    1/24/01:    implemented SSE
+==================================================================*/
+/********** C ************/
+int AVCSAD_Macroblock_C(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
+{
+    (void)(extra_info);
+
+    int32 x10;
+    int dmin = (uint32)dmin_lx >> 16;
+    int lx = dmin_lx & 0xFFFF;
+
+    NUM_SAD_MB_CALL();
+
+    x10 = simd_sad_mb(ref, blk, dmin, lx);
+
+    return x10;
+}
+
+#ifdef HTFM   /* HTFM with uniform subsampling implementation 2/28/01 */
+/*===============================================================
+    Function:   AVCAVCSAD_MB_HTFM_Collect and AVCSAD_MB_HTFM
+    Date:       3/2/1
+    Purpose:    Compute the SAD on a 16x16 block using
+                uniform subsampling and hypothesis testing fast matching
+                for early dropout. SAD_MB_HP_HTFM_Collect is to collect
+                the statistics to compute the thresholds to be used in
+                SAD_MB_HP_HTFM.
+    Input/Output:
+    Changes:
+  ===============================================================*/
+
+int AVCAVCSAD_MB_HTFM_Collect(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
+{
+    int i;
+    int sad = 0;
+    uint8 *p1;
+    int lx4 = (dmin_lx << 2) & 0x3FFFC;
+    uint32 cur_word;
+    int saddata[16], tmp, tmp2;    /* used when collecting flag (global) is on */
+    int difmad;
+    int madstar;
+    HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
+    int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
+    uint *countbreak = &(htfm_stat->countbreak);
+    int *offsetRef = htfm_stat->offsetRef;
+
+    madstar = (uint32)dmin_lx >> 20;
+
+    NUM_SAD_MB_CALL();
+
+    blk -= 4;
+    for (i = 0; i < 16; i++)
+    {
+        p1 = ref + offsetRef[i];
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        NUM_SAD_MB();
+
+        saddata[i] = sad;
+
+        if (i > 0)
+        {
+            if ((uint32)sad > ((uint32)dmin_lx >> 16))
+            {
+                difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+                (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+                (*countbreak)++;
+                return sad;
+            }
+        }
+    }
+
+    difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+    (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+    (*countbreak)++;
+    return sad;
+}
+
+int AVCSAD_MB_HTFM(uint8 *ref, uint8 *blk, int dmin_lx, void *extra_info)
+{
+    int sad = 0;
+    uint8 *p1;
+
+    int i;
+    int tmp, tmp2;
+    int lx4 = (dmin_lx << 2) & 0x3FFFC;
+    int sadstar = 0, madstar;
+    int *nrmlz_th = (int*) extra_info;
+    int *offsetRef = (int*) extra_info + 32;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_lx >> 20;
+
+    NUM_SAD_MB_CALL();
+
+    blk -= 4;
+    for (i = 0; i < 16; i++)
+    {
+        p1 = ref + offsetRef[i];
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        cur_word = *((uint32*)(blk += 4));
+        tmp = p1[12];
+        tmp2 = (cur_word >> 24) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[8];
+        tmp2 = (cur_word >> 16) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[4];
+        tmp2 = (cur_word >> 8) & 0xFF;
+        sad = SUB_SAD(sad, tmp, tmp2);
+        tmp = p1[0];
+        p1 += lx4;
+        tmp2 = (cur_word & 0xFF);
+        sad = SUB_SAD(sad, tmp, tmp2);
+
+        NUM_SAD_MB();
+
+        sadstar += madstar;
+        if (((uint32)sad <= ((uint32)dmin_lx >> 16)) && (sad <= (sadstar - *nrmlz_th++)))
+            ;
+        else
+            return 65536;
+    }
+
+    return sad;
+}
+#endif /* HTFM */
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_halfpel.cpp b/media/libstagefright/codecs/avc/enc/src/sad_halfpel.cpp
new file mode 100644
index 0000000..faf2198
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad_halfpel.cpp
@@ -0,0 +1,629 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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.
+ * -------------------------------------------------------------------
+ */
+/* contains
+int AVCHalfPel1_SAD_MB(uint8 *ref,uint8 *blk,int dmin,int width,int ih,int jh)
+int AVCHalfPel2_SAD_MB(uint8 *ref,uint8 *blk,int dmin,int width)
+int AVCHalfPel1_SAD_Blk(uint8 *ref,uint8 *blk,int dmin,int width,int ih,int jh)
+int AVCHalfPel2_SAD_Blk(uint8 *ref,uint8 *blk,int dmin,int width)
+
+int AVCSAD_MB_HalfPel_C(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
+int AVCSAD_MB_HP_HTFM_Collect(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
+int AVCSAD_MB_HP_HTFM(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
+int AVCSAD_Blk_HalfPel_C(uint8 *ref,uint8 *blk,int dmin,int width,int rx,int xh,int yh,void *extra_info)
+*/
+
+#include "avcenc_lib.h"
+#include "sad_halfpel_inline.h"
+
+#ifdef _SAD_STAT
+uint32 num_sad_HP_MB = 0;
+uint32 num_sad_HP_Blk = 0;
+uint32 num_sad_HP_MB_call = 0;
+uint32 num_sad_HP_Blk_call = 0;
+#define NUM_SAD_HP_MB_CALL()    num_sad_HP_MB_call++
+#define NUM_SAD_HP_MB()         num_sad_HP_MB++
+#define NUM_SAD_HP_BLK_CALL()   num_sad_HP_Blk_call++
+#define NUM_SAD_HP_BLK()        num_sad_HP_Blk++
+#else
+#define NUM_SAD_HP_MB_CALL()
+#define NUM_SAD_HP_MB()
+#define NUM_SAD_HP_BLK_CALL()
+#define NUM_SAD_HP_BLK()
+#endif
+
+
+
+/*===============================================================
+    Function:   SAD_MB_HalfPel
+    Date:       09/17/2000
+    Purpose:    Compute the SAD on the half-pel resolution
+    Input/Output:   hmem is assumed to be a pointer to the starting
+                point of the search in the 33x33 matrix search region
+    Changes:
+    11/7/00:    implemented MMX
+  ===============================================================*/
+/*==================================================================
+    Function:   AVCSAD_MB_HalfPel_C
+    Date:       04/30/2001
+    Purpose:    Compute SAD 16x16 between blk and ref in halfpel
+                resolution,
+    Changes:
+  ==================================================================*/
+/* One component is half-pel */
+int AVCSAD_MB_HalfPel_Cxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    (void)(extra_info);
+
+    int i, j;
+    int sad = 0;
+    uint8 *kk, *p1, *p2, *p3, *p4;
+//  int sumref=0;
+    int temp;
+    int rx = dmin_rx & 0xFFFF;
+
+    NUM_SAD_HP_MB_CALL();
+
+    p1 = ref;
+    p2 = ref + 1;
+    p3 = ref + rx;
+    p4 = ref + rx + 1;
+    kk  = blk;
+
+    for (i = 0; i < 16; i++)
+    {
+        for (j = 0; j < 16; j++)
+        {
+
+            temp = ((p1[j] + p2[j] + p3[j] + p4[j] + 2) >> 2) - *kk++;
+            sad += AVC_ABS(temp);
+        }
+
+        NUM_SAD_HP_MB();
+
+        if (sad > (int)((uint32)dmin_rx >> 16))
+            return sad;
+
+        p1 += rx;
+        p3 += rx;
+        p2 += rx;
+        p4 += rx;
+    }
+    return sad;
+}
+
+int AVCSAD_MB_HalfPel_Cyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    (void)(extra_info);
+
+    int i, j;
+    int sad = 0;
+    uint8 *kk, *p1, *p2;
+//  int sumref=0;
+    int temp;
+    int rx = dmin_rx & 0xFFFF;
+
+    NUM_SAD_HP_MB_CALL();
+
+    p1 = ref;
+    p2 = ref + rx; /* either left/right or top/bottom pixel */
+    kk  = blk;
+
+    for (i = 0; i < 16; i++)
+    {
+        for (j = 0; j < 16; j++)
+        {
+
+            temp = ((p1[j] + p2[j] + 1) >> 1) - *kk++;
+            sad += AVC_ABS(temp);
+        }
+
+        NUM_SAD_HP_MB();
+
+        if (sad > (int)((uint32)dmin_rx >> 16))
+            return sad;
+        p1 += rx;
+        p2 += rx;
+    }
+    return sad;
+}
+
+int AVCSAD_MB_HalfPel_Cxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    (void)(extra_info);
+
+    int i, j;
+    int sad = 0;
+    uint8 *kk, *p1;
+    int temp;
+    int rx = dmin_rx & 0xFFFF;
+
+    NUM_SAD_HP_MB_CALL();
+
+    p1 = ref;
+    kk  = blk;
+
+    for (i = 0; i < 16; i++)
+    {
+        for (j = 0; j < 16; j++)
+        {
+
+            temp = ((p1[j] + p1[j+1] + 1) >> 1) - *kk++;
+            sad += AVC_ABS(temp);
+        }
+
+        NUM_SAD_HP_MB();
+
+        if (sad > (int)((uint32)dmin_rx >> 16))
+            return sad;
+        p1 += rx;
+    }
+    return sad;
+}
+
+#ifdef HTFM  /* HTFM with uniform subsampling implementation,  2/28/01 */
+
+//Checheck here
+int AVCAVCSAD_MB_HP_HTFM_Collectxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0;
+    uint8 *p1, *p2;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int saddata[16];      /* used when collecting flag (global) is on */
+    int difmad, tmp, tmp2;
+    int madstar;
+    HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
+    int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
+    UInt *countbreak = &(htfm_stat->countbreak);
+    int *offsetRef = htfm_stat->offsetRef;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+        p2 = p1 + rx;
+
+        j = 4;/* 4 lines */
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12] + p2[12];
+            tmp2 = p1[13] + p2[13];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 24) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8] + p2[8];
+            tmp2 = p1[9] + p2[9];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 16) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4] + p2[4];
+            tmp2 = p1[5] + p2[5];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 8) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp2 = p1[1] + p2[1];
+            tmp = p1[0] + p2[0];
+            p1 += refwx4;
+            p2 += refwx4;
+            tmp += tmp2;
+            tmp2 = (cur_word & 0xFF);
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        saddata[i] = sad;
+
+        if (i > 0)
+        {
+            if (sad > ((uint32)dmin_rx >> 16))
+            {
+                difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+                (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+                (*countbreak)++;
+                return sad;
+            }
+        }
+    }
+    difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+    (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+    (*countbreak)++;
+
+    return sad;
+}
+
+int AVCAVCSAD_MB_HP_HTFM_Collectyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0;
+    uint8 *p1, *p2;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int saddata[16];      /* used when collecting flag (global) is on */
+    int difmad, tmp, tmp2;
+    int madstar;
+    HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
+    int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
+    UInt *countbreak = &(htfm_stat->countbreak);
+    int *offsetRef = htfm_stat->offsetRef;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+        p2 = p1 + rx;
+        j = 4;
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12];
+            tmp2 = p2[12];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 24) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8];
+            tmp2 = p2[8];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 16) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4];
+            tmp2 = p2[4];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 8) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[0];
+            p1 += refwx4;
+            tmp2 = p2[0];
+            p2 += refwx4;
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word & 0xFF);
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        saddata[i] = sad;
+
+        if (i > 0)
+        {
+            if (sad > ((uint32)dmin_rx >> 16))
+            {
+                difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+                (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+                (*countbreak)++;
+                return sad;
+            }
+        }
+    }
+    difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+    (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+    (*countbreak)++;
+
+    return sad;
+}
+
+int AVCAVCSAD_MB_HP_HTFM_Collectxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0;
+    uint8 *p1;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int saddata[16];      /* used when collecting flag (global) is on */
+    int difmad, tmp, tmp2;
+    int madstar;
+    HTFM_Stat *htfm_stat = (HTFM_Stat*) extra_info;
+    int *abs_dif_mad_avg = &(htfm_stat->abs_dif_mad_avg);
+    UInt *countbreak = &(htfm_stat->countbreak);
+    int *offsetRef = htfm_stat->offsetRef;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+
+        j = 4; /* 4 lines */
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12];
+            tmp2 = p1[13];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 24) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8];
+            tmp2 = p1[9];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 16) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4];
+            tmp2 = p1[5];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 8) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[0];
+            tmp2 = p1[1];
+            p1 += refwx4;
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word & 0xFF);
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        saddata[i] = sad;
+
+        if (i > 0)
+        {
+            if (sad > ((uint32)dmin_rx >> 16))
+            {
+                difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+                (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+                (*countbreak)++;
+                return sad;
+            }
+        }
+    }
+    difmad = saddata[0] - ((saddata[1] + 1) >> 1);
+    (*abs_dif_mad_avg) += ((difmad > 0) ? difmad : -difmad);
+    (*countbreak)++;
+
+    return sad;
+}
+
+int AVCSAD_MB_HP_HTFMxhyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0, tmp, tmp2;
+    uint8 *p1, *p2;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int sadstar = 0, madstar;
+    int *nrmlz_th = (int*) extra_info;
+    int *offsetRef = nrmlz_th + 32;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+        p2 = p1 + rx;
+
+        j = 4; /* 4 lines */
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12] + p2[12];
+            tmp2 = p1[13] + p2[13];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 24) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8] + p2[8];
+            tmp2 = p1[9] + p2[9];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 16) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4] + p2[4];
+            tmp2 = p1[5] + p2[5];
+            tmp += tmp2;
+            tmp2 = (cur_word >> 8) & 0xFF;
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+            tmp2 = p1[1] + p2[1];
+            tmp = p1[0] + p2[0];
+            p1 += refwx4;
+            p2 += refwx4;
+            tmp += tmp2;
+            tmp2 = (cur_word & 0xFF);
+            tmp += 2;
+            sad = INTERP2_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        sadstar += madstar;
+        if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
+        {
+            return 65536;
+        }
+    }
+
+    return sad;
+}
+
+int AVCSAD_MB_HP_HTFMyh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0, tmp, tmp2;
+    uint8 *p1, *p2;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int sadstar = 0, madstar;
+    int *nrmlz_th = (int*) extra_info;
+    int *offsetRef = nrmlz_th + 32;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+        p2 = p1 + rx;
+        j = 4;
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12];
+            tmp2 = p2[12];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 24) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8];
+            tmp2 = p2[8];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 16) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4];
+            tmp2 = p2[4];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 8) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[0];
+            p1 += refwx4;
+            tmp2 = p2[0];
+            p2 += refwx4;
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word & 0xFF);
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+        sadstar += madstar;
+        if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
+        {
+            return 65536;
+        }
+    }
+
+    return sad;
+}
+
+int AVCSAD_MB_HP_HTFMxh(uint8 *ref, uint8 *blk, int dmin_rx, void *extra_info)
+{
+    int i, j;
+    int sad = 0, tmp, tmp2;
+    uint8 *p1;
+    int rx = dmin_rx & 0xFFFF;
+    int refwx4 = rx << 2;
+    int sadstar = 0, madstar;
+    int *nrmlz_th = (int*) extra_info;
+    int *offsetRef = nrmlz_th + 32;
+    uint32 cur_word;
+
+    madstar = (uint32)dmin_rx >> 20;
+
+    NUM_SAD_HP_MB_CALL();
+
+    blk -= 4;
+
+    for (i = 0; i < 16; i++) /* 16 stages */
+    {
+        p1 = ref + offsetRef[i];
+
+        j = 4;/* 4 lines */
+        do
+        {
+            cur_word = *((uint32*)(blk += 4));
+            tmp = p1[12];
+            tmp2 = p1[13];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 24) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[8];
+            tmp2 = p1[9];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 16) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[4];
+            tmp2 = p1[5];
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word >> 8) & 0xFF;
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+            tmp = p1[0];
+            tmp2 = p1[1];
+            p1 += refwx4;
+            tmp++;
+            tmp2 += tmp;
+            tmp = (cur_word & 0xFF);
+            sad = INTERP1_SUB_SAD(sad, tmp, tmp2);;
+        }
+        while (--j);
+
+        NUM_SAD_HP_MB();
+
+        sadstar += madstar;
+        if (sad > sadstar - nrmlz_th[i] || sad > ((uint32)dmin_rx >> 16))
+        {
+            return 65536;
+        }
+    }
+
+    return sad;
+}
+
+#endif /* HTFM */
+
+
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h b/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
new file mode 100644
index 0000000..3a21647
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad_halfpel_inline.h
@@ -0,0 +1,96 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 _SAD_HALFPEL_INLINE_H_
+#define _SAD_HALFPEL_INLINE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+    __inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        tmp = (tmp2 >> 1) - tmp;
+        if (tmp > 0) sad += tmp;
+        else sad -= tmp;
+
+        return sad;
+    }
+
+    __inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        tmp = (tmp >> 2) - tmp2;
+        if (tmp > 0) sad += tmp;
+        else sad -= tmp;
+
+        return sad;
+    }
+
+#elif defined(__CC_ARM)  /* only work with arm v5 */
+
+    __inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        __asm
+        {
+            rsbs    tmp, tmp, tmp2, asr #1 ;
+            rsbmi   tmp, tmp, #0 ;
+            add     sad, sad, tmp ;
+        }
+
+        return sad;
+    }
+
+    __inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        __asm
+        {
+            rsbs    tmp, tmp2, tmp, asr #2 ;
+            rsbmi   tmp, tmp, #0 ;
+            add     sad, sad, tmp ;
+        }
+
+        return sad;
+    }
+
+#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+    __inline int32 INTERP1_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+__asm__ volatile("rsbs	%1, %1, %2, asr #1\n\trsbmi %1, %1, #0\n\tadd  %0, %0, %1": "=r"(sad), "=r"(tmp): "r"(tmp2));
+
+        return sad;
+    }
+
+    __inline int32 INTERP2_SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+__asm__ volatile("rsbs	%1, %2, %1, asr #2\n\trsbmi %1, %1, #0\n\tadd	%0, %0, %1": "=r"(sad), "=r"(tmp): "r"(tmp2));
+
+        return sad;
+    }
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_SAD_HALFPEL_INLINE_H_
+
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_inline.h b/media/libstagefright/codecs/avc/enc/src/sad_inline.h
new file mode 100644
index 0000000..f39794f
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad_inline.h
@@ -0,0 +1,488 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 _SAD_INLINE_H_
+#define _SAD_INLINE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+    __inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        tmp = tmp - tmp2;
+        if (tmp > 0) sad += tmp;
+        else sad -= tmp;
+
+        return sad;
+    }
+
+    __inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+        x7 = src2 ^ src1;       /* check odd/even combination */
+        if ((uint32)src2 >= (uint32)src1)
+        {
+            src1 = src2 - src1;     /* subs */
+        }
+        else
+        {
+            src1 = src1 - src2;
+        }
+        x7 = x7 ^ src1;     /* only odd bytes need to add carry */
+        x7 = mask & ((uint32)x7 >> 1);
+        x7 = (x7 << 8) - x7;
+        src1 = src1 + (x7 >> 7); /* add 0xFF to the negative byte, add back carry */
+        src1 = src1 ^(x7 >> 7);   /* take absolute value of negative byte */
+
+        return src1;
+    }
+
+#define NUMBER 3
+#define SHIFT 24
+
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 2
+#undef SHIFT
+#define SHIFT 16
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 1
+#undef SHIFT
+#define SHIFT 8
+#include "sad_mb_offset.h"
+
+
+    __inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
+    {
+        int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+        x9 = 0x80808080; /* const. */
+
+        x8 = (uint32)ref & 0x3;
+        if (x8 == 3)
+            goto SadMBOffset3;
+        if (x8 == 2)
+            goto SadMBOffset2;
+        if (x8 == 1)
+            goto SadMBOffset1;
+
+//  x5 = (x4<<8)-x4; /* x5 = x4*255; */
+        x4 = x5 = 0;
+
+        x6 = 0xFFFF00FF;
+
+        ref -= lx;
+        blk -= 16;
+
+        x8 = 16;
+
+LOOP_SAD0:
+        /****** process 8 pixels ******/
+        x10 = *((uint32*)(ref += lx));
+        x11 = *((uint32*)(ref + 4));
+        x12 = *((uint32*)(blk += 16));
+        x14 = *((uint32*)(blk + 4));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10; /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8);  /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****** process 8 pixels ******/
+        x10 = *((uint32*)(ref + 8));
+        x11 = *((uint32*)(ref + 12));
+        x12 = *((uint32*)(blk + 8));
+        x14 = *((uint32*)(blk + 12));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****************/
+        x10 = x5 - (x4 << 8); /* extract low bytes */
+        x10 = x10 + x4;     /* add with high bytes */
+        x10 = x10 + (x10 << 16); /* add with lower half word */
+
+        if ((int)((uint32)x10 >> 16) <= dmin) /* compare with dmin */
+        {
+            if (--x8)
+            {
+                goto LOOP_SAD0;
+            }
+
+        }
+
+        return ((uint32)x10 >> 16);
+
+SadMBOffset3:
+
+        return sad_mb_offset3(ref, blk, lx, dmin);
+
+SadMBOffset2:
+
+        return sad_mb_offset2(ref, blk, lx, dmin);
+
+SadMBOffset1:
+
+        return sad_mb_offset1(ref, blk, lx, dmin);
+
+    }
+
+#elif defined(__CC_ARM)  /* only work with arm v5 */
+
+    __inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+        __asm
+        {
+            rsbs    tmp, tmp, tmp2 ;
+            rsbmi   tmp, tmp, #0 ;
+            add     sad, sad, tmp ;
+        }
+
+        return sad;
+    }
+
+    __inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+        __asm
+        {
+            EOR     x7, src2, src1;     /* check odd/even combination */
+            SUBS    src1, src2, src1;
+            EOR     x7, x7, src1;
+            AND     x7, mask, x7, lsr #1;
+            ORRCC   x7, x7, #0x80000000;
+            RSB     x7, x7, x7, lsl #8;
+            ADD     src1, src1, x7, asr #7;   /* add 0xFF to the negative byte, add back carry */
+            EOR     src1, src1, x7, asr #7;   /* take absolute value of negative byte */
+        }
+
+        return src1;
+    }
+
+    __inline int32 sad_4pixelN(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+        __asm
+        {
+            EOR      x7, src2, src1;        /* check odd/even combination */
+            ADDS     src1, src2, src1;
+            EOR      x7, x7, src1;      /* only odd bytes need to add carry */
+            ANDS     x7, mask, x7, rrx;
+            RSB      x7, x7, x7, lsl #8;
+            SUB      src1, src1, x7, asr #7;  /* add 0xFF to the negative byte, add back carry */
+            EOR      src1, src1, x7, asr #7; /* take absolute value of negative byte */
+        }
+
+        return src1;
+    }
+
+#define sum_accumulate  __asm{      SBC      x5, x5, x10;  /* accumulate low bytes */ \
+        BIC      x10, x6, x10;   /* x10 & 0xFF00FF00 */ \
+        ADD      x4, x4, x10,lsr #8;   /* accumulate high bytes */ \
+        SBC      x5, x5, x11;    /* accumulate low bytes */ \
+        BIC      x11, x6, x11;   /* x11 & 0xFF00FF00 */ \
+        ADD      x4, x4, x11,lsr #8; } /* accumulate high bytes */
+
+
+#define NUMBER 3
+#define SHIFT 24
+#define INC_X8 0x08000001
+
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 2
+#undef SHIFT
+#define SHIFT 16
+#undef INC_X8
+#define INC_X8 0x10000001
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 1
+#undef SHIFT
+#define SHIFT 8
+#undef INC_X8
+#define INC_X8 0x08000001
+#include "sad_mb_offset.h"
+
+
+    __inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
+    {
+        int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+        x9 = 0x80808080; /* const. */
+        x4 = x5 = 0;
+
+        __asm
+        {
+            MOVS    x8, ref, lsl #31 ;
+            BHI     SadMBOffset3;
+            BCS     SadMBOffset2;
+            BMI     SadMBOffset1;
+
+            MVN     x6, #0xFF00;
+        }
+LOOP_SAD0:
+        /****** process 8 pixels ******/
+        x11 = *((int32*)(ref + 12));
+        x10 = *((int32*)(ref + 8));
+        x14 = *((int32*)(blk + 12));
+        x12 = *((int32*)(blk + 8));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        __asm
+        {
+            /****** process 8 pixels ******/
+            LDR     x11, [ref, #4];
+            LDR     x10, [ref], lx ;
+            LDR     x14, [blk, #4];
+            LDR     x12, [blk], #16 ;
+        }
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****************/
+        x10 = x5 - (x4 << 8); /* extract low bytes */
+        x10 = x10 + x4;     /* add with high bytes */
+        x10 = x10 + (x10 << 16); /* add with lower half word */
+
+        __asm
+        {
+            /****************/
+            RSBS    x11, dmin, x10, lsr #16;
+            ADDLSS  x8, x8, #0x10000001;
+            BLS     LOOP_SAD0;
+        }
+
+        return ((uint32)x10 >> 16);
+
+SadMBOffset3:
+
+        return sad_mb_offset3(ref, blk, lx, dmin, x8);
+
+SadMBOffset2:
+
+        return sad_mb_offset2(ref, blk, lx, dmin, x8);
+
+SadMBOffset1:
+
+        return sad_mb_offset1(ref, blk, lx, dmin, x8);
+    }
+
+
+#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+    __inline int32 SUB_SAD(int32 sad, int32 tmp, int32 tmp2)
+    {
+__asm__ volatile("rsbs	%1, %1, %2\n\trsbmi %1, %1, #0\n\tadd	%0, %0, %1": "=r"(sad): "r"(tmp), "r"(tmp2));
+        return sad;
+    }
+
+    __inline int32 sad_4pixel(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+__asm__ volatile("EOR	%1, %2, %0\n\tSUBS  %0, %2, %0\n\tEOR	%1, %1, %0\n\tAND  %1, %3, %1, lsr #1\n\tORRCC	%1, %1, #0x80000000\n\tRSB  %1, %1, %1, lsl #8\n\tADD  %0, %0, %1, asr #7\n\tEOR  %0, %0, %1, asr #7": "=r"(src1), "=&r"(x7): "r"(src2), "r"(mask));
+
+        return src1;
+    }
+
+    __inline int32 sad_4pixelN(int32 src1, int32 src2, int32 mask)
+    {
+        int32 x7;
+
+__asm__ volatile("EOR	%1, %2, %0\n\tADDS  %0, %2, %0\n\tEOR  %1, %1, %0\n\tANDS  %1, %3, %1, rrx\n\tRSB  %1, %1, %1, lsl #8\n\tSUB	%0, %0, %1, asr #7\n\tEOR   %0, %0, %1, asr #7": "=r"(src1), "=&r"(x7): "r"(src2), "r"(mask));
+
+        return src1;
+    }
+
+#define sum_accumulate  __asm__ volatile("SBC  %0, %0, %1\n\tBIC   %1, %4, %1\n\tADD   %2, %2, %1, lsr #8\n\tSBC   %0, %0, %3\n\tBIC   %3, %4, %3\n\tADD   %2, %2, %3, lsr #8": "=&r" (x5), "=&r" (x10), "=&r" (x4), "=&r" (x11): "r" (x6));
+
+#define NUMBER 3
+#define SHIFT 24
+#define INC_X8 0x08000001
+
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 2
+#undef SHIFT
+#define SHIFT 16
+#undef INC_X8
+#define INC_X8 0x10000001
+#include "sad_mb_offset.h"
+
+#undef NUMBER
+#define NUMBER 1
+#undef SHIFT
+#define SHIFT 8
+#undef INC_X8
+#define INC_X8 0x08000001
+#include "sad_mb_offset.h"
+
+
+    __inline int32 simd_sad_mb(uint8 *ref, uint8 *blk, int dmin, int lx)
+    {
+        int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+        x9 = 0x80808080; /* const. */
+        x4 = x5 = 0;
+
+        x8 = (uint32)ref & 0x3;
+        if (x8 == 3)
+            goto SadMBOffset3;
+        if (x8 == 2)
+            goto SadMBOffset2;
+        if (x8 == 1)
+            goto SadMBOffset1;
+
+        x8 = 16;
+///
+__asm__ volatile("MVN	%0, #0xFF00": "=r"(x6));
+
+LOOP_SAD0:
+        /****** process 8 pixels ******/
+        x11 = *((int32*)(ref + 12));
+        x10 = *((int32*)(ref + 8));
+        x14 = *((int32*)(blk + 12));
+        x12 = *((int32*)(blk + 8));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****** process 8 pixels ******/
+        x11 = *((int32*)(ref + 4));
+__asm__ volatile("LDR	%0, [%1], %2": "=&r"(x10), "=r"(ref): "r"(lx));
+        //x10 = *((int32*)ref); ref+=lx;
+        x14 = *((int32*)(blk + 4));
+__asm__ volatile("LDR	%0, [%1], #16": "=&r"(x12), "=r"(blk));
+
+        /* process x11 & x14 */
+        x11 = sad_4pixel(x11, x14, x9);
+
+        /* process x12 & x10 */
+        x10 = sad_4pixel(x10, x12, x9);
+
+        x5 = x5 + x10;  /* accumulate low bytes */
+        x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x10 >> 8); /* accumulate high bytes */
+        x5 = x5 + x11;  /* accumulate low bytes */
+        x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+        x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+        /****************/
+        x10 = x5 - (x4 << 8); /* extract low bytes */
+        x10 = x10 + x4;     /* add with high bytes */
+        x10 = x10 + (x10 << 16); /* add with lower half word */
+
+        /****************/
+
+        if (((uint32)x10 >> 16) <= dmin) /* compare with dmin */
+        {
+            if (--x8)
+            {
+                goto LOOP_SAD0;
+            }
+
+        }
+
+        return ((uint32)x10 >> 16);
+
+SadMBOffset3:
+
+        return sad_mb_offset3(ref, blk, lx, dmin);
+
+SadMBOffset2:
+
+        return sad_mb_offset2(ref, blk, lx, dmin);
+
+SadMBOffset1:
+
+        return sad_mb_offset1(ref, blk, lx, dmin);
+    }
+
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _SAD_INLINE_H_
+
diff --git a/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h b/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
new file mode 100644
index 0000000..d5d4a42
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/sad_mb_offset.h
@@ -0,0 +1,311 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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.
+ * -------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+#if (NUMBER==3)
+__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin)
+#elif (NUMBER==2)
+__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin)
+#elif (NUMBER==1)
+__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin)
+#endif
+{
+    int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+    //  x5 = (x4<<8) - x4;
+    x4 = x5 = 0;
+    x6 = 0xFFFF00FF;
+    x9 = 0x80808080; /* const. */
+    ref -= NUMBER; /* bic ref, ref, #3 */
+    ref -= lx;
+    blk -= 16;
+    x8 = 16;
+
+#if (NUMBER==3)
+LOOP_SAD3:
+#elif (NUMBER==2)
+LOOP_SAD2:
+#elif (NUMBER==1)
+LOOP_SAD1:
+#endif
+    /****** process 8 pixels ******/
+    x10 = *((uint32*)(ref += lx)); /* D C B A */
+    x11 = *((uint32*)(ref + 4));    /* H G F E */
+    x12 = *((uint32*)(ref + 8));    /* L K J I */
+
+    x10 = ((uint32)x10 >> SHIFT); /* 0 0 0 D */
+    x10 = x10 | (x11 << (32 - SHIFT));        /* G F E D */
+    x11 = ((uint32)x11 >> SHIFT); /* 0 0 0 H */
+    x11 = x11 | (x12 << (32 - SHIFT));        /* K J I H */
+
+    x12 = *((uint32*)(blk += 16));
+    x14 = *((uint32*)(blk + 4));
+
+    /* process x11 & x14 */
+    x11 = sad_4pixel(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixel(x10, x12, x9);
+
+    x5 = x5 + x10; /* accumulate low bytes */
+    x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+    x4 = x4 + ((uint32)x10 >> 8);  /* accumulate high bytes */
+    x5 = x5 + x11;  /* accumulate low bytes */
+    x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+    x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+    /****** process 8 pixels ******/
+    x10 = *((uint32*)(ref + 8)); /* D C B A */
+    x11 = *((uint32*)(ref + 12));   /* H G F E */
+    x12 = *((uint32*)(ref + 16));   /* L K J I */
+
+    x10 = ((uint32)x10 >> SHIFT); /* mvn x10, x10, lsr #24  = 0xFF 0xFF 0xFF ~D */
+    x10 = x10 | (x11 << (32 - SHIFT));        /* bic x10, x10, x11, lsl #8 = ~G ~F ~E ~D */
+    x11 = ((uint32)x11 >> SHIFT); /* 0xFF 0xFF 0xFF ~H */
+    x11 = x11 | (x12 << (32 - SHIFT));        /* ~K ~J ~I ~H */
+
+    x12 = *((uint32*)(blk + 8));
+    x14 = *((uint32*)(blk + 12));
+
+    /* process x11 & x14 */
+    x11 = sad_4pixel(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixel(x10, x12, x9);
+
+    x5 = x5 + x10; /* accumulate low bytes */
+    x10 = x10 & (x6 << 8); /* x10 & 0xFF00FF00 */
+    x4 = x4 + ((uint32)x10 >> 8);  /* accumulate high bytes */
+    x5 = x5 + x11;  /* accumulate low bytes */
+    x11 = x11 & (x6 << 8); /* x11 & 0xFF00FF00 */
+    x4 = x4 + ((uint32)x11 >> 8);  /* accumulate high bytes */
+
+    /****************/
+    x10 = x5 - (x4 << 8); /* extract low bytes */
+    x10 = x10 + x4;     /* add with high bytes */
+    x10 = x10 + (x10 << 16); /* add with lower half word */
+
+    if ((int)((uint32)x10 >> 16) <= dmin) /* compare with dmin */
+    {
+        if (--x8)
+        {
+#if (NUMBER==3)
+            goto         LOOP_SAD3;
+#elif (NUMBER==2)
+            goto         LOOP_SAD2;
+#elif (NUMBER==1)
+            goto         LOOP_SAD1;
+#endif
+        }
+
+    }
+
+    return ((uint32)x10 >> 16);
+}
+
+#elif defined(__CC_ARM)  /* only work with arm v5 */
+
+#if (NUMBER==3)
+__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
+#elif (NUMBER==2)
+__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
+#elif (NUMBER==1)
+__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin, int32 x8)
+#endif
+{
+    int32 x4, x5, x6, x9, x10, x11, x12, x14;
+
+    x9 = 0x80808080; /* const. */
+    x4 = x5 = 0;
+
+    __asm{
+        MVN      x6, #0xff0000;
+#if (NUMBER==3)
+LOOP_SAD3:
+#elif (NUMBER==2)
+LOOP_SAD2:
+#elif (NUMBER==1)
+LOOP_SAD1:
+#endif
+        BIC      ref, ref, #3;
+    }
+    /****** process 8 pixels ******/
+    x11 = *((int32*)(ref + 12));
+    x12 = *((int32*)(ref + 16));
+    x10 = *((int32*)(ref + 8));
+    x14 = *((int32*)(blk + 12));
+
+    __asm{
+        MVN      x10, x10, lsr #SHIFT;
+        BIC      x10, x10, x11, lsl #(32-SHIFT);
+        MVN      x11, x11, lsr #SHIFT;
+        BIC      x11, x11, x12, lsl #(32-SHIFT);
+
+        LDR      x12, [blk, #8];
+    }
+
+    /* process x11 & x14 */
+    x11 = sad_4pixelN(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixelN(x10, x12, x9);
+
+    sum_accumulate;
+
+    __asm{
+        /****** process 8 pixels ******/
+        LDR      x11, [ref, #4];
+        LDR      x12, [ref, #8];
+        LDR  x10, [ref], lx ;
+        LDR  x14, [blk, #4];
+
+        MVN      x10, x10, lsr #SHIFT;
+        BIC      x10, x10, x11, lsl #(32-SHIFT);
+        MVN      x11, x11, lsr #SHIFT;
+        BIC      x11, x11, x12, lsl #(32-SHIFT);
+
+        LDR      x12, [blk], #16;
+    }
+
+    /* process x11 & x14 */
+    x11 = sad_4pixelN(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixelN(x10, x12, x9);
+
+    sum_accumulate;
+
+    /****************/
+    x10 = x5 - (x4 << 8); /* extract low bytes */
+    x10 = x10 + x4;     /* add with high bytes */
+    x10 = x10 + (x10 << 16); /* add with lower half word */
+
+    __asm{
+        RSBS     x11, dmin, x10, lsr #16
+        ADDLSS   x8, x8, #INC_X8
+#if (NUMBER==3)
+        BLS      LOOP_SAD3;
+#elif (NUMBER==2)
+BLS      LOOP_SAD2;
+#elif (NUMBER==1)
+BLS      LOOP_SAD1;
+#endif
+    }
+
+    return ((uint32)x10 >> 16);
+}
+
+#elif defined(__GNUC__) && defined(__arm__) /* ARM GNU COMPILER  */
+
+#if (NUMBER==3)
+__inline int32 sad_mb_offset3(uint8 *ref, uint8 *blk, int lx, int dmin)
+#elif (NUMBER==2)
+__inline int32 sad_mb_offset2(uint8 *ref, uint8 *blk, int lx, int dmin)
+#elif (NUMBER==1)
+__inline int32 sad_mb_offset1(uint8 *ref, uint8 *blk, int lx, int dmin)
+#endif
+{
+    int32 x4, x5, x6, x8, x9, x10, x11, x12, x14;
+
+    x9 = 0x80808080; /* const. */
+    x4 = x5 = 0;
+    x8 = 16; //<<===========*******
+
+__asm__ volatile("MVN	%0, #0xFF0000": "=r"(x6));
+
+#if (NUMBER==3)
+LOOP_SAD3:
+#elif (NUMBER==2)
+LOOP_SAD2:
+#elif (NUMBER==1)
+LOOP_SAD1:
+#endif
+__asm__ volatile("BIC  %0, %0, #3": "=r"(ref));
+    /****** process 8 pixels ******/
+    x11 = *((int32*)(ref + 12));
+    x12 = *((int32*)(ref + 16));
+    x10 = *((int32*)(ref + 8));
+    x14 = *((int32*)(blk + 12));
+
+#if (SHIFT==8)
+__asm__ volatile("MVN   %0, %0, lsr #8\n\tBIC   %0, %0, %1,lsl #24\n\tMVN   %1, %1,lsr #8\n\tBIC   %1, %1, %2,lsl #24": "=&r"(x10), "=&r"(x11): "r"(x12));
+#elif (SHIFT==16)
+__asm__ volatile("MVN   %0, %0, lsr #16\n\tBIC   %0, %0, %1,lsl #16\n\tMVN   %1, %1,lsr #16\n\tBIC   %1, %1, %2,lsl #16": "=&r"(x10), "=&r"(x11): "r"(x12));
+#elif (SHIFT==24)
+__asm__ volatile("MVN   %0, %0, lsr #24\n\tBIC   %0, %0, %1,lsl #8\n\tMVN   %1, %1,lsr #24\n\tBIC   %1, %1, %2,lsl #8": "=&r"(x10), "=&r"(x11): "r"(x12));
+#endif
+
+    x12 = *((int32*)(blk + 8));
+
+    /* process x11 & x14 */
+    x11 = sad_4pixelN(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixelN(x10, x12, x9);
+
+    sum_accumulate;
+
+    /****** process 8 pixels ******/
+    x11 = *((int32*)(ref + 4));
+    x12 = *((int32*)(ref + 8));
+    x10 = *((int32*)ref); ref += lx;
+    x14 = *((int32*)(blk + 4));
+
+#if (SHIFT==8)
+__asm__ volatile("MVN   %0, %0, lsr #8\n\tBIC   %0, %0, %1,lsl #24\n\tMVN   %1, %1,lsr #8\n\tBIC   %1, %1, %2,lsl #24": "=&r"(x10), "=&r"(x11): "r"(x12));
+#elif (SHIFT==16)
+__asm__ volatile("MVN   %0, %0, lsr #16\n\tBIC   %0, %0, %1,lsl #16\n\tMVN   %1, %1,lsr #16\n\tBIC   %1, %1, %2,lsl #16": "=&r"(x10), "=&r"(x11): "r"(x12));
+#elif (SHIFT==24)
+__asm__ volatile("MVN   %0, %0, lsr #24\n\tBIC   %0, %0, %1,lsl #8\n\tMVN   %1, %1,lsr #24\n\tBIC   %1, %1, %2,lsl #8": "=&r"(x10), "=&r"(x11): "r"(x12));
+#endif
+__asm__ volatile("LDR   %0, [%1], #16": "=&r"(x12), "=r"(blk));
+
+    /* process x11 & x14 */
+    x11 = sad_4pixelN(x11, x14, x9);
+
+    /* process x12 & x10 */
+    x10 = sad_4pixelN(x10, x12, x9);
+
+    sum_accumulate;
+
+    /****************/
+    x10 = x5 - (x4 << 8); /* extract low bytes */
+    x10 = x10 + x4;     /* add with high bytes */
+    x10 = x10 + (x10 << 16); /* add with lower half word */
+
+    if (((uint32)x10 >> 16) <= (uint32)dmin) /* compare with dmin */
+    {
+        if (--x8)
+        {
+#if (NUMBER==3)
+            goto         LOOP_SAD3;
+#elif (NUMBER==2)
+goto         LOOP_SAD2;
+#elif (NUMBER==1)
+goto         LOOP_SAD1;
+#endif
+        }
+
+    }
+
+    return ((uint32)x10 >> 16);
+}
+
+#endif
+
diff --git a/media/libstagefright/codecs/avc/enc/src/slice.cpp b/media/libstagefright/codecs/avc/enc/src/slice.cpp
new file mode 100644
index 0000000..f6d066e
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/slice.cpp
@@ -0,0 +1,1025 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+
+
+AVCEnc_Status AVCEncodeSlice(AVCEncObject *encvid)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCCommonObj *video = encvid->common;
+    AVCPicParamSet *pps = video->currPicParams;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    AVCMacroblock *currMB ;
+    AVCEncBitstream *stream = encvid->bitstream;
+    uint slice_group_id;
+    int CurrMbAddr, slice_type;
+
+    slice_type = video->slice_type;
+
+    /* set the first mb in slice */
+    video->mbNum = CurrMbAddr = sliceHdr->first_mb_in_slice;// * (1+video->MbaffFrameFlag);
+    slice_group_id = video->MbToSliceGroupMap[CurrMbAddr];
+
+    video->mb_skip_run = 0;
+
+    /* while loop , see subclause 7.3.4 */
+    while (1)
+    {
+        video->mbNum = CurrMbAddr;
+        currMB = video->currMB = &(video->mblock[CurrMbAddr]);
+        currMB->slice_id = video->slice_id;  // for deblocking
+
+        video->mb_x = CurrMbAddr % video->PicWidthInMbs;
+        video->mb_y = CurrMbAddr / video->PicWidthInMbs;
+
+        /* initialize QP for this MB here*/
+        /* calculate currMB->QPy */
+        RCInitMBQP(encvid);
+
+        /* check the availability of neighboring macroblocks */
+        InitNeighborAvailability(video, CurrMbAddr);
+
+        /* Assuming that InitNeighborAvailability has been called prior to this function */
+        video->intraAvailA = video->intraAvailB = video->intraAvailC = video->intraAvailD = 0;
+        /* this is necessary for all subsequent intra search */
+
+        if (!video->currPicParams->constrained_intra_pred_flag)
+        {
+            video->intraAvailA = video->mbAvailA;
+            video->intraAvailB = video->mbAvailB;
+            video->intraAvailC = video->mbAvailC;
+            video->intraAvailD = video->mbAvailD;
+        }
+        else
+        {
+            if (video->mbAvailA)
+            {
+                video->intraAvailA = video->mblock[video->mbAddrA].mb_intra;
+            }
+            if (video->mbAvailB)
+            {
+                video->intraAvailB = video->mblock[video->mbAddrB].mb_intra ;
+            }
+            if (video->mbAvailC)
+            {
+                video->intraAvailC = video->mblock[video->mbAddrC].mb_intra;
+            }
+            if (video->mbAvailD)
+            {
+                video->intraAvailD = video->mblock[video->mbAddrD].mb_intra;
+            }
+        }
+
+        /* encode_one_macroblock() */
+        status = EncodeMB(encvid);
+        if (status != AVCENC_SUCCESS)
+        {
+            break;
+        }
+
+        /* go to next MB */
+        CurrMbAddr++;
+
+        while ((uint)video->MbToSliceGroupMap[CurrMbAddr] != slice_group_id &&
+                (uint)CurrMbAddr < video->PicSizeInMbs)
+        {
+            CurrMbAddr++;
+        }
+
+        if ((uint)CurrMbAddr >= video->PicSizeInMbs)
+        {
+            /* end of slice, return, but before that check to see if there are other slices
+            to be encoded. */
+            encvid->currSliceGroup++;
+            if (encvid->currSliceGroup > (int)pps->num_slice_groups_minus1) /* no more slice group */
+            {
+                status = AVCENC_PICTURE_READY;
+                break;
+            }
+            else
+            {
+                /* find first_mb_num for the next slice */
+                CurrMbAddr = 0;
+                while (video->MbToSliceGroupMap[CurrMbAddr] != encvid->currSliceGroup &&
+                        (uint)CurrMbAddr < video->PicSizeInMbs)
+                {
+                    CurrMbAddr++;
+                }
+                if ((uint)CurrMbAddr >= video->PicSizeInMbs)
+                {
+                    status = AVCENC_SLICE_EMPTY; /* error, one slice group has no MBs in it */
+                }
+
+                video->mbNum = CurrMbAddr;
+                status = AVCENC_SUCCESS;
+                break;
+            }
+        }
+    }
+
+    if (video->mb_skip_run > 0)
+    {
+        /* write skip_run */
+        if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE)
+        {
+            ue_v(stream, video->mb_skip_run);
+            video->mb_skip_run = 0;
+        }
+        else    /* shouldn't happen */
+        {
+            status = AVCENC_FAIL;
+        }
+    }
+
+    return status;
+}
+
+
+AVCEnc_Status EncodeMB(AVCEncObject *encvid)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    AVCCommonObj *video = encvid->common;
+    AVCPictureData *currPic = video->currPic;
+    AVCFrameIO  *currInput = encvid->currInput;
+    AVCMacroblock *currMB = video->currMB;
+    AVCMacroblock *MB_A, *MB_B;
+    AVCEncBitstream *stream = encvid->bitstream;
+    AVCRateControl *rateCtrl = encvid->rateCtrl;
+    uint8 *cur, *curL, *curCb, *curCr;
+    uint8 *orgL, *orgCb, *orgCr, *org4;
+    int CurrMbAddr = video->mbNum;
+    int picPitch = currPic->pitch;
+    int orgPitch = currInput->pitch;
+    int x_position = (video->mb_x << 4);
+    int y_position = (video->mb_y << 4);
+    int offset;
+    int b8, b4, blkidx;
+    AVCResidualType  resType;
+    int slice_type;
+    int numcoeff; /* output from residual_block_cavlc */
+    int cost16, cost8;
+
+    int num_bits, start_mb_bits, start_text_bits;
+
+    slice_type = video->slice_type;
+
+    /* now, point to the reconstructed frame */
+    offset = y_position * picPitch + x_position;
+    curL = currPic->Sl + offset;
+    orgL = currInput->YCbCr[0] + offset;
+    offset = (offset + x_position) >> 2;
+    curCb = currPic->Scb + offset;
+    curCr = currPic->Scr + offset;
+    orgCb = currInput->YCbCr[1] + offset;
+    orgCr = currInput->YCbCr[2] + offset;
+
+    if (orgPitch != picPitch)
+    {
+        offset = y_position * (orgPitch - picPitch);
+        orgL += offset;
+        offset >>= 2;
+        orgCb += offset;
+        orgCr += offset;
+    }
+
+    /******* determine MB prediction mode *******/
+    if (encvid->intraSearch[CurrMbAddr])
+    {
+        MBIntraSearch(encvid, CurrMbAddr, curL, picPitch);
+    }
+    /******* This part should be determined somehow ***************/
+    if (currMB->mbMode == AVC_I_PCM)
+    {
+        /* write down mb_type and PCM data */
+        /* and copy from currInput to currPic */
+        status = EncodeIntraPCM(encvid);
+
+
+        return status;
+    }
+
+    /****** for intra prediction, pred is already done *******/
+    /****** for I4, the recon is ready and Xfrm coefs are ready to be encoded *****/
+
+    //RCCalculateMAD(encvid,currMB,orgL,orgPitch); // no need to re-calculate MAD for Intra
+    // not used since totalSAD is used instead
+
+    /* compute the prediction */
+    /* output is video->pred_block */
+    if (!currMB->mb_intra)
+    {
+        AVCMBMotionComp(encvid, video); /* perform prediction and residue calculation */
+        /* we can do the loop here and call dct_luma */
+        video->pred_pitch = picPitch;
+        currMB->CBP = 0;
+        cost16 = 0;
+        cur = curL;
+        org4 = orgL;
+
+        for (b8 = 0; b8 < 4; b8++)
+        {
+            cost8 = 0;
+
+            for (b4 = 0; b4 < 4; b4++)
+            {
+                blkidx = blkIdx2blkXY[b8][b4];
+                video->pred_block = cur;
+                numcoeff = dct_luma(encvid, blkidx, cur, org4, &cost8);
+                currMB->nz_coeff[blkidx] = numcoeff;
+                if (numcoeff)
+                {
+                    video->cbp4x4 |= (1 << blkidx);
+                    currMB->CBP |= (1 << b8);
+                }
+
+                if (b4&1)
+                {
+                    cur += ((picPitch << 2) - 4);
+                    org4 += ((orgPitch << 2) - 4);
+                }
+                else
+                {
+                    cur += 4;
+                    org4 += 4;
+                }
+            }
+
+            /* move the IDCT part out of dct_luma to accommodate the check
+               for coeff_cost. */
+
+            if ((currMB->CBP&(1 << b8)) && (cost8 <= _LUMA_COEFF_COST_))
+            {
+                cost8 = 0; // reset it
+
+                currMB->CBP ^= (1 << b8);
+                blkidx = blkIdx2blkXY[b8][0];
+
+                currMB->nz_coeff[blkidx] = 0;
+                currMB->nz_coeff[blkidx+1] = 0;
+                currMB->nz_coeff[blkidx+4] = 0;
+                currMB->nz_coeff[blkidx+5] = 0;
+            }
+
+            cost16 += cost8;
+
+            if (b8&1)
+            {
+                cur -= 8;
+                org4 -= 8;
+            }
+            else
+            {
+                cur += (8 - (picPitch << 3));
+                org4 += (8 - (orgPitch << 3));
+            }
+        }
+
+        /* after the whole MB, we do another check for coeff_cost */
+        if ((currMB->CBP&0xF) && (cost16 <= _LUMA_MB_COEFF_COST_))
+        {
+            currMB->CBP = 0;  // reset it to zero
+            memset(currMB->nz_coeff, 0, sizeof(uint8)*16);
+        }
+
+        // now we do IDCT
+        MBInterIdct(video, curL, currMB, picPitch);
+
+//      video->pred_block = video->pred + 256;
+    }
+    else    /* Intra prediction */
+    {
+        encvid->numIntraMB++;
+
+        if (currMB->mbMode == AVC_I16) /* do prediction for the whole macroblock */
+        {
+            currMB->CBP = 0;
+            /* get the prediction from encvid->pred_i16 */
+            dct_luma_16x16(encvid, curL, orgL);
+        }
+        video->pred_block = encvid->pred_ic[currMB->intra_chroma_pred_mode];
+    }
+
+    /* chrominance */
+    /* not need to do anything, the result is in encvid->pred_ic
+    chroma dct must be aware that prediction block can come from either intra or inter. */
+
+    dct_chroma(encvid, curCb, orgCb, 0);
+
+    dct_chroma(encvid, curCr, orgCr, 1);
+
+
+    /* 4.1 if there's nothing in there, video->mb_skip_run++ */
+    /* 4.2 if coded, check if there is a run of skipped MB, encodes it,
+            set video->QPyprev = currMB->QPy; */
+
+    /* 5. vlc encode */
+
+    /* check for skipped macroblock, INTER only */
+    if (!currMB->mb_intra)
+    {
+        /* decide whether this MB (for inter MB) should be skipped if there's nothing left. */
+        if (!currMB->CBP && currMB->NumMbPart == 1 && currMB->QPy == video->QPy)
+        {
+            if (currMB->MBPartPredMode[0][0] == AVC_Pred_L0 && currMB->ref_idx_L0[0] == 0)
+            {
+                MB_A = &video->mblock[video->mbAddrA];
+                MB_B = &video->mblock[video->mbAddrB];
+
+                if (!video->mbAvailA || !video->mbAvailB)
+                {
+                    if (currMB->mvL0[0] == 0) /* both mv components are zeros.*/
+                    {
+                        currMB->mbMode = AVC_SKIP;
+                        video->mvd_l0[0][0][0] = 0;
+                        video->mvd_l0[0][0][1] = 0;
+                    }
+                }
+                else
+                {
+                    if ((MB_A->ref_idx_L0[1] == 0 && MB_A->mvL0[3] == 0) ||
+                            (MB_B->ref_idx_L0[2] == 0 && MB_B->mvL0[12] == 0))
+                    {
+                        if (currMB->mvL0[0] == 0) /* both mv components are zeros.*/
+                        {
+                            currMB->mbMode = AVC_SKIP;
+                            video->mvd_l0[0][0][0] = 0;
+                            video->mvd_l0[0][0][1] = 0;
+                        }
+                    }
+                    else if (video->mvd_l0[0][0][0] == 0 && video->mvd_l0[0][0][1] == 0)
+                    {
+                        currMB->mbMode = AVC_SKIP;
+                    }
+                }
+            }
+
+            if (currMB->mbMode == AVC_SKIP)
+            {
+                video->mb_skip_run++;
+
+                /* set parameters */
+                /* not sure whether we need the followings */
+                if (slice_type == AVC_P_SLICE)
+                {
+                    currMB->mbMode = AVC_SKIP;
+                    currMB->MbPartWidth = currMB->MbPartHeight = 16;
+                    currMB->MBPartPredMode[0][0] = AVC_Pred_L0;
+                    currMB->NumMbPart = 1;
+                    currMB->NumSubMbPart[0] = currMB->NumSubMbPart[1] =
+                                                  currMB->NumSubMbPart[2] = currMB->NumSubMbPart[3] = 1;
+                    currMB->SubMbPartWidth[0] = currMB->SubMbPartWidth[1] =
+                                                    currMB->SubMbPartWidth[2] = currMB->SubMbPartWidth[3] = currMB->MbPartWidth;
+                    currMB->SubMbPartHeight[0] = currMB->SubMbPartHeight[1] =
+                                                     currMB->SubMbPartHeight[2] = currMB->SubMbPartHeight[3] = currMB->MbPartHeight;
+
+                }
+                else if (slice_type == AVC_B_SLICE)
+                {
+                    currMB->mbMode = AVC_SKIP;
+                    currMB->MbPartWidth = currMB->MbPartHeight = 8;
+                    currMB->MBPartPredMode[0][0] = AVC_Direct;
+                    currMB->NumMbPart = -1;
+                }
+
+                /* for skipped MB, always look at the first entry in RefPicList */
+                currMB->RefIdx[0] = currMB->RefIdx[1] =
+                                        currMB->RefIdx[2] = currMB->RefIdx[3] = video->RefPicList0[0]->RefIdx;
+
+                /* do not return yet, need to do some copies */
+            }
+        }
+    }
+    /* non-skipped MB */
+
+
+    /************* START ENTROPY CODING *************************/
+
+    start_mb_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+    /* encode mb_type, mb_pred, sub_mb_pred, CBP */
+    if (slice_type != AVC_I_SLICE && slice_type != AVC_SI_SLICE && currMB->mbMode != AVC_SKIP)
+    {
+        //if(!pps->entropy_coding_mode_flag)  ALWAYS true
+        {
+            ue_v(stream, video->mb_skip_run);
+            video->mb_skip_run = 0;
+        }
+    }
+
+    if (currMB->mbMode != AVC_SKIP)
+    {
+        status = EncodeMBHeader(currMB, encvid);
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+    }
+
+    start_text_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+    /**** now decoding part *******/
+    resType = AVC_Luma;
+
+    /* DC transform for luma I16 mode */
+    if (currMB->mbMode == AVC_I16)
+    {
+        /* vlc encode level/run */
+        status = enc_residual_block(encvid, AVC_Intra16DC, encvid->numcoefdc, currMB);
+        if (status != AVCENC_SUCCESS)
+        {
+            return status;
+        }
+        resType = AVC_Intra16AC;
+    }
+
+    /* VLC encoding for luma */
+    for (b8 = 0; b8 < 4; b8++)
+    {
+        if (currMB->CBP&(1 << b8))
+        {
+            for (b4 = 0; b4 < 4; b4++)
+            {
+                /* vlc encode level/run */
+                status = enc_residual_block(encvid, resType, (b8 << 2) + b4, currMB);
+                if (status != AVCENC_SUCCESS)
+                {
+                    return status;
+                }
+            }
+        }
+    }
+
+    /* chroma */
+    if (currMB->CBP & (3 << 4)) /* chroma DC residual present */
+    {
+        for (b8 = 0; b8 < 2; b8++) /* for iCbCr */
+        {
+            /* vlc encode level/run */
+            status = enc_residual_block(encvid, AVC_ChromaDC, encvid->numcoefcdc[b8] + (b8 << 3), currMB);
+            if (status != AVCENC_SUCCESS)
+            {
+                return status;
+            }
+        }
+    }
+
+    if (currMB->CBP & (2 << 4))
+    {
+        /* AC part */
+        for (b8 = 0; b8 < 2; b8++) /* for iCbCr */
+        {
+            for (b4 = 0; b4 < 4; b4++)  /* for each block inside Cb or Cr */
+            {
+                /* vlc encode level/run */
+                status = enc_residual_block(encvid, AVC_ChromaAC, 16 + (b8 << 2) + b4, currMB);
+                if (status != AVCENC_SUCCESS)
+                {
+                    return status;
+                }
+            }
+        }
+    }
+
+
+    num_bits = 32 + (encvid->bitstream->write_pos << 3) - encvid->bitstream->bit_left;
+
+    RCPostMB(video, rateCtrl, start_text_bits - start_mb_bits,
+             num_bits - start_text_bits);
+
+//  num_bits -= start_mb_bits;
+//  fprintf(fdebug,"MB #%d: %d bits\n",CurrMbAddr,num_bits);
+//  fclose(fdebug);
+    return status;
+}
+
+/* copy the content from predBlock back to the reconstructed YUV frame */
+void Copy_MB(uint8 *curL, uint8 *curCb, uint8 *curCr, uint8 *predBlock, int picPitch)
+{
+    int j, offset;
+    uint32 *dst, *dst2, *src;
+
+    dst = (uint32*)curL;
+    src = (uint32*)predBlock;
+
+    offset = (picPitch - 16) >> 2;
+
+    for (j = 0; j < 16; j++)
+    {
+        *dst++ = *src++;
+        *dst++ = *src++;
+        *dst++ = *src++;
+        *dst++ = *src++;
+
+        dst += offset;
+    }
+
+    dst = (uint32*)curCb;
+    dst2 = (uint32*)curCr;
+    offset >>= 1;
+
+    for (j = 0; j < 8; j++)
+    {
+        *dst++ = *src++;
+        *dst++ = *src++;
+        *dst2++ = *src++;
+        *dst2++ = *src++;
+
+        dst += offset;
+        dst2 += offset;
+    }
+    return ;
+}
+
+/* encode mb_type, mb_pred, sub_mb_pred, CBP */
+/* decide whether this MB (for inter MB) should be skipped */
+AVCEnc_Status EncodeMBHeader(AVCMacroblock *currMB, AVCEncObject *encvid)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    uint mb_type;
+    AVCCommonObj *video = encvid->common;
+    AVCEncBitstream *stream = encvid->bitstream;
+
+    if (currMB->CBP > 47)   /* chroma CBP is 11 */
+    {
+        currMB->CBP -= 16;  /* remove the 5th bit from the right */
+    }
+
+    mb_type = InterpretMBType(currMB, video->slice_type);
+
+    status = ue_v(stream, mb_type);
+
+    if (currMB->mbMode == AVC_P8 || currMB->mbMode == AVC_P8ref0)
+    {
+        status = sub_mb_pred(video, currMB, stream);
+    }
+    else
+    {
+        status = mb_pred(video, currMB, stream) ;
+    }
+
+    if (currMB->mbMode != AVC_I16)
+    {
+        /* decode coded_block_pattern */
+        status = EncodeCBP(currMB, stream);
+    }
+
+    /* calculate currMB->mb_qp_delta = currMB->QPy - video->QPyprev */
+    if (currMB->CBP > 0 || currMB->mbMode == AVC_I16)
+    {
+        status = se_v(stream, currMB->QPy - video->QPy);
+        video->QPy = currMB->QPy; /* = (video->QPyprev + currMB->mb_qp_delta + 52)%52; */
+        // no need video->QPc = currMB->QPc;
+    }
+    else
+    {
+        if (currMB->QPy != video->QPy) // current QP is not the same as previous QP
+        {
+            /* restore these values */
+            RCRestoreQP(currMB, video, encvid);
+        }
+    }
+
+    return status;
+}
+
+
+/* inputs are mbMode, mb_intra, i16Mode, CBP, NumMbPart, MbPartWidth, MbPartHeight */
+uint InterpretMBType(AVCMacroblock *currMB, int slice_type)
+{
+    int CBP_chrom;
+    int mb_type;// part1, part2, part3;
+//  const static int MapParts2Type[2][3][3]={{{4,8,12},{10,6,14},{16,18,20}},
+//  {{5,9,13},{11,7,15},{17,19,21}}};
+
+    if (currMB->mb_intra)
+    {
+        if (currMB->mbMode == AVC_I4)
+        {
+            mb_type = 0;
+        }
+        else if (currMB->mbMode == AVC_I16)
+        {
+            CBP_chrom = (currMB->CBP & 0x30);
+            if (currMB->CBP&0xF)
+            {
+                currMB->CBP |= 0xF;  /* either 0x0 or 0xF */
+                mb_type = 13;
+            }
+            else
+            {
+                mb_type = 1;
+            }
+            mb_type += (CBP_chrom >> 2) + currMB->i16Mode;
+        }
+        else /* if(currMB->mbMode == AVC_I_PCM) */
+        {
+            mb_type = 25;
+        }
+    }
+    else
+    {  /* P-MB *//* note that the order of the enum AVCMBMode cannot be changed
+        since we use it here. */
+        mb_type = currMB->mbMode - AVC_P16;
+    }
+
+    if (slice_type == AVC_P_SLICE)
+    {
+        if (currMB->mb_intra)
+        {
+            mb_type += 5;
+        }
+    }
+    // following codes have not been tested yet, not needed.
+    /*  else if(slice_type == AVC_B_SLICE)
+        {
+            if(currMB->mbMode == AVC_BDirect16)
+            {
+                mb_type = 0;
+            }
+            else if(currMB->mbMode == AVC_P16)
+            {
+                mb_type = currMB->MBPartPredMode[0][0] + 1; // 1 or 2
+            }
+            else if(currMB->mbMode == AVC_P8)
+            {
+                mb_type = 26;
+            }
+            else if(currMB->mbMode == AVC_P8ref0)
+            {
+                mb_type = 27;
+            }
+            else
+            {
+                part1 = currMB->mbMode - AVC_P16x8;
+                part2 = currMB->MBPartPredMode[0][0];
+                part3 = currMB->MBPartPredMode[1][0];
+                mb_type = MapParts2Type[part1][part2][part3];
+            }
+        }
+
+        if(slice_type == AVC_SI_SLICE)
+        {
+            mb_type++;
+        }
+    */
+    return (uint)mb_type;
+}
+
+//const static int mbPart2raster[3][4] = {{0,0,0,0},{1,1,0,0},{1,0,1,0}};
+
+/* see subclause 7.3.5.1 */
+AVCEnc_Status mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    int mbPartIdx;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    int max_ref_idx;
+    uint code;
+
+    if (currMB->mbMode == AVC_I4 || currMB->mbMode == AVC_I16)
+    {
+        if (currMB->mbMode == AVC_I4)
+        {
+            /* perform prediction to get the actual intra 4x4 pred mode */
+            EncodeIntra4x4Mode(video, currMB, stream);
+            /* output will be in currMB->i4Mode[4][4] */
+        }
+
+        /* assume already set from MBPrediction() */
+        status = ue_v(stream, currMB->intra_chroma_pred_mode);
+    }
+    else if (currMB->MBPartPredMode[0][0] != AVC_Direct)
+    {
+
+        memset(currMB->ref_idx_L0, 0, sizeof(int16)*4);
+
+        /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+        max_ref_idx = sliceHdr->num_ref_idx_l0_active_minus1;
+        /*      if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+                    max_ref_idx = 2*sliceHdr->num_ref_idx_l0_active_minus1 + 1;
+        */
+        /* decode ref index for L0 */
+        if (sliceHdr->num_ref_idx_l0_active_minus1 > 0)
+        {
+            for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+            {
+                if (/*(sliceHdr->num_ref_idx_l0_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+                    currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+                {
+                    code = currMB->ref_idx_L0[mbPartIdx];
+                    status = te_v(stream, code, max_ref_idx);
+                }
+            }
+        }
+
+        /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+        max_ref_idx = sliceHdr->num_ref_idx_l1_active_minus1;
+        /*      if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+                    max_ref_idx = 2*sliceHdr->num_ref_idx_l1_active_minus1 + 1;
+        */
+        /* decode ref index for L1 */
+        if (sliceHdr->num_ref_idx_l1_active_minus1 > 0)
+        {
+            for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+            {
+                if (/*(sliceHdr->num_ref_idx_l1_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+                    currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+                {
+                    status = te_v(stream, currMB->ref_idx_L1[mbPartIdx], max_ref_idx);
+                }
+            }
+        }
+
+        /* encode mvd_l0 */
+        for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+        {
+            if (currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+            {
+                status = se_v(stream, video->mvd_l0[mbPartIdx][0][0]);
+                status = se_v(stream, video->mvd_l0[mbPartIdx][0][1]);
+            }
+        }
+        /* encode mvd_l1 */
+        for (mbPartIdx = 0; mbPartIdx < currMB->NumMbPart; mbPartIdx++)
+        {
+            if (currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+            {
+                status = se_v(stream, video->mvd_l1[mbPartIdx][0][0]);
+                status = se_v(stream, video->mvd_l1[mbPartIdx][0][1]);
+            }
+        }
+    }
+
+    return status;
+}
+
+/* see subclause 7.3.5.2 */
+AVCEnc_Status sub_mb_pred(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    int mbPartIdx, subMbPartIdx;
+    AVCSliceHeader *sliceHdr = video->sliceHdr;
+    uint max_ref_idx;
+    uint slice_type = video->slice_type;
+    uint sub_mb_type[4];
+
+    /* this should move somewhere else where we don't have to make this check */
+    if (currMB->mbMode == AVC_P8ref0)
+    {
+        memset(currMB->ref_idx_L0, 0, sizeof(int16)*4);
+    }
+
+    /* we have to check the values to make sure they are valid  */
+    /* assign values to currMB->sub_mb_type[] */
+    if (slice_type == AVC_P_SLICE)
+    {
+        InterpretSubMBTypeP(currMB, sub_mb_type);
+    }
+    /* no need to check for B-slice
+        else if(slice_type == AVC_B_SLICE)
+        {
+            InterpretSubMBTypeB(currMB,sub_mb_type);
+        }*/
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        status = ue_v(stream, sub_mb_type[mbPartIdx]);
+    }
+
+    /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+    max_ref_idx = sliceHdr->num_ref_idx_l0_active_minus1;
+    /*  if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+            max_ref_idx = 2*sliceHdr->num_ref_idx_l0_active_minus1 + 1; */
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        if ((sliceHdr->num_ref_idx_l0_active_minus1 > 0 /*|| currMB->mb_field_decoding_flag*/) &&
+                currMB->mbMode != AVC_P8ref0 && /*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+                currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+        {
+            status = te_v(stream, currMB->ref_idx_L0[mbPartIdx], max_ref_idx);
+        }
+        /* used in deblocking */
+        currMB->RefIdx[mbPartIdx] = video->RefPicList0[currMB->ref_idx_L0[mbPartIdx]]->RefIdx;
+    }
+    /* see subclause 7.4.5.1 for the range of ref_idx_lX */
+    max_ref_idx = sliceHdr->num_ref_idx_l1_active_minus1;
+    /*  if(video->MbaffFrameFlag && currMB->mb_field_decoding_flag)
+            max_ref_idx = 2*sliceHdr->num_ref_idx_l1_active_minus1 + 1;*/
+
+    if (sliceHdr->num_ref_idx_l1_active_minus1 > 0)
+    {
+        for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+        {
+            if (/*(sliceHdr->num_ref_idx_l1_active_minus1>0 || currMB->mb_field_decoding_flag) &&*/
+                /*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+                currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+            {
+                status = te_v(stream, currMB->ref_idx_L1[mbPartIdx], max_ref_idx);
+            }
+        }
+    }
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        if (/*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+            currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L1)
+        {
+            for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
+            {
+                status = se_v(stream, video->mvd_l0[mbPartIdx][subMbPartIdx][0]);
+                status = se_v(stream, video->mvd_l0[mbPartIdx][subMbPartIdx][1]);
+            }
+        }
+    }
+
+    for (mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++)
+    {
+        if (/*currMB->subMbMode[mbPartIdx]!=AVC_BDirect8 &&*/
+            currMB->MBPartPredMode[mbPartIdx][0] != AVC_Pred_L0)
+        {
+            for (subMbPartIdx = 0; subMbPartIdx < currMB->NumSubMbPart[mbPartIdx]; subMbPartIdx++)
+            {
+                status = se_v(stream, video->mvd_l1[mbPartIdx][subMbPartIdx][0]);
+                status = se_v(stream, video->mvd_l1[mbPartIdx][subMbPartIdx][1]);
+            }
+        }
+    }
+
+    return status;
+}
+
+/* input is mblock->sub_mb_type[] */
+void InterpretSubMBTypeP(AVCMacroblock *mblock, uint *sub_mb_type)
+{
+    int i;
+    /* see enum AVCMBType declaration */
+    /*const static AVCSubMBMode map2subMbMode[4] = {AVC_8x8,AVC_8x4,AVC_4x8,AVC_4x4};
+    const static int map2subPartWidth[4] = {8,8,4,4};
+    const static int map2subPartHeight[4] = {8,4,8,4};
+    const static int map2numSubPart[4] = {1,2,2,4};*/
+
+    for (i = 0; i < 4 ; i++)
+    {
+        sub_mb_type[i] = mblock->subMbMode[i] - AVC_8x8;
+    }
+
+    return ;
+}
+
+void InterpretSubMBTypeB(AVCMacroblock *mblock, uint *sub_mb_type)
+{
+    int i;
+    /* see enum AVCMBType declaration */
+    /*  const static AVCSubMBMode map2subMbMode[13] = {AVC_BDirect8,AVC_8x8,AVC_8x8,
+            AVC_8x8,AVC_8x4,AVC_4x8,AVC_8x4,AVC_4x8,AVC_8x4,AVC_4x8,AVC_4x4,AVC_4x4,AVC_4x4};
+        const static int map2subPartWidth[13] = {4,8,8,8,8,4,8,4,8,4,4,4,4};
+        const static int map2subPartHeight[13] = {4,8,8,8,4,8,4,8,4,8,4,4,4};
+        const static int map2numSubPart[13] = {4,1,1,1,2,2,2,2,2,2,4,4,4};
+        const static int map2predMode[13] = {3,0,1,2,0,0,1,1,2,2,0,1,2};*/
+
+    for (i = 0; i < 4 ; i++)
+    {
+        if (mblock->subMbMode[i] == AVC_BDirect8)
+        {
+            sub_mb_type[i] = 0;
+        }
+        else if (mblock->subMbMode[i] == AVC_8x8)
+        {
+            sub_mb_type[i] = 1 + mblock->MBPartPredMode[i][0];
+        }
+        else if (mblock->subMbMode[i] == AVC_4x4)
+        {
+            sub_mb_type[i] = 10 + mblock->MBPartPredMode[i][0];
+        }
+        else
+        {
+            sub_mb_type[i] = 4 + (mblock->MBPartPredMode[i][0] << 1) + (mblock->subMbMode[i] - AVC_8x4);
+        }
+    }
+
+    return ;
+}
+
+/* see subclause 8.3.1 */
+AVCEnc_Status EncodeIntra4x4Mode(AVCCommonObj *video, AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+    int intra4x4PredModeA = 0;
+    int intra4x4PredModeB, predIntra4x4PredMode;
+    int component, SubBlock_indx, block_x, block_y;
+    int dcOnlyPredictionFlag;
+    uint    flag;
+    int     rem = 0;
+    int     mode;
+    int bindx = 0;
+
+    for (component = 0; component < 4; component++) /* partition index */
+    {
+        block_x = ((component & 1) << 1);
+        block_y = ((component >> 1) << 1);
+
+        for (SubBlock_indx = 0; SubBlock_indx < 4; SubBlock_indx++) /* sub-partition index */
+        {
+            dcOnlyPredictionFlag = 0;
+            if (block_x > 0)
+            {
+                intra4x4PredModeA = currMB->i4Mode[(block_y << 2) + block_x - 1 ];
+            }
+            else
+            {
+                if (video->intraAvailA)
+                {
+                    if (video->mblock[video->mbAddrA].mbMode == AVC_I4)
+                    {
+                        intra4x4PredModeA = video->mblock[video->mbAddrA].i4Mode[(block_y << 2) + 3];
+                    }
+                    else
+                    {
+                        intra4x4PredModeA = AVC_I4_DC;
+                    }
+                }
+                else
+                {
+                    dcOnlyPredictionFlag = 1;
+                }
+            }
+
+            if (block_y > 0)
+            {
+                intra4x4PredModeB = currMB->i4Mode[((block_y-1) << 2) + block_x];
+            }
+            else
+            {
+                if (video->intraAvailB)
+                {
+                    if (video->mblock[video->mbAddrB].mbMode == AVC_I4)
+                    {
+                        intra4x4PredModeB = video->mblock[video->mbAddrB].i4Mode[(3 << 2) + block_x];
+                    }
+                    else
+                    {
+                        intra4x4PredModeB = AVC_I4_DC;
+                    }
+                }
+                else
+                {
+                    dcOnlyPredictionFlag = 1;
+                }
+            }
+
+            if (dcOnlyPredictionFlag)
+            {
+                intra4x4PredModeA = intra4x4PredModeB = AVC_I4_DC;
+            }
+
+            predIntra4x4PredMode = AVC_MIN(intra4x4PredModeA, intra4x4PredModeB);
+
+            flag = 0;
+            mode = currMB->i4Mode[(block_y<<2)+block_x];
+
+            if (mode == (AVCIntra4x4PredMode)predIntra4x4PredMode)
+            {
+                flag = 1;
+            }
+            else if (mode < predIntra4x4PredMode)
+            {
+                rem = mode;
+            }
+            else
+            {
+                rem = mode - 1;
+            }
+
+            BitstreamWrite1Bit(stream, flag);
+
+            if (!flag)
+            {
+                BitstreamWriteBits(stream, 3, rem);
+            }
+
+            bindx++;
+            block_y += (SubBlock_indx & 1) ;
+            block_x += (1 - 2 * (SubBlock_indx & 1)) ;
+        }
+    }
+
+    return AVCENC_SUCCESS;
+}
+
+
+
diff --git a/media/libstagefright/codecs/avc/enc/src/vlc_encode.cpp b/media/libstagefright/codecs/avc/enc/src/vlc_encode.cpp
new file mode 100644
index 0000000..222e709
--- /dev/null
+++ b/media/libstagefright/codecs/avc/enc/src/vlc_encode.cpp
@@ -0,0 +1,336 @@
+/* ------------------------------------------------------------------
+ * Copyright (C) 1998-2009 PacketVideo
+ *
+ * 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 "avcenc_lib.h"
+
+/**
+See algorithm in subclause 9.1, Table 9-1, Table 9-2. */
+AVCEnc_Status ue_v(AVCEncBitstream *bitstream, uint codeNum)
+{
+    if (AVCENC_SUCCESS != SetEGBitstring(bitstream, codeNum))
+        return AVCENC_FAIL;
+
+    return AVCENC_SUCCESS;
+}
+
+/**
+See subclause 9.1.1, Table 9-3 */
+AVCEnc_Status  se_v(AVCEncBitstream *bitstream, int value)
+{
+    uint codeNum;
+    AVCEnc_Status status;
+
+    if (value <= 0)
+    {
+        codeNum = -value * 2;
+    }
+    else
+    {
+        codeNum = value * 2 - 1;
+    }
+
+    status = ue_v(bitstream, codeNum);
+
+    return status;
+}
+
+AVCEnc_Status te_v(AVCEncBitstream *bitstream, uint value, uint range)
+{
+    AVCEnc_Status status;
+
+    if (range > 1)
+    {
+        return ue_v(bitstream, value);
+    }
+    else
+    {
+        status = BitstreamWrite1Bit(bitstream, 1 - value);
+        return status;
+    }
+}
+
+/**
+See subclause 9.1, Table 9-1, 9-2. */
+// compute leadingZeros and inforbits
+//codeNum = (1<<leadingZeros)-1+infobits;
+AVCEnc_Status SetEGBitstring(AVCEncBitstream *bitstream, uint codeNum)
+{
+    AVCEnc_Status status;
+    int leadingZeros;
+    int infobits;
+
+    if (!codeNum)
+    {
+        status = BitstreamWrite1Bit(bitstream, 1);
+        return status;
+    }
+
+    /* calculate leadingZeros and infobits */
+    leadingZeros = 1;
+    while ((uint)(1 << leadingZeros) < codeNum + 2)
+    {
+        leadingZeros++;
+    }
+    leadingZeros--;
+    infobits = codeNum - (1 << leadingZeros) + 1;
+
+    status = BitstreamWriteBits(bitstream, leadingZeros, 0);
+    infobits |= (1 << leadingZeros);
+    status = BitstreamWriteBits(bitstream, leadingZeros + 1, infobits);
+    return status;
+}
+
+/* see Table 9-4 assignment of codeNum to values of coded_block_pattern. */
+const static uint8 MapCBP2code[48][2] =
+{
+    {3, 0}, {29, 2}, {30, 3}, {17, 7}, {31, 4}, {18, 8}, {37, 17}, {8, 13}, {32, 5}, {38, 18}, {19, 9}, {9, 14},
+    {20, 10}, {10, 15}, {11, 16}, {2, 11}, {16, 1}, {33, 32}, {34, 33}, {21, 36}, {35, 34}, {22, 37}, {39, 44}, {4, 40},
+    {36, 35}, {40, 45}, {23, 38}, {5, 41}, {24, 39}, {6, 42}, {7, 43}, {1, 19}, {41, 6}, {42, 24}, {43, 25}, {25, 20},
+    {44, 26}, {26, 21}, {46, 46}, {12, 28}, {45, 27}, {47, 47}, {27, 22}, {13, 29}, {28, 23}, {14, 30}, {15, 31}, {0, 12}
+};
+
+AVCEnc_Status EncodeCBP(AVCMacroblock *currMB, AVCEncBitstream *stream)
+{
+    AVCEnc_Status status;
+    uint codeNum;
+
+    if (currMB->mbMode == AVC_I4)
+    {
+        codeNum = MapCBP2code[currMB->CBP][0];
+    }
+    else
+    {
+        codeNum = MapCBP2code[currMB->CBP][1];
+    }
+
+    status = ue_v(stream, codeNum);
+
+    return status;
+}
+
+AVCEnc_Status ce_TotalCoeffTrailingOnes(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff, int nC)
+{
+    const static uint8 totCoeffTrailOne[3][4][17][2] =
+    {
+        {   // 0702
+            {{1, 1}, {6, 5}, {8, 7}, {9, 7}, {10, 7}, {11, 7}, {13, 15}, {13, 11}, {13, 8}, {14, 15}, {14, 11}, {15, 15}, {15, 11}, {16, 15}, {16, 11}, {16, 7}, {16, 4}},
+            {{0, 0}, {2, 1}, {6, 4}, {8, 6}, {9, 6}, {10, 6}, {11, 6}, {13, 14}, {13, 10}, {14, 14}, {14, 10}, {15, 14}, {15, 10}, {15, 1}, {16, 14}, {16, 10}, {16, 6}},
+            {{0, 0}, {0, 0}, {3, 1}, {7, 5}, {8, 5}, {9, 5}, {10, 5}, {11, 5}, {13, 13}, {13, 9}, {14, 13}, {14, 9}, {15, 13}, {15, 9}, {16, 13}, {16, 9}, {16, 5}},
+            {{0, 0}, {0, 0}, {0, 0}, {5, 3}, {6, 3}, {7, 4}, {8, 4}, {9, 4}, {10, 4}, {11, 4}, {13, 12}, {14, 12}, {14, 8}, {15, 12}, {15, 8}, {16, 12}, {16, 8}},
+        },
+        {
+            {{2, 3}, {6, 11}, {6, 7}, {7, 7}, {8, 7}, {8, 4}, {9, 7}, {11, 15}, {11, 11}, {12, 15}, {12, 11}, {12, 8}, {13, 15}, {13, 11}, {13, 7}, {14, 9}, {14, 7}},
+            {{0, 0}, {2, 2}, {5, 7}, {6, 10}, {6, 6}, {7, 6}, {8, 6}, {9, 6}, {11, 14}, {11, 10}, {12, 14}, {12, 10}, {13, 14}, {13, 10}, {14, 11}, {14, 8}, {14, 6}},
+            {{0, 0}, {0, 0}, {3, 3}, {6, 9}, {6, 5}, {7, 5}, {8, 5}, {9, 5}, {11, 13}, {11, 9}, {12, 13}, {12, 9}, {13, 13}, {13, 9}, {13, 6}, {14, 10}, {14, 5}},
+            {{0, 0}, {0, 0}, {0, 0}, {4, 5}, {4, 4}, {5, 6}, {6, 8}, {6, 4}, {7, 4}, {9, 4}, {11, 12}, {11, 8}, {12, 12}, {13, 12}, {13, 8}, {13, 1}, {14, 4}},
+        },
+        {
+            {{4, 15}, {6, 15}, {6, 11}, {6, 8}, {7, 15}, {7, 11}, {7, 9}, {7, 8}, {8, 15}, {8, 11}, {9, 15}, {9, 11}, {9, 8}, {10, 13}, {10, 9}, {10, 5}, {10, 1}},
+            {{0, 0}, {4, 14}, {5, 15}, {5, 12}, {5, 10}, {5, 8}, {6, 14}, {6, 10}, {7, 14}, {8, 14}, {8, 10}, {9, 14}, {9, 10}, {9, 7}, {10, 12}, {10, 8}, {10, 4}},
+            {{0, 0}, {0, 0}, {4, 13}, {5, 14}, {5, 11}, {5, 9}, {6, 13}, {6, 9}, {7, 13}, {7, 10}, {8, 13}, {8, 9}, {9, 13}, {9, 9}, {10, 11}, {10, 7}, {10, 3}},
+            {{0, 0}, {0, 0}, {0, 0}, {4, 12}, {4, 11}, {4, 10}, {4, 9}, {4, 8}, {5, 13}, {6, 12}, {7, 12}, {8, 12}, {8, 8}, {9, 12}, {10, 10}, {10, 6}, {10, 2}}
+        }
+    };
+
+
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    uint code, len;
+    int vlcnum;
+
+    if (TrailingOnes > 3)
+    {
+        return AVCENC_TRAILINGONES_FAIL;
+    }
+
+    if (nC >= 8)
+    {
+        if (TotalCoeff)
+        {
+            code = ((TotalCoeff - 1) << 2) | (TrailingOnes);
+        }
+        else
+        {
+            code = 3;
+        }
+        status = BitstreamWriteBits(stream, 6, code);
+    }
+    else
+    {
+        if (nC < 2)
+        {
+            vlcnum = 0;
+        }
+        else if (nC < 4)
+        {
+            vlcnum = 1;
+        }
+        else
+        {
+            vlcnum = 2;
+        }
+
+        len = totCoeffTrailOne[vlcnum][TrailingOnes][TotalCoeff][0];
+        code = totCoeffTrailOne[vlcnum][TrailingOnes][TotalCoeff][1];
+        status = BitstreamWriteBits(stream, len, code);
+    }
+
+    return status;
+}
+
+AVCEnc_Status ce_TotalCoeffTrailingOnesChromaDC(AVCEncBitstream *stream, int TrailingOnes, int TotalCoeff)
+{
+    const static uint8 totCoeffTrailOneChrom[4][5][2] =
+    {
+        { {2, 1}, {6, 7}, {6, 4}, {6, 3}, {6, 2}},
+        { {0, 0}, {1, 1}, {6, 6}, {7, 3}, {8, 3}},
+        { {0, 0}, {0, 0}, {3, 1}, {7, 2}, {8, 2}},
+        { {0, 0}, {0, 0}, {0, 0}, {6, 5}, {7, 0}},
+    };
+
+    AVCEnc_Status status = AVCENC_SUCCESS;
+    uint code, len;
+
+    len = totCoeffTrailOneChrom[TrailingOnes][TotalCoeff][0];
+    code = totCoeffTrailOneChrom[TrailingOnes][TotalCoeff][1];
+    status = BitstreamWriteBits(stream, len, code);
+
+    return status;
+}
+
+/* see Table 9-7 and 9-8 */
+AVCEnc_Status ce_TotalZeros(AVCEncBitstream *stream, int total_zeros, int TotalCoeff)
+{
+    const static uint8 lenTotalZeros[15][16] =
+    {
+        { 1, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9},
+        { 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6},
+        { 4, 3, 3, 3, 4, 4, 3, 3, 4, 5, 5, 6, 5, 6},
+        { 5, 3, 4, 4, 3, 3, 3, 4, 3, 4, 5, 5, 5},
+        { 4, 4, 4, 3, 3, 3, 3, 3, 4, 5, 4, 5},
+        { 6, 5, 3, 3, 3, 3, 3, 3, 4, 3, 6},
+        { 6, 5, 3, 3, 3, 2, 3, 4, 3, 6},
+        { 6, 4, 5, 3, 2, 2, 3, 3, 6},
+        { 6, 6, 4, 2, 2, 3, 2, 5},
+        { 5, 5, 3, 2, 2, 2, 4},
+        { 4, 4, 3, 3, 1, 3},
+        { 4, 4, 2, 1, 3},
+        { 3, 3, 1, 2},
+        { 2, 2, 1},
+        { 1, 1},
+    };
+
+    const static uint8 codTotalZeros[15][16] =
+    {
+        {1, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 1},
+        {7, 6, 5, 4, 3, 5, 4, 3, 2, 3, 2, 3, 2, 1, 0},
+        {5, 7, 6, 5, 4, 3, 4, 3, 2, 3, 2, 1, 1, 0},
+        {3, 7, 5, 4, 6, 5, 4, 3, 3, 2, 2, 1, 0},
+        {5, 4, 3, 7, 6, 5, 4, 3, 2, 1, 1, 0},
+        {1, 1, 7, 6, 5, 4, 3, 2, 1, 1, 0},
+        {1, 1, 5, 4, 3, 3, 2, 1, 1, 0},
+        {1, 1, 1, 3, 3, 2, 2, 1, 0},
+        {1, 0, 1, 3, 2, 1, 1, 1, },
+        {1, 0, 1, 3, 2, 1, 1, },
+        {0, 1, 1, 2, 1, 3},
+        {0, 1, 1, 1, 1},
+        {0, 1, 1, 1},
+        {0, 1, 1},
+        {0, 1},
+    };
+    int len, code;
+    AVCEnc_Status status;
+
+    len = lenTotalZeros[TotalCoeff-1][total_zeros];
+    code = codTotalZeros[TotalCoeff-1][total_zeros];
+
+    status = BitstreamWriteBits(stream, len, code);
+
+    return status;
+}
+
+/* see Table 9-9 */
+AVCEnc_Status ce_TotalZerosChromaDC(AVCEncBitstream *stream, int total_zeros, int TotalCoeff)
+{
+    const static uint8 lenTotalZerosChromaDC[3][4] =
+    {
+        { 1, 2, 3, 3, },
+        { 1, 2, 2, 0, },
+        { 1, 1, 0, 0, },
+    };
+
+    const static uint8 codTotalZerosChromaDC[3][4] =
+    {
+        { 1, 1, 1, 0, },
+        { 1, 1, 0, 0, },
+        { 1, 0, 0, 0, },
+    };
+
+    int len, code;
+    AVCEnc_Status status;
+
+    len = lenTotalZerosChromaDC[TotalCoeff-1][total_zeros];
+    code = codTotalZerosChromaDC[TotalCoeff-1][total_zeros];
+
+    status = BitstreamWriteBits(stream, len, code);
+
+    return status;
+}
+
+/* see Table 9-10 */
+AVCEnc_Status ce_RunBefore(AVCEncBitstream *stream, int run_before, int zerosLeft)
+{
+    const static uint8 lenRunBefore[7][16] =
+    {
+        {1, 1},
+        {1, 2, 2},
+        {2, 2, 2, 2},
+        {2, 2, 2, 3, 3},
+        {2, 2, 3, 3, 3, 3},
+        {2, 3, 3, 3, 3, 3, 3},
+        {3, 3, 3, 3, 3, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11},
+    };
+
+    const static uint8 codRunBefore[7][16] =
+    {
+        {1, 0},
+        {1, 1, 0},
+        {3, 2, 1, 0},
+        {3, 2, 1, 1, 0},
+        {3, 2, 3, 2, 1, 0},
+        {3, 0, 1, 3, 2, 5, 4},
+        {7, 6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+    };
+
+    int len, code;
+    AVCEnc_Status status;
+
+    if (zerosLeft <= 6)
+    {
+        len = lenRunBefore[zerosLeft-1][run_before];
+        code = codRunBefore[zerosLeft-1][run_before];
+    }
+    else
+    {
+        len = lenRunBefore[6][run_before];
+        code = codRunBefore[6][run_before];
+    }
+
+    status = BitstreamWriteBits(stream, len, code);
+
+
+    return status;
+}
diff --git a/media/libstagefright/include/AVCEncoder.h b/media/libstagefright/include/AVCEncoder.h
new file mode 100644
index 0000000..4fe2e30
--- /dev/null
+++ b/media/libstagefright/include/AVCEncoder.h
@@ -0,0 +1,90 @@
+/*
+ * 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 AVC_ENCODER_H_
+
+#define AVC_ENCODER_H_
+
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/Vector.h>
+
+struct tagAVCHandle;
+struct tagAVCEncParam;
+
+namespace android {
+
+struct MediaBuffer;
+struct MediaBufferGroup;
+
+struct AVCEncoder : public MediaSource,
+                    public MediaBufferObserver {
+    AVCEncoder(const sp<MediaSource> &source,
+            const sp<MetaData>& meta);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+    virtual void signalBufferReturned(MediaBuffer *buffer);
+
+    // Callbacks required by the encoder
+    int32_t allocOutputBuffers(unsigned int sizeInMbs, unsigned int numBuffers);
+    void    unbindOutputBuffer(int32_t index);
+    int32_t bindOutputBuffer(int32_t index, uint8_t **yuv);
+
+protected:
+    virtual ~AVCEncoder();
+
+private:
+    sp<MediaSource> mSource;
+    sp<MetaData>    mFormat;
+    sp<MetaData>    mMeta;
+
+    int32_t  mVideoWidth;
+    int32_t  mVideoHeight;
+    int32_t  mVideoFrameRate;
+    int32_t  mVideoBitRate;
+    int32_t  mVideoColorFormat;
+    int64_t  mNumInputFrames;
+    status_t mInitCheck;
+    bool     mStarted;
+    bool     mSpsPpsHeaderReceived;
+    bool     mReadyForNextFrame;
+    int32_t  mIsIDRFrame;  // for set kKeyIsSyncFrame
+
+    tagAVCHandle          *mHandle;
+    tagAVCEncParam        *mEncParams;
+    MediaBuffer           *mInputBuffer;
+    uint8_t               *mInputFrameData;
+    MediaBufferGroup      *mGroup;
+    Vector<MediaBuffer *> mOutputBuffers;
+
+
+    status_t initCheck(const sp<MetaData>& meta);
+    void releaseOutputBuffers();
+
+    AVCEncoder(const AVCEncoder &);
+    AVCEncoder &operator=(const AVCEncoder &);
+};
+
+}  // namespace android
+
+#endif  // AVC_ENCODER_H_
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 89d53e2..a4dde51 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -22,6 +22,8 @@
 #include <ui/InputTransport.h>
 #include <utils/PollLoop.h>
 
+#include <android_runtime/android_app_NativeActivity.h>
+
 #include <poll.h>
 
 using android::InputEvent;
@@ -187,65 +189,21 @@
 
 void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper,
         ALooper_callbackFunc* callback, void* data) {
-    queue->setPollLoop(static_cast<android::PollLoop*>(looper));
-    ALooper_addFd(looper, queue->getConsumer().getChannel()->getReceivePipeFd(),
-            POLLIN, callback, data);
+    queue->attachLooper(looper, callback, data);
 }
 
 void AInputQueue_detachLooper(AInputQueue* queue) {
-    queue->getPollLoop()->removeCallback(
-            queue->getConsumer().getChannel()->getReceivePipeFd());
+    queue->detachLooper();
 }
 
 int AInputQueue_hasEvents(AInputQueue* queue) {
-    struct pollfd pfd;
-    
-    pfd.fd = queue->getConsumer().getChannel()->getReceivePipeFd();
-    pfd.events = POLLIN;
-    pfd.revents = 0;
-    
-    int nfd = poll(&pfd, 1, 0);
-    if (nfd <= 0) return nfd;
-    return pfd.revents == POLLIN ? 1 : -1;
+    return queue->hasEvents();
 }
 
 int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent) {
-    *outEvent = NULL;
-    
-    int32_t res = queue->getConsumer().receiveDispatchSignal();
-    if (res != android::OK) {
-        LOGE("channel '%s' ~ Failed to receive dispatch signal.  status=%d",
-                queue->getConsumer().getChannel()->getName().string(), res);
-        return -1;
-    }
-    
-    InputEvent* myEvent = NULL;
-    res = queue->consume(&myEvent);
-    if (res != android::OK) {
-        LOGW("channel '%s' ~ Failed to consume input event.  status=%d",
-                queue->getConsumer().getChannel()->getName().string(), res);
-        queue->getConsumer().sendFinishedSignal();
-        return -1;
-    }
-    
-    *outEvent = myEvent;
-    return 0;
+    return queue->getEvent(outEvent);
 }
 
-void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event,
-        int handled) {
-    if (!handled && ((InputEvent*)event)->getType() == INPUT_EVENT_TYPE_KEY
-            && ((KeyEvent*)event)->hasDefaultAction()) {
-        // The app didn't handle this, but it may have a default action
-        // associated with it.  We need to hand this back to Java to be
-        // executed.
-        queue->doDefaultKey((KeyEvent*)event);
-        return;
-    }
-    
-    int32_t res = queue->getConsumer().sendFinishedSignal();
-    if (res != android::OK) {
-        LOGW("Failed to send finished signal on channel '%s'.  status=%d",
-                queue->getConsumer().getChannel()->getName().string(), res);
-    }
+void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled) {
+    queue->finishEvent(event, handled != 0);
 }
diff --git a/native/android/native_activity.cpp b/native/android/native_activity.cpp
index 509cc33..0c6823a 100644
--- a/native/android/native_activity.cpp
+++ b/native/android/native_activity.cpp
@@ -29,3 +29,11 @@
 		uint32_t addFlags, uint32_t removeFlags) {
 	android_NativeActivity_setWindowFlags(activity, addFlags, addFlags|removeFlags);
 }
+
+void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags) {
+	android_NativeActivity_showSoftInput(activity, flags);
+}
+
+void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags) {
+	android_NativeActivity_hideSoftInput(activity, flags);
+}
diff --git a/native/glue/threaded_app/threaded_app.c b/native/glue/threaded_app/threaded_app.c
index 2411e93..452c735 100644
--- a/native/glue/threaded_app/threaded_app.c
+++ b/native/glue/threaded_app/threaded_app.c
@@ -18,6 +18,7 @@
 #include <jni.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
 #include <sys/resource.h>
@@ -75,6 +76,19 @@
             pthread_cond_broadcast(&android_app->cond);
             pthread_mutex_unlock(&android_app->mutex);
             break;
+
+        case APP_CMD_WINDOW_REDRAW_NEEDED:
+            LOGI("APP_CMD_WINDOW_REDRAW_NEEDED\n");
+            pthread_mutex_lock(&android_app->mutex);
+            android_app->redrawNeeded = 0;
+            pthread_cond_broadcast(&android_app->cond);
+            pthread_mutex_unlock(&android_app->mutex);
+            break;
+
+        case APP_CMD_CONTENT_RECT_CHANGED:
+            LOGI("APP_CMD_CONTENT_RECT_CHANGED\n");
+            android_app->contentRect = android_app->pendingContentRect;
+            break;
             
         case APP_CMD_DESTROY:
             LOGI("APP_CMD_DESTROY\n");
@@ -133,6 +147,12 @@
     }
     android_app->msgread = msgpipe[0];
     android_app->msgwrite = msgpipe[1];
+    int result = fcntl(android_app->msgread, F_SETFL, O_NONBLOCK);
+    if (result != 0) LOGW("Could not make message read pipe "
+            "non-blocking: %s", strerror(errno));
+    result = fcntl(android_app->msgwrite, F_SETFL, O_NONBLOCK);
+    if (result != 0) LOGW("Could not make message write pipe "
+            "non-blocking: %s", strerror(errno));
     
     pthread_attr_t attr; 
     pthread_attr_init(&attr);
@@ -184,6 +204,23 @@
     pthread_mutex_unlock(&android_app->mutex);
 }
 
+static void android_app_wait_redraw(struct android_app* android_app) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->redrawNeeded = 1;
+    android_app_write_cmd(android_app, APP_CMD_WINDOW_REDRAW_NEEDED);
+    while (android_app->redrawNeeded) {
+        pthread_cond_wait(&android_app->cond, &android_app->mutex);
+    }
+    pthread_mutex_unlock(&android_app->mutex);
+}
+
+static void android_app_set_content_rect(struct android_app* android_app, const ARect* rect) {
+    pthread_mutex_lock(&android_app->mutex);
+    android_app->pendingContentRect = *rect;
+    android_app_write_cmd(android_app, APP_CMD_CONTENT_RECT_CHANGED);
+    pthread_mutex_unlock(&android_app->mutex);
+}
+
 static void android_app_free(struct android_app* android_app) {
     pthread_mutex_lock(&android_app->mutex);
     android_app_write_cmd(android_app, APP_CMD_DESTROY);
@@ -231,6 +268,8 @@
 
 static void onLowMemory(ANativeActivity* activity) {
     LOGI("LowMemory: %p\n", activity);
+    android_app_write_cmd((struct android_app*)activity->instance,
+            APP_CMD_LOW_MEMORY);
 }
 
 static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
@@ -244,6 +283,23 @@
     android_app_set_window((struct android_app*)activity->instance, window);
 }
 
+static void onNativeWindowResized(ANativeActivity* activity, ANativeWindow* window) {
+    LOGI("NativeWindowResized: %p -- %p\n", activity, window);
+    android_app_write_cmd((struct android_app*)activity->instance,
+            APP_CMD_WINDOW_RESIZED);
+}
+
+static void onNativeWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* window) {
+    LOGI("NativeWindowRedrawNeeded: %p -- %p\n", activity, window);
+    android_app_wait_redraw((struct android_app*)activity->instance);
+}
+
+static void onContentRectChanged(ANativeActivity* activity, const ARect* rect) {
+    LOGI("ContentRectChanged: %p -- (%d,%d)-(%d,%d)\n", activity, rect->left,
+            rect->top, rect->right, rect->bottom);
+    android_app_set_content_rect((struct android_app*)activity->instance, rect);
+}
+
 static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
     LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window);
     android_app_set_window((struct android_app*)activity->instance, NULL);
@@ -268,12 +324,15 @@
     activity->callbacks->onSaveInstanceState = onSaveInstanceState;
     activity->callbacks->onPause = onPause;
     activity->callbacks->onStop = onStop;
-    activity->callbacks->onLowMemory = onLowMemory;
     activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
     activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
+    activity->callbacks->onNativeWindowResized = onNativeWindowResized;
+    activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;
     activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
     activity->callbacks->onInputQueueCreated = onInputQueueCreated;
     activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
+    activity->callbacks->onContentRectChanged = onContentRectChanged;
+    activity->callbacks->onLowMemory = onLowMemory;
     
     activity->instance = android_app_create(activity);
 }
diff --git a/native/include/android/input.h b/native/include/android/input.h
index 014b6a3..25dd68e 100644
--- a/native/include/android/input.h
+++ b/native/include/android/input.h
@@ -68,7 +68,10 @@
     INPUT_DEVICE_CLASS_TOUCHSCREEN_MT= 0x00000010,
 
     /* The input device is a directional pad. */
-    INPUT_DEVICE_CLASS_DPAD          = 0x00000020
+    INPUT_DEVICE_CLASS_DPAD          = 0x00000020,
+
+    /* The input device is a gamepad (implies keyboard). */
+    INPUT_DEVICE_CLASS_GAMEPAD       = 0x00000040
 };
 
 /*
diff --git a/native/include/android/keycodes.h b/native/include/android/keycodes.h
index 36855c5..496eccc0 100644
--- a/native/include/android/keycodes.h
+++ b/native/include/android/keycodes.h
@@ -41,114 +41,122 @@
 
 /*
  * Key codes.
- *
- * XXX: The declarations in <ui/KeycodeLabel.h> should be updated to use these instead.
- *      We should probably move this into android/keycodes.h and add some new API for
- *      getting labels so that we can remove the other tables also in KeycodeLabel.h.
  */
 enum {
-    KEYCODE_UNKNOWN         = 0,
-    KEYCODE_SOFT_LEFT       = 1,
-    KEYCODE_SOFT_RIGHT      = 2,
-    KEYCODE_HOME            = 3,
-    KEYCODE_BACK            = 4,
-    KEYCODE_CALL            = 5,
-    KEYCODE_ENDCALL         = 6,
-    KEYCODE_0               = 7,
-    KEYCODE_1               = 8,
-    KEYCODE_2               = 9,
-    KEYCODE_3               = 10,
-    KEYCODE_4               = 11,
-    KEYCODE_5               = 12,
-    KEYCODE_6               = 13,
-    KEYCODE_7               = 14,
-    KEYCODE_8               = 15,
-    KEYCODE_9               = 16,
-    KEYCODE_STAR            = 17,
-    KEYCODE_POUND           = 18,
-    KEYCODE_DPAD_UP         = 19,
-    KEYCODE_DPAD_DOWN       = 20,
-    KEYCODE_DPAD_LEFT       = 21,
-    KEYCODE_DPAD_RIGHT      = 22,
-    KEYCODE_DPAD_CENTER     = 23,
-    KEYCODE_VOLUME_UP       = 24,
-    KEYCODE_VOLUME_DOWN     = 25,
-    KEYCODE_POWER           = 26,
-    KEYCODE_CAMERA          = 27,
-    KEYCODE_CLEAR           = 28,
-    KEYCODE_A               = 29,
-    KEYCODE_B               = 30,
-    KEYCODE_C               = 31,
-    KEYCODE_D               = 32,
-    KEYCODE_E               = 33,
-    KEYCODE_F               = 34,
-    KEYCODE_G               = 35,
-    KEYCODE_H               = 36,
-    KEYCODE_I               = 37,
-    KEYCODE_J               = 38,
-    KEYCODE_K               = 39,
-    KEYCODE_L               = 40,
-    KEYCODE_M               = 41,
-    KEYCODE_N               = 42,
-    KEYCODE_O               = 43,
-    KEYCODE_P               = 44,
-    KEYCODE_Q               = 45,
-    KEYCODE_R               = 46,
-    KEYCODE_S               = 47,
-    KEYCODE_T               = 48,
-    KEYCODE_U               = 49,
-    KEYCODE_V               = 50,
-    KEYCODE_W               = 51,
-    KEYCODE_X               = 52,
-    KEYCODE_Y               = 53,
-    KEYCODE_Z               = 54,
-    KEYCODE_COMMA           = 55,
-    KEYCODE_PERIOD          = 56,
-    KEYCODE_ALT_LEFT        = 57,
-    KEYCODE_ALT_RIGHT       = 58,
-    KEYCODE_SHIFT_LEFT      = 59,
-    KEYCODE_SHIFT_RIGHT     = 60,
-    KEYCODE_TAB             = 61,
-    KEYCODE_SPACE           = 62,
-    KEYCODE_SYM             = 63,
-    KEYCODE_EXPLORER        = 64,
-    KEYCODE_ENVELOPE        = 65,
-    KEYCODE_ENTER           = 66,
-    KEYCODE_DEL             = 67,
-    KEYCODE_GRAVE           = 68,
-    KEYCODE_MINUS           = 69,
-    KEYCODE_EQUALS          = 70,
-    KEYCODE_LEFT_BRACKET    = 71,
-    KEYCODE_RIGHT_BRACKET   = 72,
-    KEYCODE_BACKSLASH       = 73,
-    KEYCODE_SEMICOLON       = 74,
-    KEYCODE_APOSTROPHE      = 75,
-    KEYCODE_SLASH           = 76,
-    KEYCODE_AT              = 77,
-    KEYCODE_NUM             = 78,
-    KEYCODE_HEADSETHOOK     = 79,
-    KEYCODE_FOCUS           = 80,   // *Camera* focus
-    KEYCODE_PLUS            = 81,
-    KEYCODE_MENU            = 82,
-    KEYCODE_NOTIFICATION    = 83,
-    KEYCODE_SEARCH          = 84,
-    KEYCODE_MEDIA_PLAY_PAUSE= 85,
-    KEYCODE_MEDIA_STOP      = 86,
-    KEYCODE_MEDIA_NEXT      = 87,
-    KEYCODE_MEDIA_PREVIOUS  = 88,
-    KEYCODE_MEDIA_REWIND    = 89,
-    KEYCODE_MEDIA_FAST_FORWARD = 90,
-    KEYCODE_MUTE            = 91,
-    KEYCODE_PAGE_UP         = 92,
-    KEYCODE_PAGE_DOWN       = 93
+    AKEYCODE_UNKNOWN         = 0,
+    AKEYCODE_SOFT_LEFT       = 1,
+    AKEYCODE_SOFT_RIGHT      = 2,
+    AKEYCODE_HOME            = 3,
+    AKEYCODE_BACK            = 4,
+    AKEYCODE_CALL            = 5,
+    AKEYCODE_ENDCALL         = 6,
+    AKEYCODE_0               = 7,
+    AKEYCODE_1               = 8,
+    AKEYCODE_2               = 9,
+    AKEYCODE_3               = 10,
+    AKEYCODE_4               = 11,
+    AKEYCODE_5               = 12,
+    AKEYCODE_6               = 13,
+    AKEYCODE_7               = 14,
+    AKEYCODE_8               = 15,
+    AKEYCODE_9               = 16,
+    AKEYCODE_STAR            = 17,
+    AKEYCODE_POUND           = 18,
+    AKEYCODE_DPAD_UP         = 19,
+    AKEYCODE_DPAD_DOWN       = 20,
+    AKEYCODE_DPAD_LEFT       = 21,
+    AKEYCODE_DPAD_RIGHT      = 22,
+    AKEYCODE_DPAD_CENTER     = 23,
+    AKEYCODE_VOLUME_UP       = 24,
+    AKEYCODE_VOLUME_DOWN     = 25,
+    AKEYCODE_POWER           = 26,
+    AKEYCODE_CAMERA          = 27,
+    AKEYCODE_CLEAR           = 28,
+    AKEYCODE_A               = 29,
+    AKEYCODE_B               = 30,
+    AKEYCODE_C               = 31,
+    AKEYCODE_D               = 32,
+    AKEYCODE_E               = 33,
+    AKEYCODE_F               = 34,
+    AKEYCODE_G               = 35,
+    AKEYCODE_H               = 36,
+    AKEYCODE_I               = 37,
+    AKEYCODE_J               = 38,
+    AKEYCODE_K               = 39,
+    AKEYCODE_L               = 40,
+    AKEYCODE_M               = 41,
+    AKEYCODE_N               = 42,
+    AKEYCODE_O               = 43,
+    AKEYCODE_P               = 44,
+    AKEYCODE_Q               = 45,
+    AKEYCODE_R               = 46,
+    AKEYCODE_S               = 47,
+    AKEYCODE_T               = 48,
+    AKEYCODE_U               = 49,
+    AKEYCODE_V               = 50,
+    AKEYCODE_W               = 51,
+    AKEYCODE_X               = 52,
+    AKEYCODE_Y               = 53,
+    AKEYCODE_Z               = 54,
+    AKEYCODE_COMMA           = 55,
+    AKEYCODE_PERIOD          = 56,
+    AKEYCODE_ALT_LEFT        = 57,
+    AKEYCODE_ALT_RIGHT       = 58,
+    AKEYCODE_SHIFT_LEFT      = 59,
+    AKEYCODE_SHIFT_RIGHT     = 60,
+    AKEYCODE_TAB             = 61,
+    AKEYCODE_SPACE           = 62,
+    AKEYCODE_SYM             = 63,
+    AKEYCODE_EXPLORER        = 64,
+    AKEYCODE_ENVELOPE        = 65,
+    AKEYCODE_ENTER           = 66,
+    AKEYCODE_DEL             = 67,
+    AKEYCODE_GRAVE           = 68,
+    AKEYCODE_MINUS           = 69,
+    AKEYCODE_EQUALS          = 70,
+    AKEYCODE_LEFT_BRACKET    = 71,
+    AKEYCODE_RIGHT_BRACKET   = 72,
+    AKEYCODE_BACKSLASH       = 73,
+    AKEYCODE_SEMICOLON       = 74,
+    AKEYCODE_APOSTROPHE      = 75,
+    AKEYCODE_SLASH           = 76,
+    AKEYCODE_AT              = 77,
+    AKEYCODE_NUM             = 78,
+    AKEYCODE_HEADSETHOOK     = 79,
+    AKEYCODE_FOCUS           = 80,   // *Camera* focus
+    AKEYCODE_PLUS            = 81,
+    AKEYCODE_MENU            = 82,
+    AKEYCODE_NOTIFICATION    = 83,
+    AKEYCODE_SEARCH          = 84,
+    AKEYCODE_MEDIA_PLAY_PAUSE= 85,
+    AKEYCODE_MEDIA_STOP      = 86,
+    AKEYCODE_MEDIA_NEXT      = 87,
+    AKEYCODE_MEDIA_PREVIOUS  = 88,
+    AKEYCODE_MEDIA_REWIND    = 89,
+    AKEYCODE_MEDIA_FAST_FORWARD = 90,
+    AKEYCODE_MUTE            = 91,
+    AKEYCODE_PAGE_UP         = 92,
+    AKEYCODE_PAGE_DOWN       = 93,
+    AKEYCODE_PICTSYMBOLS     = 94,
+    AKEYCODE_SWITCH_CHARSET  = 95,
+    AKEYCODE_BUTTON_A        = 96,
+    AKEYCODE_BUTTON_B        = 97,
+    AKEYCODE_BUTTON_C        = 98,
+    AKEYCODE_BUTTON_X        = 99,
+    AKEYCODE_BUTTON_Y        = 100,
+    AKEYCODE_BUTTON_Z        = 101,
+    AKEYCODE_BUTTON_L1       = 102,
+    AKEYCODE_BUTTON_R1       = 103,
+    AKEYCODE_BUTTON_L2       = 104,
+    AKEYCODE_BUTTON_R2       = 105,
+    AKEYCODE_BUTTON_THUMBL   = 106,
+    AKEYCODE_BUTTON_THUMBR   = 107,
+    AKEYCODE_BUTTON_START    = 108,
+    AKEYCODE_BUTTON_SELECT   = 109,
+    AKEYCODE_BUTTON_MODE     = 110,
 
-    /* NOTE: If you add a new keycode here you must also add it to:
-     *  native/include/android/keycodes.h
-     *  frameworks/base/include/ui/KeycodeLabels.h
-     *   frameworks/base/core/java/android/view/KeyEvent.java
-     *   tools/puppet_master/PuppetMaster.nav_keys.py
-     *   frameworks/base/core/res/res/values/attrs.xml
-     */
+    // NOTE: If you add a new keycode here you must also add it to several other files.
+    //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
 };
 
 #ifdef __cplusplus
diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h
index d0ff052..ea6f05f 100644
--- a/native/include/android/native_activity.h
+++ b/native/include/android/native_activity.h
@@ -147,6 +147,21 @@
     void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window);
 
     /**
+     * The drawing window for this native activity has been resized.  You should
+     * retrieve the new size from the window and ensure that your rendering in
+     * it now matches.
+     */
+    void (*onNativeWindowResized)(ANativeActivity* activity, ANativeWindow* window);
+
+    /**
+     * The drawing window for this native activity needs to be redrawn.  To avoid
+     * transient artifacts during screen changes (such resizing after rotation),
+     * applications should not return from this function until they have finished
+     * drawing their window in its current state.
+     */
+    void (*onNativeWindowRedrawNeeded)(ANativeActivity* activity, ANativeWindow* window);
+
+    /**
      * The drawing window for this native activity is going to be destroyed.
      * You MUST ensure that you do not touch the window object after returning
      * from this function: in the common case of drawing to the window from
@@ -170,6 +185,11 @@
     void (*onInputQueueDestroyed)(ANativeActivity* activity, AInputQueue* queue);
 
     /**
+     * The rectangle in the window in which content should be placed has changed.
+     */
+    void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect);
+
+    /**
      * The system is running low on memory.  Use this callback to release
      * resources you do not need, to help the system avoid killing more
      * important processes.
@@ -197,6 +217,28 @@
 void ANativeActivity_setWindowFlags(ANativeActivity* activity,
         uint32_t addFlags, uint32_t removeFlags);
 
+/**
+ * Flags for ANativeActivity_showSoftInput; see the Java InputMethodManager
+ * API for documentation.
+ */
+enum {
+    ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001,
+    ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002,
+};
+
+void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags);
+
+/**
+ * Flags for ANativeActivity_hideSoftInput; see the Java InputMethodManager
+ * API for documentation.
+ */
+enum {
+    ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001,
+    ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002,
+};
+
+void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags);
+
 #ifdef __cplusplus
 };
 #endif
diff --git a/native/include/android_glue/threaded_app.h b/native/include/android_glue/threaded_app.h
index adfdbea..2b58e9c 100644
--- a/native/include/android_glue/threaded_app.h
+++ b/native/include/android_glue/threaded_app.h
@@ -48,6 +48,10 @@
     // When non-NULL, this is the window surface that the app can draw in.
     ANativeWindow* window;
 
+    // Current content rectangle of the window; this is the area where the
+    // window's content should be placed to be seen by the user.
+    ARect contentRect;
+
     // Current state of the app's activity.  May be either APP_CMD_START,
     // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
     int activityState;
@@ -69,8 +73,10 @@
 
     int running;
     int destroyed;
+    int redrawNeeded;
     AInputQueue* pendingInputQueue;
     ANativeWindow* pendingWindow;
+    ARect pendingContentRect;
 };
 
 enum {
@@ -105,6 +111,26 @@
     APP_CMD_WINDOW_CHANGED,
 
     /**
+     * Command from main thread: the current ANativeWindow has been resized.
+     * Please redraw with its new size.
+     */
+    APP_CMD_WINDOW_RESIZED,
+
+    /**
+     * Command from main thread: the system needs that the current ANativeWindow
+     * be redrawn.  You should redraw the window before handing this to
+     * android_app_exec_cmd() in order to avoid transient drawing glitches.
+     */
+    APP_CMD_WINDOW_REDRAW_NEEDED,
+
+    /**
+     * Command from main thread: the content area of the window has changed,
+     * such as from the soft input window being shown or hidden.  You can
+     * find the new content rect in android_app::contentRect.
+     */
+    APP_CMD_CONTENT_RECT_CHANGED,
+
+    /**
      * Command from main thread: the app's activity window has gained
      * input focus.
      */
@@ -117,6 +143,12 @@
     APP_CMD_LOST_FOCUS,
 
     /**
+     * Command from main thread: the system is running low on memory.
+     * Try to reduce your memory use.
+     */
+    APP_CMD_LOW_MEMORY,
+
+    /**
      * Command from main thread: the app's activity has been started.
      */
     APP_CMD_START,
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 2ff231d..41207f7 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -222,6 +222,10 @@
         // underlying surface is created and destroyed
         SurfaceHolder holder = getHolder();
         holder.addCallback(this);
+        // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment
+        // this statement if back-porting to 2.2 or older:
+        // holder.setFormat(PixelFormat.RGB_565);
+        //
         // setType is not needed for SDK 2.0 or newer. Uncomment this
         // statement if back-porting this code to older SDKs.
         // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
@@ -1103,7 +1107,6 @@
             mRenderer = renderer;
         }
 
-
         @Override
         public void run() {
             setName("GLThread " + getId());
@@ -1154,6 +1157,7 @@
                 boolean sizeChanged = false;
                 boolean wantRenderNotification = false;
                 boolean doRenderNotification = false;
+                boolean askedToReleaseEglContext = false;
                 int w = 0;
                 int h = 0;
                 Runnable event = null;
@@ -1179,6 +1183,17 @@
                                 }
                             }
 
+                            // Do we need to give up the EGL context?
+                            if (mShouldReleaseEglContext) {
+                                if (LOG_SURFACE) {
+                                    Log.i("GLThread", "releasing EGL context because asked to tid=" + getId());
+                                }
+                                stopEglSurfaceLocked();
+                                stopEglContextLocked();
+                                mShouldReleaseEglContext = false;
+                                askedToReleaseEglContext = true;
+                            }
+
                             // Have we lost the EGL context?
                             if (lostEglContext) {
                                 stopEglSurfaceLocked();
@@ -1228,6 +1243,9 @@
                             }
 
                             if (doRenderNotification) {
+                                if (LOG_SURFACE) {
+                                    Log.i("GLThread", "sending render notification tid=" + getId());
+                                }
                                 wantRenderNotification = false;
                                 doRenderNotification = false;
                                 mRenderComplete = true;
@@ -1235,22 +1253,24 @@
                             }
 
                             // Ready to draw?
-                            if ((!mPaused) && mHasSurface
-                                && (mWidth > 0) && (mHeight > 0)
-                                && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY))) {
+                            if (readyToDraw()) {
 
                                 // If we don't have an EGL context, try to acquire one.
-                                if ((! mHaveEglContext) && sGLThreadManager.tryAcquireEglContextLocked(this)) {
-                                    try {
-                                        mEglHelper.start();
-                                    } catch (RuntimeException t) {
-                                        sGLThreadManager.releaseEglContextLocked(this);
-                                        throw t;
-                                    }
-                                    mHaveEglContext = true;
-                                    createEglContext = true;
+                                if (! mHaveEglContext) {
+                                    if (askedToReleaseEglContext) {
+                                        askedToReleaseEglContext = false;
+                                    } else if (sGLThreadManager.tryAcquireEglContextLocked(this)) {
+                                        try {
+                                            mEglHelper.start();
+                                        } catch (RuntimeException t) {
+                                            sGLThreadManager.releaseEglContextLocked(this);
+                                            throw t;
+                                        }
+                                        mHaveEglContext = true;
+                                        createEglContext = true;
 
-                                    sGLThreadManager.notifyAll();
+                                        sGLThreadManager.notifyAll();
+                                    }
                                 }
 
                                 if (mHaveEglContext && !mHaveEglSurface) {
@@ -1265,6 +1285,9 @@
                                         w = mWidth;
                                         h = mHeight;
                                         wantRenderNotification = true;
+                                        if (LOG_SURFACE) {
+                                            Log.i("GLThread", "noticing that we want render notification tid=" + getId());
+                                        }
 
                                         if (DRAW_TWICE_AFTER_SIZE_CHANGED) {
                                             // We keep mRequestRender true so that we draw twice after the size changes.
@@ -1284,7 +1307,16 @@
 
                             // By design, this is the only place in a GLThread thread where we wait().
                             if (LOG_THREADS) {
-                                Log.i("GLThread", "waiting tid=" + getId());
+                                Log.i("GLThread", "waiting tid=" + getId()
+                                    + " mHaveEglContext: " + mHaveEglContext
+                                    + " mHaveEglSurface: " + mHaveEglSurface
+                                    + " mPaused: " + mPaused
+                                    + " mHasSurface: " + mHasSurface
+                                    + " mWaitingForSurface: " + mWaitingForSurface
+                                    + " mWidth: " + mWidth
+                                    + " mHeight: " + mHeight
+                                    + " mRequestRender: " + mRequestRender
+                                    + " mRenderMode: " + mRenderMode);
                             }
                             sGLThreadManager.wait();
                         }
@@ -1326,7 +1358,7 @@
                     }
 
                     if (LOG_RENDERER_DRAW_FRAME) {
-                        Log.w("GLThread", "onDrawFrame");
+                        Log.w("GLThread", "onDrawFrame tid=" + getId());
                     }
                     mRenderer.onDrawFrame(gl);
                     if (!mEglHelper.swap()) {
@@ -1352,6 +1384,16 @@
             }
         }
 
+        public boolean ableToDraw() {
+            return mHaveEglContext && mHaveEglSurface && readyToDraw();
+        }
+
+        private boolean readyToDraw() {
+            return (!mPaused) && mHasSurface
+                && (mWidth > 0) && (mHeight > 0)
+                && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
+        }
+
         public void setRenderMode(int renderMode) {
             if ( !((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY)) ) {
                 throw new IllegalArgumentException("renderMode");
@@ -1461,9 +1503,10 @@
                 sGLThreadManager.notifyAll();
 
                 // Wait for thread to react to resize and render a frame
-                while (! mExited && !mPaused && !mRenderComplete ) {
+                while (! mExited && !mPaused && !mRenderComplete
+                        && (mGLThread != null && mGLThread.ableToDraw())) {
                     if (LOG_SURFACE) {
-                        Log.i("Main thread", "onWindowResize waiting for render complete.");
+                        Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + mGLThread.getId());
                     }
                     try {
                         sGLThreadManager.wait();
@@ -1490,6 +1533,11 @@
             }
         }
 
+        public void requestReleaseEglContextLocked() {
+            mShouldReleaseEglContext = true;
+            sGLThreadManager.notifyAll();
+        }
+
         /**
          * Queue an "event" to be run on the GL rendering thread.
          * @param r the runnable to be run on the GL rendering thread.
@@ -1514,6 +1562,7 @@
         private boolean mWaitingForSurface;
         private boolean mHaveEglContext;
         private boolean mHaveEglSurface;
+        private boolean mShouldReleaseEglContext;
         private int mWidth;
         private int mHeight;
         private int mRenderMode;
@@ -1598,6 +1647,13 @@
             if (mMultipleGLESContextsAllowed) {
                 return true;
             }
+            // Notify the owning thread that it should release the context.
+            // TODO: implement a fairness policy. Currently
+            // if the owning thread is drawing continuously it will just
+            // reacquire the EGL context.
+            if (mEglOwner != null) {
+                mEglOwner.requestReleaseEglContextLocked();
+            }
             return false;
         }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cd4f96d..7395233 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -49,6 +49,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.HashSet;
 import java.util.List;
 
 /**
@@ -67,11 +68,29 @@
 
     private Context mContext;
 
+    private static final HashSet<String> mValidTables = new HashSet<String>();
+
+    static {
+        mValidTables.add("system");
+        mValidTables.add("secure");
+        mValidTables.add("bluetooth_devices");
+        mValidTables.add("bookmarks");
+
+        // These are old.
+        mValidTables.add("favorites");
+        mValidTables.add("gservices");
+        mValidTables.add("old_favorites");
+    }
+
     public DatabaseHelper(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
         mContext = context;
     }
 
+    public static boolean isValidTable(String name) {
+        return mValidTables.contains(name);
+    }
+
     private void createSecureTable(SQLiteDatabase db) {
         db.execSQL("CREATE TABLE secure (" +
                 "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1019fa8..6a5290e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -83,6 +83,9 @@
         SqlArguments(Uri url, String where, String[] args) {
             if (url.getPathSegments().size() == 1) {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 this.where = where;
                 this.args = args;
             } else if (url.getPathSegments().size() != 2) {
@@ -91,6 +94,9 @@
                 throw new UnsupportedOperationException("WHERE clause not supported: " + url);
             } else {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 if ("system".equals(this.table) || "secure".equals(this.table)) {
                     this.where = Settings.NameValueTable.NAME + "=?";
                     this.args = new String[] { url.getPathSegments().get(1) };
@@ -105,6 +111,9 @@
         SqlArguments(Uri url) {
             if (url.getPathSegments().size() == 1) {
                 this.table = url.getPathSegments().get(0);
+                if (!DatabaseHelper.isValidTable(this.table)) {
+                    throw new IllegalArgumentException("Bad root path: " + this.table);
+                }
                 this.where = null;
                 this.args = null;
             } else {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 5642588..b9232c8 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -104,7 +104,7 @@
     // mDecor itself, or a child of mDecor where the contents go.
     private ViewGroup mContentParent;
 
-    SurfaceHolder.Callback mTakeSurfaceCallback;
+    SurfaceHolder.Callback2 mTakeSurfaceCallback;
     BaseSurfaceHolder mSurfaceHolder;
     
     InputQueue.Callback mTakeInputQueueCallback;
@@ -248,7 +248,7 @@
     }
 
     @Override
-    public void takeSurface(SurfaceHolder.Callback callback) {
+    public void takeSurface(SurfaceHolder.Callback2 callback) {
         mTakeSurfaceCallback = callback;
     }
     
@@ -2038,7 +2038,7 @@
             }
         }
 
-        public android.view.SurfaceHolder.Callback willYouTakeTheSurface() {
+        public android.view.SurfaceHolder.Callback2 willYouTakeTheSurface() {
             return mFeatureId < 0 ? mTakeSurfaceCallback : null;
         }
         
diff --git a/services/java/com/android/server/ViewServer.java b/services/java/com/android/server/ViewServer.java
index ae00438..9c7db9b 100644
--- a/services/java/com/android/server/ViewServer.java
+++ b/services/java/com/android/server/ViewServer.java
@@ -21,6 +21,8 @@
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.InetAddress;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.io.IOException;
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
@@ -41,11 +43,13 @@
      */
     public static final int VIEW_SERVER_DEFAULT_PORT = 4939;
 
+    private static final int VIEW_SERVER_MAX_CONNECTIONS = 10;
+
     // Debug facility
     private static final String LOG_TAG = "ViewServer";
 
-    private static final String VALUE_PROTOCOL_VERSION = "2";
-    private static final String VALUE_SERVER_VERSION = "3";
+    private static final String VALUE_PROTOCOL_VERSION = "3";
+    private static final String VALUE_SERVER_VERSION = "4";
 
     // Protocol commands
     // Returns the protocol version
@@ -54,6 +58,8 @@
     private static final String COMMAND_SERVER_VERSION = "SERVER";
     // Lists all of the available windows in the system
     private static final String COMMAND_WINDOW_MANAGER_LIST = "LIST";
+    // Keeps a connection open and notifies when the list of windows changes
+    private static final String COMMAND_WINDOW_MANAGER_AUTOLIST = "AUTOLIST";
 
     private ServerSocket mServer;
     private Thread mThread;
@@ -61,6 +67,8 @@
     private final WindowManagerService mWindowManager;
     private final int mPort;
 
+    private ExecutorService mThreadPool;
+
     /**
      * Creates a new ViewServer associated with the specified window manager.
      * The server uses the default port {@link #VIEW_SERVER_DEFAULT_PORT}. The server
@@ -103,8 +111,9 @@
             return false;
         }
 
-        mServer = new ServerSocket(mPort, 1, InetAddress.getLocalHost());
+        mServer = new ServerSocket(mPort, VIEW_SERVER_MAX_CONNECTIONS, InetAddress.getLocalHost());
         mThread = new Thread(this, "Remote View Server [port=" + mPort + "]");
+        mThreadPool = Executors.newFixedThreadPool(VIEW_SERVER_MAX_CONNECTIONS);
         mThread.start();
 
         return true;
@@ -122,7 +131,16 @@
      */
     boolean stop() {
         if (mThread != null) {
+
             mThread.interrupt();
+            if (mThreadPool != null) {
+                try {
+                    mThreadPool.shutdownNow();
+                } catch (SecurityException e) {
+                    Slog.w(LOG_TAG, "Could not stop all view server threads");
+                }
+            }
+            mThreadPool = null;
             mThread = null;
             try {
                 mServer.close();
@@ -152,62 +170,21 @@
      * Main server loop.
      */
     public void run() {
-        final ServerSocket server = mServer;
-
         while (Thread.currentThread() == mThread) {
-            Socket client = null;
             // Any uncaught exception will crash the system process
             try {
-                client = server.accept();
-
-                BufferedReader in = null;
-                try {
-                    in = new BufferedReader(new InputStreamReader(client.getInputStream()), 1024);
-
-                    final String request = in.readLine();
-
-                    String command;
-                    String parameters;
-
-                    int index = request.indexOf(' ');
-                    if (index == -1) {
-                        command = request;
-                        parameters = "";
-                    } else {
-                        command = request.substring(0, index);
-                        parameters = request.substring(index + 1);
-                    }
-
-                    boolean result;
-                    if (COMMAND_PROTOCOL_VERSION.equalsIgnoreCase(command)) {
-                        result = writeValue(client, VALUE_PROTOCOL_VERSION);
-                    } else if (COMMAND_SERVER_VERSION.equalsIgnoreCase(command)) {
-                        result = writeValue(client, VALUE_SERVER_VERSION);
-                    } else if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) {
-                        result = mWindowManager.viewServerListWindows(client);
-                    } else {
-                        result = mWindowManager.viewServerWindowCommand(client,
-                                command, parameters);
-                    }
-
-                    if (!result) {
-                        Slog.w(LOG_TAG, "An error occured with the command: " + command);
-                    }
-                } finally {
-                    if (in != null) {
-                        in.close();
-                    }
-                }
-            } catch (Exception e) {
-                Slog.w(LOG_TAG, "Connection error: ", e);
-            } finally {
-                if (client != null) {
+                Socket client = mServer.accept();
+                if(mThreadPool != null) {
+                    mThreadPool.submit(new ViewServerWorker(client));
+                } else {
                     try {
                         client.close();
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
                 }
+            } catch (Exception e) {
+                Slog.w(LOG_TAG, "Connection error: ", e);
             }
         }
     }
@@ -235,4 +212,106 @@
         }
         return result;
     }
+
+    class ViewServerWorker implements Runnable, WindowManagerService.WindowChangeListener {
+        private Socket mClient;
+        private boolean mNeedWindowListUpdate;
+        public ViewServerWorker(Socket client) {
+            mClient = client;
+        }
+
+        public void run() {
+
+            BufferedReader in = null;
+            try {
+                in = new BufferedReader(new InputStreamReader(mClient.getInputStream()), 1024);
+
+                final String request = in.readLine();
+
+                String command;
+                String parameters;
+
+                int index = request.indexOf(' ');
+                if (index == -1) {
+                    command = request;
+                    parameters = "";
+                } else {
+                    command = request.substring(0, index);
+                    parameters = request.substring(index + 1);
+                }
+
+                boolean result;
+                if (COMMAND_PROTOCOL_VERSION.equalsIgnoreCase(command)) {
+                    result = writeValue(mClient, VALUE_PROTOCOL_VERSION);
+                } else if (COMMAND_SERVER_VERSION.equalsIgnoreCase(command)) {
+                    result = writeValue(mClient, VALUE_SERVER_VERSION);
+                } else if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) {
+                    result = mWindowManager.viewServerListWindows(mClient);
+                } else if(COMMAND_WINDOW_MANAGER_AUTOLIST.equalsIgnoreCase(command)) {
+                    result = windowManagerAutolistLoop();
+                } else {
+                    result = mWindowManager.viewServerWindowCommand(mClient,
+                            command, parameters);
+                }
+
+                if (!result) {
+                    Slog.w(LOG_TAG, "An error occured with the command: " + command);
+                }
+            } catch(IOException e) {
+                Slog.w(LOG_TAG, "Connection error: ", e);
+            } finally {
+                if (in != null) {
+                    try {
+                        in.close();
+
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+                if (mClient != null) {
+                    try {
+                        mClient.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+
+        public void windowsChanged() {
+            synchronized(this) {
+                mNeedWindowListUpdate = true;
+                notifyAll();
+            }
+        }
+
+        private boolean windowManagerAutolistLoop() {
+            mWindowManager.addWindowChangeListener(this);
+            BufferedWriter out = null;
+            try {
+                out = new BufferedWriter(new OutputStreamWriter(mClient.getOutputStream()));
+                while (!Thread.interrupted()) {
+                    synchronized (this) {
+                        while (!mNeedWindowListUpdate) {
+                            wait();
+                        }
+                        mNeedWindowListUpdate = false;
+                    }
+                    out.write("UPDATE\n");
+                    out.flush();
+                }
+            } catch (Exception e) {
+                Slog.w(LOG_TAG, "Connection error: ", e);
+            } finally {
+                if (out != null) {
+                    try {
+                        out.close();
+                    } catch (IOException e) {
+                    }
+                }
+                mWindowManager.removeWindowChangeListener(this);
+            }
+            return true;
+        }
+    }
 }
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 38f1e1f..833d08e 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -489,6 +489,13 @@
     boolean mInTouchMode = false;
 
     private ViewServer mViewServer;
+    private ArrayList<WindowChangeListener> mWindowChangeListeners =
+        new ArrayList<WindowChangeListener>();
+    private boolean mWindowsChanged = false;
+
+    public interface WindowChangeListener {
+        public void windowsChanged();
+    }
 
     final Configuration mTempConfiguration = new Configuration();
     int mScreenLayout = Configuration.SCREENLAYOUT_SIZE_UNDEFINED;
@@ -662,6 +669,7 @@
             TAG, "Adding window " + window + " at "
             + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
         mWindows.add(i+1, window);
+        mWindowsChanged = true;
     }
 
     private void placeWindowBefore(Object pos, WindowState window) {
@@ -670,6 +678,7 @@
             TAG, "Adding window " + window + " at "
             + i + " of " + mWindows.size() + " (before " + pos + ")");
         mWindows.add(i, window);
+        mWindowsChanged = true;
     }
 
     //This method finds out the index of a window that has the same app token as
@@ -727,6 +736,7 @@
                                         TAG, "Adding window " + win + " at "
                                         + (newIdx+1) + " of " + N);
                                 localmWindows.add(newIdx+1, win);
+                                mWindowsChanged = true;
                             }
                         }
                     }
@@ -809,6 +819,7 @@
                                     TAG, "Adding window " + win + " at "
                                     + i + " of " + N);
                             localmWindows.add(i, win);
+                            mWindowsChanged = true;
                         }
                     }
                 }
@@ -826,6 +837,7 @@
                         TAG, "Adding window " + win + " at "
                         + i + " of " + N);
                 localmWindows.add(i, win);
+                mWindowsChanged = true;
             }
             if (addToToken) {
                 token.windows.add(tokenWindowsPos, win);
@@ -1034,6 +1046,7 @@
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(
                     TAG, "Adding input method window " + win + " at " + pos);
             mWindows.add(pos, win);
+            mWindowsChanged = true;
             moveInputMethodDialogsLocked(pos+1);
             return;
         }
@@ -1075,6 +1088,7 @@
             if (wpos < interestingPos) interestingPos--;
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Temp removing at " + wpos + ": " + win);
             mWindows.remove(wpos);
+            mWindowsChanged = true;
             int NC = win.mChildWindows.size();
             while (NC > 0) {
                 NC--;
@@ -1101,6 +1115,7 @@
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "ReAdd removing from " + wpos
                     + ": " + win);
             mWindows.remove(wpos);
+            mWindowsChanged = true;
             reAddWindowLocked(wpos, win);
         }
     }
@@ -1561,6 +1576,7 @@
                     if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at "
                             + oldIndex + ": " + wallpaper);
                     localmWindows.remove(oldIndex);
+                    mWindowsChanged = true;
                     if (oldIndex < foundI) {
                         foundI--;
                     }
@@ -1572,6 +1588,7 @@
                         + " from " + oldIndex + " to " + foundI);
 
                 localmWindows.add(foundI, wallpaper);
+                mWindowsChanged = true;
                 changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
             }
         }
@@ -2078,6 +2095,7 @@
 
         mWindowMap.remove(win.mClient.asBinder());
         mWindows.remove(win);
+        mWindowsChanged = true;
         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
 
         if (mInputMethodWindow == win) {
@@ -3360,6 +3378,7 @@
                         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
                                 "Removing starting window: " + startingWindow);
                         mWindows.remove(startingWindow);
+                        mWindowsChanged = true;
                         ttoken.windows.remove(startingWindow);
                         ttoken.allAppWindows.remove(startingWindow);
                         addWindowToListInOrderLocked(startingWindow, true);
@@ -3841,6 +3860,7 @@
             WindowState win = token.windows.get(i);
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
             mWindows.remove(win);
+            mWindowsChanged = true;
             int j = win.mChildWindows.size();
             while (j > 0) {
                 j--;
@@ -3945,6 +3965,7 @@
             mWindows.add(index, win);
             index++;
         }
+        mWindowsChanged = true;
         return index;
     }
 
@@ -4783,6 +4804,33 @@
         return success;
     }
 
+    public void addWindowChangeListener(WindowChangeListener listener) {
+        synchronized(mWindowMap) {
+            mWindowChangeListeners.add(listener);
+        }
+    }
+
+    public void removeWindowChangeListener(WindowChangeListener listener) {
+        synchronized(mWindowMap) {
+            mWindowChangeListeners.remove(listener);
+        }
+    }
+
+    private void notifyWindowsChanged() {
+        WindowChangeListener[] windowChangeListeners;
+        synchronized(mWindowMap) {
+            if(mWindowChangeListeners.isEmpty()) {
+                return;
+            }
+            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
+            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
+        }
+        int N = windowChangeListeners.length;
+        for(int i = 0; i < N; i++) {
+            windowChangeListeners[i].windowsChanged();
+        }
+    }
+
     private WindowState findWindow(int hashCode) {
         if (hashCode == -1) {
             return getFocusedWindow();
@@ -7672,6 +7720,7 @@
         public static final int ENABLE_SCREEN = 16;
         public static final int APP_FREEZE_TIMEOUT = 17;
         public static final int SEND_NEW_CONFIGURATION = 18;
+        public static final int WINDOWS_CHANGED = 19;
 
         private Session mLastReportedHold;
 
@@ -8003,6 +8052,16 @@
                     break;
                 }
 
+                case WINDOWS_CHANGED: {
+                    if (mWindowsChanged) {
+                        synchronized (mWindowMap) {
+                            mWindowsChanged = false;
+                        }
+                        notifyWindowsChanged();
+                    }
+                    break;
+                }
+
             }
         }
     }
@@ -8087,6 +8146,7 @@
             WindowState w = (WindowState)mWindows.get(i);
             if (w.mAppToken != null) {
                 WindowState win = (WindowState)mWindows.remove(i);
+                mWindowsChanged = true;
                 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
                         "Rebuild removing window: " + win);
                 NW--;
@@ -8222,6 +8282,10 @@
                     requestAnimationLocked(0);
                 }
             }
+            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
+                mH.removeMessages(H.WINDOWS_CHANGED);
+                mH.sendMessage(mH.obtainMessage(H.WINDOWS_CHANGED));
+            }
         } catch (RuntimeException e) {
             mInLayout = false;
             Slog.e(TAG, "Unhandled exception while layout out windows", e);
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index fc901f4..26e105a 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -405,28 +405,28 @@
 }
 
 bool NativeInputManager::isAppSwitchKey(int32_t keyCode) {
-    return keyCode == KEYCODE_HOME || keyCode == KEYCODE_ENDCALL;
+    return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL;
 }
 
 bool NativeInputManager::isPolicyKey(int32_t keyCode, bool isScreenOn) {
     // Special keys that the WindowManagerPolicy might care about.
     switch (keyCode) {
-    case KEYCODE_VOLUME_UP:
-    case KEYCODE_VOLUME_DOWN:
-    case KEYCODE_ENDCALL:
-    case KEYCODE_POWER:
-    case KEYCODE_CALL:
-    case KEYCODE_HOME:
-    case KEYCODE_MENU:
-    case KEYCODE_SEARCH:
+    case AKEYCODE_VOLUME_UP:
+    case AKEYCODE_VOLUME_DOWN:
+    case AKEYCODE_ENDCALL:
+    case AKEYCODE_POWER:
+    case AKEYCODE_CALL:
+    case AKEYCODE_HOME:
+    case AKEYCODE_MENU:
+    case AKEYCODE_SEARCH:
         // media keys
-    case KEYCODE_HEADSETHOOK:
-    case KEYCODE_MEDIA_PLAY_PAUSE:
-    case KEYCODE_MEDIA_STOP:
-    case KEYCODE_MEDIA_NEXT:
-    case KEYCODE_MEDIA_PREVIOUS:
-    case KEYCODE_MEDIA_REWIND:
-    case KEYCODE_MEDIA_FAST_FORWARD:
+    case AKEYCODE_HEADSETHOOK:
+    case AKEYCODE_MEDIA_PLAY_PAUSE:
+    case AKEYCODE_MEDIA_STOP:
+    case AKEYCODE_MEDIA_NEXT:
+    case AKEYCODE_MEDIA_PREVIOUS:
+    case AKEYCODE_MEDIA_REWIND:
+    case AKEYCODE_MEDIA_FAST_FORWARD:
         return true;
     default:
         // We need to pass all keys to the policy in the following cases:
diff --git a/test-runner/src/android/test/ProviderTestCase2.java b/test-runner/src/android/test/ProviderTestCase2.java
index 28ecee5..1fb5538 100644
--- a/test-runner/src/android/test/ProviderTestCase2.java
+++ b/test-runner/src/android/test/ProviderTestCase2.java
@@ -27,15 +27,44 @@
 import java.io.File;
 
 /**
- * This TestCase class provides a framework for isolated testing of a single
- * ContentProvider.  It uses a {@link android.test.mock.MockContentResolver} to
- * access the provider, restricts the provider to an isolated area of the
- * filesystem (for safely creating & modifying databases & files), and injects
- * {@link android.test.IsolatedContext} to isolate the ContentProvider from the
- * rest of the running system.
- *
- * <p>This environment is created automatically by {@link #setUp} and {@link
- * #tearDown}.
+ * This test case class provides a framework for testing a single
+ * {@link ContentProvider} and for testing your app code with an
+ * isolated content provider. Instead of using the system map of
+ * providers that is based on the manifests of other applications, the test
+ * case creates its own internal map. It then uses this map to resolve providers
+ * given an authority. This allows you to inject test providers and to null out
+ * providers that you do not want to use.
+ * <p>
+ *      This test case also sets up the following mock objects:
+ * </p>
+ * <ul>
+ *      <li>
+ *          An {@link android.test.IsolatedContext} that stubs out Context methods that might
+ *          affect the rest of the running system, while allowing tests to do real file and
+ *          database work.
+ *      </li>
+ *      <li>
+ *          A {@link android.test.mock.MockContentResolver} that provides the functionality of a
+ *          regular content resolver, but uses {@link IsolatedContext}. It stubs out
+ *          {@link ContentResolver#notifyChange(Uri, ContentObserver, boolean)} to
+ *          prevent the test from affecting the running system.
+ *      </li>
+ *      <li>
+ *          An instance of the provider under test, running in an {@link IsolatedContext}.
+ *      </li>
+ * </ul>
+ * <p>
+ *      This framework is set up automatically by the base class' {@link #setUp()} method. If you
+ *      override this method, you must call the super method as the first statement in
+ *      your override.
+ * </p>
+ * <p>
+ *     In order for their tests to be run, concrete subclasses must provide their own
+ *     constructor with no arguments. This constructor must call
+ *     {@link #ProviderTestCase2(Class, String)} as  its first operation.
+ * </p>
+ * For more information on content provider testing, please see
+ * <a href="{@docRoot}guide/topics/testing/provider_testing.html">Content Provider Testing</a>.
  */
 public abstract class ProviderTestCase2<T extends ContentProvider> extends AndroidTestCase {
 
@@ -54,34 +83,53 @@
 
         @Override
         public File getDir(String name, int mode) {
-            // name the directory so the directory will be seperated from
+            // name the directory so the directory will be separated from
             // one created through the regular Context
             return getContext().getDir("mockcontext2_" + name, mode);
         }
     }
-
+    /**
+     * Constructor.
+     *
+     * @param providerClass The class name of the provider under test
+     * @param providerAuthority The provider's authority string
+     */
     public ProviderTestCase2(Class<T> providerClass, String providerAuthority) {
         mProviderClass = providerClass;
         mProviderAuthority = providerAuthority;
     }
 
-    /**
-     * The content provider that will be set up for use in each test method.
-     */
     private T mProvider;
 
+    /**
+     * Returns the content provider created by this class in the {@link #setUp()} method.
+     * @return T An instance of the provider class given as a parameter to the test case class.
+     */
     public T getProvider() {
         return mProvider;
     }
 
+    /**
+     * Sets up the environment for the test fixture.
+     * <p>
+     * Creates a new
+     * {@link android.test.mock.MockContentResolver}, a new IsolatedContext
+     * that isolates the provider's file operations, and a new instance of
+     * the provider under test within the isolated environment.
+     * </p>
+     *
+     * @throws Exception
+     */
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
         mResolver = new MockContentResolver();
         final String filenamePrefix = "test.";
-        RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
-                new MockContext2(), // The context that most methods are delegated to
+        RenamingDelegatingContext targetContextWrapper = new
+                RenamingDelegatingContext(
+                new MockContext2(), // The context that most methods are
+                                    //delegated to
                 getContext(), // The context that file methods are delegated to
                 filenamePrefix);
         mProviderContext = new IsolatedContext(mResolver, targetContextWrapper);
@@ -92,14 +140,55 @@
         mResolver.addProvider(mProviderAuthority, getProvider());
     }
 
+    /**
+     * Gets the {@link MockContentResolver} created by this class during initialization. You
+     * must use the methods of this resolver to access the provider under test.
+     *
+     * @return A {@link MockContentResolver} instance.
+     */
     public MockContentResolver getMockContentResolver() {
         return mResolver;
     }
 
+    /**
+     * Gets the {@link IsolatedContext} created by this class during initialization.
+     * @return The {@link IsolatedContext} instance
+     */
     public IsolatedContext getMockContext() {
         return mProviderContext;
     }
 
+    /**
+     * <p>
+     *      Creates a new content provider of the same type as that passed to the test case class,
+     *      with an authority name set to the authority parameter, and using an SQLite database as
+     *      the underlying data source. The SQL statement parameter is used to create the database.
+     *      This method also creates a new {@link MockContentResolver} and adds the provider to it.
+     * </p>
+     * <p>
+     *      Both the new provider and the new resolver are put into an {@link IsolatedContext}
+     *      that uses the targetContext parameter for file operations and a {@link MockContext}
+     *      for everything else. The IsolatedContext prepends the filenamePrefix parameter to
+     *      file, database, and directory names.
+     * </p>
+     * <p>
+     *      This is a convenience method for creating a "mock" provider that can contain test data.
+     * </p>
+     *
+     * @param targetContext The context to use as the basis of the IsolatedContext
+     * @param filenamePrefix A string that is prepended to file, database, and directory names
+     * @param providerClass The type of the provider being tested
+     * @param authority The authority string to associated with the test provider
+     * @param databaseName The name assigned to the database
+     * @param databaseVersion The version assigned to the database
+     * @param sql A string containing the SQL statements that are needed to create the desired
+     * database and its tables. The format is the same as that generated by the
+     * <a href="http://www.sqlite.org/sqlite.html">sqlite3</a> tool's <code>.dump</code> command.
+     * @return ContentResolver A new {@link MockContentResolver} linked to the provider
+     *
+     * @throws IllegalAccessException
+     * @throws InstantiationException
+     */
     public static <T extends ContentProvider> ContentResolver newResolverWithContentProviderFromSql(
             Context targetContext, String filenamePrefix, Class<T> providerClass, String authority,
             String databaseName, int databaseVersion, String sql)
diff --git a/test-runner/src/android/test/ServiceTestCase.java b/test-runner/src/android/test/ServiceTestCase.java
index d9262f6..f9e8adb 100644
--- a/test-runner/src/android/test/ServiceTestCase.java
+++ b/test-runner/src/android/test/ServiceTestCase.java
@@ -31,42 +31,64 @@
 /**
  * This test case provides a framework in which you can test Service classes in
  * a controlled environment.  It provides basic support for the lifecycle of a
- * Service, and hooks by which you can inject various dependencies and control
+ * Service, and hooks with which you can inject various dependencies and control
  * the environment in which your Service is tested.
  *
  * <p><b>Lifecycle Support.</b>
- * Every Service is designed to be accessed within a specific sequence of
- * calls.  <insert link to Service lifecycle doc here>. 
- * In order to support the lifecycle of a Service, this test case will make the
- * following calls at the following times.
+ * A Service is accessed with a specific sequence of
+ * calls, as documented in the section
+ * <a href="http://developer.android.com/guide/topics/fundamentals.html#servlife">
+ * Service lifecycle</a> in the Developer Guide. In order to support the lifecycle of a Service,
+ * <code>ServiceTestCase</code> enforces this protocol:
  *
- * <ul><li>The test case will not call onCreate() until your test calls 
- * {@link #startService} or {@link #bindService}.  This gives you a chance
- * to set up or adjust any additional framework or test logic before
- * onCreate().</li>
- * <li>When your test calls {@link #startService} or {@link #bindService}
- * the test case will call onCreate(), and then call the corresponding entry point in your service.
- * It will record any parameters or other support values necessary to support the lifecycle.</li>
- * <li>After your test completes, the test case {@link #tearDown} function is
- * automatically called, and it will stop and destroy your service with the appropriate
- * calls (depending on how your test invoked the service.)</li>
+ * <ul>
+ *      <li>
+ *          The {@link #setUp()} method is called before each test method. The base implementation
+ *          gets the system context. If you override <code>setUp()</code>, you must call
+ *          <code>super.setUp()</code> as the first statement in your override.
+ *      </li>
+ *      <li>
+ *          The test case waits to call {@link android.app.Service#onCreate()} until one of your
+ *          test methods calls {@link #startService} or {@link #bindService}.  This gives you an
+ *          opportunity to set up or adjust any additional framework or test logic before you test
+ *          the running service.
+ *      </li>
+ *      <li>
+ *          When one of your test methods calls {@link #startService ServiceTestCase.startService()}
+ *          or {@link #bindService  ServiceTestCase.bindService()}, the test case calls
+ *          {@link android.app.Service#onCreate() Service.onCreate()} and then calls either
+ *          {@link android.app.Service#startService(Intent) Service.startService(Intent)} or
+ *          {@link android.app.Service#bindService(Intent, ServiceConnection, int)
+ *          Service.bindService(Intent, ServiceConnection, int)}, as appropriate. It also stores
+ *          values needed to track and support the lifecycle.
+ *      </li>
+ *      <li>
+ *          After each test method finishes, the test case calls the {@link #tearDown} method. This
+ *          method stops and destroys the service with the appropriate calls, depending on how the
+ *          service was started. If you override <code>tearDown()</code>, your must call the
+ *          <code>super.tearDown()</code> as the last statement in your override.
+ *      </li>
  * </ul>
- * 
- * <p><b>Dependency Injection.</b>
- * Every service has two inherent dependencies, the {@link android.content.Context Context} in
- * which it runs, and the {@link android.app.Application Application} with which it is associated.
- * This framework allows you to inject modified, mock, or isolated replacements for these 
- * dependencies, and thus perform a true unit test.
- * 
- * <p>If simply run your tests as-is, your Service will be injected with a fully-functional
- * Context, and a generic {@link android.test.mock.MockApplication MockApplication} object.
- * You can create and inject alternatives to either of these by calling 
- * {@link AndroidTestCase#setContext(Context) setContext()} or 
- * {@link #setApplication setApplication()}.  You must do this <i>before</i> calling
- * startService() or bindService().  The test framework provides a
- * number of alternatives for Context, including {link android.test.mock.MockContext MockContext}, 
- * {@link android.test.RenamingDelegatingContext RenamingDelegatingContext}, and 
- * {@link android.content.ContextWrapper ContextWrapper}.
+ *
+ * <p>
+ *      <strong>Dependency Injection.</strong>
+ *      A service has two inherent dependencies, its {@link android.content.Context Context} and its
+ *      associated {@link android.app.Application Application}. The ServiceTestCase framework
+ *      allows you to inject modified, mock, or isolated replacements for these dependencies, and
+ *      thus perform unit tests with controlled dependencies in an isolated environment.
+ * </p>
+ * <p>
+ *      By default, the test case is injected with a full system context and a generic
+ *      {@link android.test.mock.MockApplication MockApplication} object. You can inject
+ *      alternatives to either of these by invoking
+ *      {@link AndroidTestCase#setContext(Context) setContext()} or
+ *      {@link #setApplication setApplication()}.  You must do this <em>before</em> calling
+ *      startService() or bindService().  The test framework provides a
+ *      number of alternatives for Context, including
+ *      {link android.test.mock.MockContext MockContext},
+ *      {@link android.test.RenamingDelegatingContext RenamingDelegatingContext},
+ *      {@link android.content.ContextWrapper ContextWrapper}, and
+ *      {@link android.test.IsolatedContext}.
  */
 public abstract class ServiceTestCase<T extends Service> extends AndroidTestCase {
 
@@ -75,6 +97,10 @@
     private Context mSystemContext;
     private Application mApplication;
 
+    /**
+     * Constructor
+     * @param serviceClass The type of the service under test.
+     */
     public ServiceTestCase(Class<T> serviceClass) {
         mServiceClass = serviceClass;
     }
@@ -88,30 +114,35 @@
     private int mServiceId;
 
     /**
-     * @return Returns the actual service under test.
+     * @return An instance of the service under test. This instance is created automatically when
+     * a test calls {@link #startService} or {@link #bindService}.
      */
     public T getService() {
         return mService;
     }
 
     /**
-     * This will do the work to instantiate the Service under test.  After this, your test 
-     * code must also start and stop the service.
+     * Gets the current system context and stores it.
+     *
+     * Extend this method to do your own test initialization. If you do so, you
+     * must call <code>super.setUp()</code> as the first statement in your override. The method is
+     * called before each test method is executed.
      */
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        
+
         // get the real context, before the individual tests have a chance to muck with it
         mSystemContext = getContext();
 
     }
-    
+
     /**
-     * Create the service under test and attach all injected dependencies (Context, Application) to
-     * it.  This will be called automatically by {@link #startService} or by {@link #bindService}.
-     * If you wish to call {@link AndroidTestCase#setContext(Context) setContext()} or 
-     * {@link #setApplication setApplication()}, you must do so  before calling this function.
+     * Creates the service under test and attaches all injected dependencies
+     * (Context, Application) to it.  This is called automatically by {@link #startService} or
+     * by {@link #bindService}.
+     * If you need to call {@link AndroidTestCase#setContext(Context) setContext()} or
+     * {@link #setApplication setApplication()}, do so before calling this method.
      */
     protected void setupService() {
         mService = null;
@@ -131,60 +162,74 @@
                 getApplication(),
                 null                // mocked services don't talk with the activity manager
                 );
-        
+
         assertNotNull(mService);
-        
+
         mServiceId = new Random().nextInt();
         mServiceAttached = true;
     }
-    
+
     /**
-     * Start the service under test, in the same way as if it was started by
-     * {@link android.content.Context#startService Context.startService()}, providing the 
-     * arguments it supplied.  If you use this method to start the service, it will automatically
-     * be stopped by {@link #tearDown}.
-     *  
-     * @param intent The Intent as if supplied to {@link android.content.Context#startService}.
+     * Starts the service under test, in the same way as if it were started by
+     * {@link android.content.Context#startService(Intent) Context.startService(Intent)} with
+     * an {@link android.content.Intent} that identifies a service.
+     * If you use this method to start the service, it is automatically stopped by
+     * {@link #tearDown}.
+     *
+     * @param intent An Intent that identifies a service, of the same form as the Intent passed to
+     * {@link android.content.Context#startService(Intent) Context.startService(Intent)}.
      */
     protected void startService(Intent intent) {
         if (!mServiceAttached) {
             setupService();
         }
         assertNotNull(mService);
-        
+
         if (!mServiceCreated) {
             mService.onCreate();
             mServiceCreated = true;
         }
         mService.onStartCommand(intent, 0, mServiceId);
-        
+
         mServiceStarted = true;
     }
-    
-    /**
-     * Start the service under test, in the same way as if it was started by
-     * {@link android.content.Context#bindService Context.bindService()}, providing the 
-     * arguments it supplied.
-     *  
-     * Return the communication channel to the service.  May return null if 
-     * clients can not bind to the service.  The returned
-     * {@link android.os.IBinder} is usually for a complex interface
-     * that has been <a href="{@docRoot}guide/developing/tools/aidl.html">described using
-     * aidl</a>. 
-     * 
-     * Note:  In order to test with this interface, your service must implement a getService()
-     * method, as shown in samples.ApiDemos.app.LocalService.
 
-     * @param intent The Intent as if supplied to {@link android.content.Context#bindService}.
-     * 
-     * @return Return an IBinder for making further calls into the Service.
+    /**
+     * <p>
+     *      Starts the service under test, in the same way as if it were started by
+     *      {@link android.content.Context#bindService(Intent, ServiceConnection, int)
+     *      Context.bindService(Intent, ServiceConnection, flags)} with an
+     *      {@link android.content.Intent} that identifies a service.
+     * </p>
+     * <p>
+     *      Notice that the parameters are different. You do not provide a
+     *      {@link android.content.ServiceConnection} object or the flags parameter. Instead,
+     *      you only provide the Intent. The method returns an object whose type is a
+     *      subclass of {@link android.os.IBinder}, or null if the method fails. An IBinder
+     *      object refers to a communication channel between the application and
+     *      the service. The flag is assumed to be {@link android.content.Context#BIND_AUTO_CREATE}.
+     * </p>
+     * <p>
+     *      See <a href="{@docRoot}guide/developing/tools/aidl.html">Designing a Remote Interface
+     *      Using AIDL</a> for more information about the communication channel object returned
+     *      by this method.
+     * </p>
+     * Note:  To be able to use bindService in a test, the service must implement getService()
+     * method. An example of this is in the ApiDemos sample application, in the
+     * LocalService demo.
+     *
+     * @param intent An Intent object of the form expected by
+     * {@link android.content.Context#bindService}.
+     *
+     * @return An object whose type is a subclass of IBinder, for making further calls into
+     * the service.
      */
     protected IBinder bindService(Intent intent) {
         if (!mServiceAttached) {
             setupService();
         }
         assertNotNull(mService);
-        
+
         if (!mServiceCreated) {
             mService.onCreate();
             mServiceCreated = true;
@@ -192,15 +237,15 @@
         // no extras are expected by unbind
         mServiceIntent = intent.cloneFilter();
         IBinder result = mService.onBind(intent);
-        
+
         mServiceBound = true;
         return result;
     }
-    
+
     /**
-     * This will make the necessary calls to stop (or unbind) the Service under test, and
-     * call onDestroy().  Ordinarily this will be called automatically (by {@link #tearDown}, but
-     * you can call it directly from your test in order to check for proper shutdown behaviors.
+     * Makes the necessary calls to stop (or unbind) the service under test, and
+     * calls onDestroy().  Ordinarily this is called automatically (by {@link #tearDown}, but
+     * you can call it directly from your test in order to check for proper shutdown behavior.
      */
     protected void shutdownService() {
         if (mServiceStarted) {
@@ -214,13 +259,18 @@
             mService.onDestroy();
         }
     }
-    
+
     /**
-     * Shuts down the Service under test.  Also makes sure all resources are cleaned up and 
-     * garbage collected before moving on to the next
-     * test.  Subclasses that override this method should make sure they call super.tearDown()
-     * at the end of the overriding method.
-     * 
+     * <p>
+     *      Shuts down the service under test.  Ensures all resources are cleaned up and
+     *      garbage collected before moving on to the next test. This method is called after each
+     *      test method.
+     * </p>
+     * <p>
+     *      Subclasses that override this method must call <code>super.tearDown()</code> as their
+     *      last statement.
+     * </p>
+     *
      * @throws Exception
      */
     @Override
@@ -228,45 +278,54 @@
         shutdownService();
         mService = null;
 
-        // Scrub out members - protects against memory leaks in the case where someone 
+        // Scrub out members - protects against memory leaks in the case where someone
         // creates a non-static inner class (thus referencing the test case) and gives it to
         // someone else to hold onto
         scrubClass(ServiceTestCase.class);
 
         super.tearDown();
     }
-    
+
     /**
-     * Set the application for use during the test.  If your test does not call this function,
-     * a new {@link android.test.mock.MockApplication MockApplication} object will be generated.
-     * 
-     * @param application The Application object that will be injected into the Service under test.
+     * Sets the application that is used during the test.  If you do not call this method,
+     * a new {@link android.test.mock.MockApplication MockApplication} object is used.
+     *
+     * @param application The Application object that is used by the service under test.
+     *
+     * @see #getApplication()
      */
     public void setApplication(Application application) {
         mApplication = application;
     }
 
     /**
-     * Return the Application object being used by the Service under test.
-     * 
-     * @return Returns the application object.
-     * 
+     * Returns the Application object in use by the service under test.
+     *
+     * @return The application object.
+     *
      * @see #setApplication
      */
     public Application getApplication() {
         return mApplication;
     }
-    
+
     /**
-     * Return a real (not mocked or instrumented) system Context that can be used when generating
-     * Mock or other Context objects for your Service under test.
-     * 
-     * @return Returns a reference to a normal Context.
+     * Returns the real system context that is saved by {@link #setUp()}. Use it to create
+     * mock or other types of context objects for the service under test.
+     *
+     * @return A normal system context.
      */
     public Context getSystemContext() {
         return mSystemContext;
     }
 
+    /**
+     * Tests that {@link #setupService()} runs correctly and issues an
+     * {@link junit.framework.Assert#assertNotNull(String, Object)} if it does.
+     * You can override this test method if you wish.
+     *
+     * @throws Exception
+     */
     public void testServiceTestCaseSetUpProperly() throws Exception {
         setupService();
         assertNotNull("service should be launched successfully", mService);
diff --git a/test-runner/src/android/test/mock/MockContentResolver.java b/test-runner/src/android/test/mock/MockContentResolver.java
index 3a1dc36c..ab511f8 100644
--- a/test-runner/src/android/test/mock/MockContentResolver.java
+++ b/test-runner/src/android/test/mock/MockContentResolver.java
@@ -28,29 +28,59 @@
 import java.util.Map;
 
 /**
- * A mock {@link android.content.ContentResolver} class that isolates the test code from the real
- * content system.  All methods are non-functional and throw
- * {@link java.lang.UnsupportedOperationException}.  
- *
- * <p>This only isolates the test code in ways that have proven useful so far. More should be
- * added as they become a problem.
+ * <p>
+ *      An extension of {@link android.content.ContentResolver} that is designed for
+ *      testing.
+ * </p>
+ * <p>
+ *      MockContentResolver overrides Android's normal way of resolving providers by
+ *      authority. To have access to a provider based on its authority, users of
+ *      MockContentResolver first instantiate the provider and
+ *      use {@link MockContentResolver#addProvider(String, ContentProvider)}. Resolution of an
+ *      authority occurs entirely within MockContentResolver.
+ * </p>
+ * <p>
+ *      Users can also set an authority's entry in the map to null, so that a provider is completely
+ *      mocked out.
+ * </p>
  */
+
 public class MockContentResolver extends ContentResolver {
     Map<String, ContentProvider> mProviders;
 
+    /*
+     * Creates a local map of providers. This map is used instead of the global map when an
+     * API call tries to acquire a provider.
+     */
     public MockContentResolver() {
         super(null);
         mProviders = Maps.newHashMap();
     }
 
+    /**
+     * Adds access to a provider based on its authority
+     *
+     * @param name The authority name associated with the provider.
+     * @param provider An instance of {@link android.content.ContentProvider} or one of its
+     * subclasses, or null.
+     */
     public void addProvider(String name, ContentProvider provider) {
+
+        /*
+         * Maps the authority to the provider locally.
+         */
         mProviders.put(name, provider);
     }
 
     /** @hide */
     @Override
     protected IContentProvider acquireProvider(Context context, String name) {
+
+        /*
+         * Gets the content provider from the local map
+         */
         final ContentProvider provider = mProviders.get(name);
+
         if (provider != null) {
             return provider.getIContentProvider();
         } else {
@@ -64,7 +94,18 @@
         return true;
     }
 
+    /**
+     * Overrides {@link android.content.ContentResolver#notifyChange(Uri, ContentObserver, boolean)
+     * ContentResolver.notifChange(Uri, ContentObserver, boolean)}. All parameters are ignored.
+     * The method hides providers linked to MockContentResolver from other observers in the system.
+     *
+     * @param uri (Ignored) The uri of the content provider.
+     * @param observer (Ignored) The observer that originated the change.
+     * @param syncToNetwork (Ignored) If true, attempt to sync the change to the network.
+     */
     @Override
-    public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+    public void notifyChange(Uri uri,
+            ContentObserver observer,
+            boolean syncToNetwork) {
     }
 }