Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2661bbd2 authored by Eino-Ville Talvala's avatar Eino-Ville Talvala Committed by Android (Google) Code Review
Browse files

Merge "Camera: Add hidden camera preview to renderscript allocation API"

parents a1d7a123 7005b67c
Loading
Loading
Loading
Loading
+155 −0
Original line number Diff line number Diff line
@@ -31,6 +31,11 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.RSIllegalArgumentException;
import android.renderscript.Type;
import android.util.Log;
import android.text.TextUtils;
import android.view.Surface;
@@ -152,6 +157,7 @@ public class Camera {
    private PictureCallback mRawImageCallback;
    private PictureCallback mJpegCallback;
    private PreviewCallback mPreviewCallback;
    private boolean mUsingPreviewAllocation;
    private PictureCallback mPostviewCallback;
    private AutoFocusCallback mAutoFocusCallback;
    private AutoFocusMoveCallback mAutoFocusMoveCallback;
@@ -327,6 +333,7 @@ public class Camera {
        mJpegCallback = null;
        mPreviewCallback = null;
        mPostviewCallback = null;
        mUsingPreviewAllocation = false;
        mZoomListener = null;

        Looper looper;
@@ -587,6 +594,9 @@ public class Camera {
        mPreviewCallback = cb;
        mOneShot = false;
        mWithBuffer = false;
        if (cb != null) {
            mUsingPreviewAllocation = false;
        }
        // Always use one-shot mode. We fake camera preview mode by
        // doing one-shot preview continuously.
        setHasPreviewCallback(cb != null, false);
@@ -610,6 +620,9 @@ public class Camera {
        mPreviewCallback = cb;
        mOneShot = true;
        mWithBuffer = false;
        if (cb != null) {
            mUsingPreviewAllocation = false;
        }
        setHasPreviewCallback(cb != null, false);
    }

@@ -645,6 +658,9 @@ public class Camera {
        mPreviewCallback = cb;
        mOneShot = false;
        mWithBuffer = true;
        if (cb != null) {
            mUsingPreviewAllocation = false;
        }
        setHasPreviewCallback(cb != null, true);
    }

@@ -744,6 +760,134 @@ public class Camera {
    private native final void _addCallbackBuffer(
                                byte[] callbackBuffer, int msgType);

    /**
     * <p>Create a {@link android.renderscript RenderScript}
     * {@link android.renderscript.Allocation Allocation} to use as a
     * destination of preview callback frames. Use
     * {@link #setPreviewCallbackAllocation setPreviewCallbackAllocation} to use
     * the created Allocation as a destination for camera preview frames.</p>
     *
     * <p>The Allocation will be created with a YUV type, and its contents must
     * be accessed within Renderscript with the {@code rsGetElementAtYuv_*}
     * accessor methods. Its size will be based on the current
     * {@link Parameters#getPreviewSize preview size} configured for this
     * camera.</p>
     *
     * @param rs the RenderScript context for this Allocation.
     * @param usage additional usage flags to set for the Allocation. The usage
     *   flag {@link android.renderscript.Allocation#USAGE_IO_INPUT} will always
     *   be set on the created Allocation, but additional flags may be provided
     *   here.
     * @return a new YUV-type Allocation with dimensions equal to the current
     *   preview size.
     * @throws RSIllegalArgumentException if the usage flags are not compatible
     *   with an YUV Allocation.
     * @see #setPreviewCallbackAllocation
     * @hide
     */
    public final Allocation createPreviewAllocation(RenderScript rs, int usage)
            throws RSIllegalArgumentException {
        Parameters p = getParameters();
        Size previewSize = p.getPreviewSize();
        Type.Builder yuvBuilder = new Type.Builder(rs,
                Element.createPixel(rs,
                        Element.DataType.UNSIGNED_8,
                        Element.DataKind.PIXEL_YUV));
        // Use YV12 for wide compatibility. Changing this requires also
        // adjusting camera service's format selection.
        yuvBuilder.setYuvFormat(ImageFormat.YV12);
        yuvBuilder.setX(previewSize.width);
        yuvBuilder.setY(previewSize.height);

        Allocation a = Allocation.createTyped(rs, yuvBuilder.create(),
                usage | Allocation.USAGE_IO_INPUT);

        return a;
    }

    /**
     * <p>Set an {@link android.renderscript.Allocation Allocation} as the
     * target of preview callback data. Use this method for efficient processing
     * of camera preview data with RenderScript. The Allocation must be created
     * with the {@link #createPreviewAllocation createPreviewAllocation }
     * method.</p>
     *
     * <p>Setting a preview allocation will disable any active preview callbacks
     * set by {@link #setPreviewCallback setPreviewCallback} or
     * {@link #setPreviewCallbackWithBuffer setPreviewCallbackWithBuffer}, and
     * vice versa. Using a preview allocation still requires an active standard
     * preview target to be set, either with
     * {@link #setPreviewTexture setPreviewTexture} or
     * {@link #setPreviewDisplay setPreviewDisplay}.</p>
     *
     * <p>To be notified when new frames are available to the Allocation, use
     * {@link android.renderscript.Allocation#setIoInputNotificationHandler Allocation.setIoInputNotificationHandler}. To
     * update the frame currently accessible from the Allocation to the latest
     * preview frame, call
     * {@link android.renderscript.Allocation#ioReceive Allocation.ioReceive}.</p>
     *
     * <p>To disable preview into the Allocation, call this method with a
     * {@code null} parameter.</p>
     *
     * <p>Once a preview allocation is set, the preview size set by
     * {@link Parameters#setPreviewSize setPreviewSize} cannot be changed. If
     * you wish to change the preview size, first remove the preview allocation
     * by calling {@code setPreviewCallbackAllocation(null)}, then change the
     * preview size, create a new preview Allocation with
     * {@link #createPreviewAllocation createPreviewAllocation}, and set it as
     * the new preview callback allocation target.</p>
     *
     * <p>If you are using the preview data to create video or still images,
     * strongly consider using {@link android.media.MediaActionSound} to
     * properly indicate image capture or recording start/stop to the user.</p>
     *
     * @param previewAllocation the allocation to use as destination for preview
     * @throws IOException if configuring the camera to use the Allocation for
     *   preview fails.
     * @throws IllegalArgumentException if the Allocation's dimensions or other
     *   parameters don't meet the requirements.
     * @see #createPreviewAllocation
     * @see #setPreviewCallback
     * @see #setPreviewCallbackWithBuffer
     * @hide
     */
    public final void setPreviewCallbackAllocation(Allocation previewAllocation)
            throws IOException {
        Surface previewSurface = null;
        if (previewAllocation != null) {
             Parameters p = getParameters();
             Size previewSize = p.getPreviewSize();
             if (previewSize.width != previewAllocation.getType().getX() ||
                     previewSize.height != previewAllocation.getType().getY()) {
                 throw new IllegalArgumentException(
                     "Allocation dimensions don't match preview dimensions: " +
                     "Allocation is " +
                     previewAllocation.getType().getX() +
                     ", " +
                     previewAllocation.getType().getY() +
                     ". Preview is " + previewSize.width + ", " +
                     previewSize.height);
             }
             if ((previewAllocation.getUsage() &
                             Allocation.USAGE_IO_INPUT) == 0) {
                 throw new IllegalArgumentException(
                     "Allocation usage does not include USAGE_IO_INPUT");
             }
             if (previewAllocation.getType().getElement().getDataKind() !=
                     Element.DataKind.PIXEL_YUV) {
                 throw new IllegalArgumentException(
                     "Allocation is not of a YUV type");
             }
             previewSurface = previewAllocation.getSurface();
             mUsingPreviewAllocation = true;
         } else {
             mUsingPreviewAllocation = false;
         }
         setPreviewCallbackSurface(previewSurface);
    }

    private native final void setPreviewCallbackSurface(Surface s);

    private class EventHandler extends Handler
    {
        private Camera mCamera;
@@ -1492,6 +1636,17 @@ public class Camera {
     * @see #getParameters()
     */
    public void setParameters(Parameters params) {
        // If using preview allocations, don't allow preview size changes
        if (mUsingPreviewAllocation) {
            Size newPreviewSize = params.getPreviewSize();
            Size currentPreviewSize = getParameters().getPreviewSize();
            if (newPreviewSize.width != currentPreviewSize.width ||
                    newPreviewSize.height != currentPreviewSize.height) {
                throw new IllegalStateException("Cannot change preview size" +
                        " while a preview allocation is configured.");
            }
        }

        native_setParameters(params.flatten());
    }

+27 −0
Original line number Diff line number Diff line
@@ -586,6 +586,30 @@ static void android_hardware_Camera_setPreviewTexture(JNIEnv *env,
    }
}

static void android_hardware_Camera_setPreviewCallbackSurface(JNIEnv *env,
        jobject thiz, jobject jSurface)
{
    ALOGV("setPreviewCallbackSurface");
    JNICameraContext* context;
    sp<Camera> camera = get_native_camera(env, thiz, &context);
    if (camera == 0) return;

    sp<IGraphicBufferProducer> gbp;
    sp<Surface> surface;
    if (jSurface) {
        surface = android_view_Surface_getSurface(env, jSurface);
        if (surface != NULL) {
            gbp = surface->getIGraphicBufferProducer();
        }
    }
    // Clear out normal preview callbacks
    context->setCallbackMode(env, false, false);
    // Then set up callback surface
    if (camera->setPreviewCallbackTarget(gbp) != NO_ERROR) {
        jniThrowException(env, "java/io/IOException", "setPreviewCallbackTarget failed");
    }
}

static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
    ALOGV("startPreview");
@@ -881,6 +905,9 @@ static JNINativeMethod camMethods[] = {
  { "setPreviewTexture",
    "(Landroid/graphics/SurfaceTexture;)V",
    (void *)android_hardware_Camera_setPreviewTexture },
  { "setPreviewCallbackSurface",
    "(Landroid/view/Surface;)V",
    (void *)android_hardware_Camera_setPreviewCallbackSurface },
  { "startPreview",
    "()V",
    (void *)android_hardware_Camera_startPreview },