vkislicins
vkislicins

Reputation: 3391

Android camera2 surface with size 1920x1080 is not valid

I've implemented camera2 in my app and it is working on Nexus 6P and Nexus 5. Now I'm trying to test it on other devices, and the first one I tried on failed straight away. This is the error I get on HTC M7 running Lollipop:

Surface with size (w=1920, h=1080) and format 0x1 is not valid, 
size not in valid set: [1920x1088, 1440x1088, 1456x832, 1088x1088,
1280x720, 960x720, 960x544, 720x720, 800x480, 768x464, 720x480, 
768x432, 640x480, 544x544, 576x432, 640x384, 640x368, 480x480, 
480x320, 384x288, 352x288, 320x240, 240x160, 176x144]

Any suggestions what should I do in this case? I've tried calculating the nearest resolution to my TextureView (which is 1280x720) and resizing TextureView accordingly, but that doesn't look particularly nice - too much unused space... Didn't see this problem on this device using old camera and SurfaceView

EDIT:

The problem seems to be inside my TextureView. This is my code:

inside a controller I have:

 TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
            int width, int height) {
        startLollipopPreview(width, height);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
            int width, int height) {
        configureTransform(width,height);
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
    }
};


 private void startLollipopPreview(int width, int height) {
    CameraProxy camera = getCurrentCamera();
    try {
        if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
            throw new RuntimeException("Time out waiting to lock camera opening.");
        }
        mPreviewSize = camera
                .getOptimalPreviewSize((Activity) mContext,
                        camera.getSupportedPreviewSizes(
                                width, height), (double) width / height);
        mPreviewTexture.setAspectRatio(mPreviewSize.width, mPreviewSize.height);
        mPreviewTexture.getSurfaceTexture().setDefaultBufferSize(mPreviewSize.width,
                mPreviewSize.height);
        configureTransform(mPreviewSize.width, mPreviewSize.height);
        camera.setStateAndHandler(getCameraStateCallback(), mBackgroundHandler);
        camera.open();
    } catch (CameraHardwareException e) {
        Log.e(TAG, ".surfaceCreated() - Error opening camera", e);
        ((Activity) mContext).finish();
    } catch (InterruptedException e) {
        Log.e(TAG, ".surfaceCreated() - InterruptedException opening camera", e);
    }
}

configureTransform() looks exactly like the Camera2 google sample so I don't think the problem is in there.

inside my TextureView I have the following:

 public void setAspectRatio(int width, int height) {
    if (width < 0 || height < 0) {
        throw new IllegalArgumentException("Size cannot be negative.");
    }
    mRatioWidth = width;
    mRatioHeight = height;
    requestLayout();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        if (width < height * mRatioWidth / mRatioHeight) {
            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
            params.gravity = Gravity.CENTER_VERTICAL;
            setLayoutParams(params);
            setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
        } else {
            setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
        }
    }
}

Upvotes: 2

Views: 6651

Answers (2)

E J Chathuranga
E J Chathuranga

Reputation: 925

The problem you facing change according to emulator/device that you testing the app.

This error occurs when the devices compatible sizes for the dimension of the screen and the MediaRecorder settings are not matched.

When the camera is open (openCamera(int w, int h) method) it's getting the sizes of supported resolutions by using chooseOptimalSize(.... .....) method. But before that, it will set videoSize().

Try to Logcat to get what are the supported sizes and according to that set the mMediaRecorder.setVideoSize(w,h);

Upvotes: 1

cwbowron
cwbowron

Reputation: 1025

I believe you need to set the buffer size to a supported preview size:

textureView.getSurfaceTexture().setDefaultBufferSize(1280,720);

and then you can scale the TextureView so that it fits your screen, even if the preview size is smaller. The Camera2Video sample has an example. Specifically look at configureTransform in Camera2VideoFragment:

/**
 * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`.
 * This method should not to be called until the camera preview size is determined in
 * openCamera, or until the size of `mTextureView` is fixed.
 *
 * @param viewWidth  The width of `mTextureView`
 * @param viewHeight The height of `mTextureView`
 */
private void configureTransform(int viewWidth, int viewHeight) {
    Activity activity = getActivity();
    if (null == mTextureView || null == mPreviewSize || null == activity) {
        return;
    }
    int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
    Matrix matrix = new Matrix();
    RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
    RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
    float centerX = viewRect.centerX();
    float centerY = viewRect.centerY();
    if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
        bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
        matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
        float scale = Math.max(
                (float) viewHeight / mPreviewSize.getHeight(),
                (float) viewWidth / mPreviewSize.getWidth());
        matrix.postScale(scale, scale, centerX, centerY);
        matrix.postRotate(90 * (rotation - 2), centerX, centerY);
    }
    mTextureView.setTransform(matrix);
}

Upvotes: 1

Related Questions