2

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);
        }
    }
}
vkislicins
  • 3,331
  • 3
  • 32
  • 62

2 Answers2

1

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);
}
cwbowron
  • 1,015
  • 6
  • 10
  • Added the scaling bit, still getting the error message. Now with the new resolution that I'm calculating with increased aspect ratio tolerance, I'm getting a slightly different values in the error `Surface with size (w=1890, h=1080)...` - the rest of the message is the same – vkislicins Dec 17 '15 at 15:18
  • I think the problem is in my `TextureView`. I'm using the same code as in the sample to set aspect ratio and call `setMeasuredDimension` inside `onMeasure` but it doesn't seem to be working correctly. – vkislicins Dec 17 '15 at 16:16
  • I think you might need to adjust the buffer size of the texture view as well. `textureView.getSurfaceTexture().setDefaultBufferSize( previewWidth, previewHeight );` – cwbowron Dec 17 '15 at 16:19
  • Did you use setDefaultBufferSize( 1280, 720 ) or one of the other listed supported sizes? – cwbowron Dec 17 '15 at 16:23
  • Another supported one - 1920x1088 – vkislicins Dec 17 '15 at 16:28
  • I've updated the post with some code - maybe you can spot something there? Thanks again for your help. – vkislicins Dec 17 '15 at 16:29
  • It doesn't crash - just gives an error and no preview. I've figured out how to make it work though, however I can't say I understand the behaviour. Inside `onMeasure` I need to change `if (width < height * mRatioWidth / mRatioHeight)` to `if (width > height * mRatioWidth / mRatioHeight)` – vkislicins Dec 17 '15 at 16:43
  • Hi, have you guys found this solution? – raditya gumay Nov 27 '16 at 15:32
1

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);

E J Chathuranga
  • 927
  • 12
  • 27