I am getting error in initializing TextureView inside Service for Camera2 API. I want to capture Images with Camera2 API using Services. Below is my code:
Camera Service:
public class CameraService extends Service{
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final int REQUEST_CAMERA_PERMISSION = 1;
private static final String FRAGMENT_DIALOG = "dialog";
int mPictureCounter = 0;
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private static final String TAG = "Camera2BasicFragment";
private static final int STATE_PREVIEW = 0, STATE_WAITING_LOCK = 1, STATE_WAITING_PRECAPTURE = 2, STATE_WAITING_NON_PRECAPTURE = 3, STATE_PICTURE_TAKEN = 4, MAX_PREVIEW_WIDTH = 1920, MAX_PREVIEW_HEIGHT = 1080;
private final TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
};
private String mCameraId;
private AutoFitTextureView mTextureView;
private CameraCaptureSession mCaptureSession;
private CameraDevice mCameraDevice;
private Size mPreviewSize;
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
Activity activity = (Activity) getApplicationContext();
if (null != activity) {
activity.finish();
}
}
};
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private ImageReader mImageReader;
private File mFile;
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Calendar c = Calendar.getInstance();
mFile = new File(getApplicationContext().getExternalFilesDir(null), "pic" + c.get(Calendar.MILLISECOND) + "" + c.get(Calendar.SECOND) + "" + c.get(Calendar.MINUTE) + "" + c.get(Calendar.HOUR_OF_DAY) + "" + c.get(Calendar.DAY_OF_MONTH) + "" + c.get(Calendar.MONTH) + "" + c.get(Calendar.YEAR) + ".jpg");
Log.e("TestingProject", "\n\n\n--------------------------------**********************************\n" +
"Files Absolute Path : " + mFile.getAbsolutePath()
+ "\n**********************************--------------------------------\n\n\n");
mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
}
};
private CaptureRequest.Builder mPreviewRequestBuilder;
private CaptureRequest mPreviewRequest;
private int mState = STATE_PREVIEW;
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
private boolean mFlashSupported;
private int mSensorOrientation;
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW: {
break;
}
case STATE_WAITING_LOCK: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
captureStillPicture();
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
} else {
runPrecaptureSequence();
}
}
break;
}
case STATE_WAITING_PRECAPTURE: {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
mState = STATE_WAITING_NON_PRECAPTURE;
}
break;
}
case STATE_WAITING_NON_PRECAPTURE: {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
mState = STATE_PICTURE_TAKEN;
captureStillPicture();
}
break;
}
}
}
#Override
public void onCaptureProgressed(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull CaptureResult partialResult) {
process(partialResult);
}
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
process(result);
}
};
private void showToast(final String text) {
final Activity activity = (Activity) getApplicationContext();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
}
});
}
}
private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
List<Size> bigEnough = new ArrayList<>();
List<Size> notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
public static test newInstance() {
return new test();
}
private void setUpCameraOutputs(int width, int height) {
Activity activity = (Activity) getApplicationContext();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics
= manager.getCameraCharacteristics(cameraId);
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
continue;
}
Size largest = Collections.max(
Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
new CompareSizesByArea());
mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
ImageFormat.JPEG, /*maxImages*/2);
mImageReader.setOnImageAvailableListener(
mOnImageAvailableListener, mBackgroundHandler);
int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
switch (displayRotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (mSensorOrientation == 90 || mSensorOrientation == 270) {
swappedDimensions = true;
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
if (mSensorOrientation == 0 || mSensorOrientation == 180) {
swappedDimensions = true;
}
break;
default:
Log.e(TAG, "Display rotation is invalid: " + displayRotation);
}
Point displaySize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
int rotatedPreviewWidth = width;
int rotatedPreviewHeight = height;
int maxPreviewWidth = displaySize.x;
int maxPreviewHeight = displaySize.y;
if (swappedDimensions) {rotatedPreviewWidth = height;
rotatedPreviewHeight = width;
maxPreviewWidth = displaySize.y;
maxPreviewHeight = displaySize.x;}
if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {maxPreviewWidth = MAX_PREVIEW_WIDTH;}
if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {maxPreviewHeight = MAX_PREVIEW_HEIGHT;}
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,maxPreviewHeight, largest);
int orientation=getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mTextureView.setAspectRatio(
mPreviewSize.getWidth(), mPreviewSize.getHeight());
} else{mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
}
Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
mFlashSupported = available == null ? false : available;
mCameraId = cameraId;
return;
}} catch (CameraAccessException e) {e.printStackTrace();} catch (NullPointerException e) {
}
}
private void openCamera(int width, int height) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
requestCameraPermission();
return;
}
setUpCameraOutputs(width, height);
configureTransform(width, height);
Activity activity = (Activity) getApplicationContext();
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try{if(!mCameraOpenCloseLock.tryAcquire(2500,TimeUnit.MILLISECONDS)) {throw new RuntimeException("Time out waiting to lock camera opening.");}
manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
if (null != mCaptureSession) {
mCaptureSession.close();
mCaptureSession = null;
}
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
if (null != mImageReader) {
mImageReader.close();
mImageReader = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
mCameraOpenCloseLock.release();
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface surface = new Surface(texture);
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
if (null == mCameraDevice) {
return;
}
mCaptureSession = cameraCaptureSession;
try { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(mPreviewRequestBuilder);
mPreviewRequest = mPreviewRequestBuilder.build(); mCaptureSession.setRepeatingRequest(mPreviewRequest,mCaptureCallback,mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}
#Override
public void onConfigureFailed(
#NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
}, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void configureTransform(int viewWidth, int viewHeight) {
Activity activity = (Activity) getApplicationContext();
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);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
mTextureView.setTransform(matrix);
}
private void takePicture() {
Log.e("TESTING", "taking Pic");
lockFocus();
}
private void lockFocus() {
try {
List<CaptureRequest> captureList = new ArrayList<CaptureRequest>();
mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
for (int i = 0; i < 10; i++) {
captureList.add(mPreviewRequestBuilder.build());
}
mCaptureSession.stopRepeating();
mCaptureSession.captureBurst(captureList, cameraCaptureCallback, null);
mPreviewRequestBuilder.removeTarget(mImageReader.getSurface());
} catch (CameraAccessException e) {e.printStackTrace();}
}
CameraCaptureSession.CaptureCallback cameraCaptureCallback = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
Log.e("TestingProject", "pic # " + (mPictureCounter + 1));
mPictureCounter++;
if (mPictureCounter >= 10)
unlockFocus();
}
};
private void runPrecaptureSequence() {try{mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
mState = STATE_WAITING_PRECAPTURE;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {e.printStackTrace();}
}
private void captureStillPicture() {
try {
final Activity activity = (Activity) getApplicationContext();
if (null == activity || null == mCameraDevice) {return;}
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
setAutoFlash(captureBuilder);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,#NonNull CaptureRequest request,#NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
Log.d(TAG, mFile.toString());
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private int getOrientation(int rotation) {
return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
}
private void unlockFocus() {
try {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
setAutoFlash(mPreviewRequestBuilder);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);
mState = STATE_PREVIEW;
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,mBackgroundHandler);
} catch (CameraAccessException e) {
Log.e("TestingProject", "BHAND... " + e.getMessage());
}
}
private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
if (mFlashSupported) {
requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
}
}
private static class ImageSaver implements Runnable {
private final Image mImage;
private final File mFile;
public ImageSaver(Image image, File file) {
mImage = image;
mFile = file;
}
#Override
public void run() {
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
output.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
static class CompareSizesByArea implements Comparator<Size> {
#Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
public static class ErrorDialog extends DialogFragment {
private static final String ARG_MESSAGE = "message";
public static ErrorDialog newInstance(String message) {
ErrorDialog dialog = new ErrorDialog();
Bundle args = new Bundle();
args.putString(ARG_MESSAGE, message);
dialog.setArguments(args);
return dialog;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
return new AlertDialog.Builder(activity)
.setMessage(getArguments().getString(ARG_MESSAGE))
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {activity.finish();}}).create();}
}
public static class ConfirmationDialog extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Fragment parent = getParentFragment();
return new AlertDialog.Builder(getActivity())
.setMessage(R.string.request_permission)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {FragmentCompat.requestPermissions(parent,
new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
}
}).setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {Activity activity = parent.getActivity();
if (activity != null) {
activity.finish();
}
}
}).create();
}
}
#TargetApi(Build.VERSION_CODES.M)
private void requestCameraPermission() {
String[] perms = {"android.permission.RECORD_AUDIO", "android.permission.CAMERA"};
int permsRequestCode = 200;
((Activity)getApplicationContext()).requestPermissions(perms, permsRequestCode);
}
public CameraService() {
mTextureView = new AutoFitTextureView((Activity)getApplicationContext(),null,0);
mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
mPreviewSize.getWidth(), mPreviewSize.getHeight(), Gravity.CENTER));
mTextureView .setSurfaceTextureListener(mSurfaceTextureListener);
Calendar c = Calendar.getInstance();
mFile = new File(getExternalFilesDir(null), "proof_" + c.get(Calendar.MILLISECOND) + c.get(Calendar.SECOND) + c.get(Calendar.MINUTE) + c.get(Calendar.HOUR_OF_DAY) + c.get(Calendar.DAY_OF_MONTH) + c.get(Calendar.MONTH) + c.get(Calendar.YEAR) + ".jpg");
Log.e("TestingProject", "File Path : " + mFile.getAbsolutePath());
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(10000);
((Activity)getApplicationContext()).runOnUiThread(new Runnable() {public void run() {takePicture();}
});
} catch (InterruptedException e) {e.printStackTrace();}
}
}).start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
AutoFitTextureView Class
public class AutoFitTextureView extends TextureView {
private int mRatioWidth = 0;
private int mRatioHeight = 0;
public AutoFitTextureView(Context context) {
this(context, null);
}
public AutoFitTextureView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
Log.e("TEST", "defStyle = " +defStyle);
for (int i = 0; i < attrs.getAttributeCount() ; i++)
Log.e("TEST", "IN constructor === "+attrs.getAttributeName(i)+"---- Value =
"+attrs.getAttributeValue(i));
}
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) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
} }
This is the stack trace of error
Related
Using OpenCV Android Tutorial I would like to change Preview Resolution. Therefore I commented out the calcPreviewSize function and set the resoultion to 640x480, which is supported and included in camera characteristics. The change of preview resolution is successful but often the app crashes although the given line does not contain any change from the official tutorial.
E/JavaCamera2View: createCaptureSession failed
java.lang.IllegalStateException: Session has been closed; further changes are illegal.
at android.hardware.camera2.impl.CameraCaptureSessionImpl.checkNotClosed(CameraCaptureSessionImpl.java:607)
at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:227)
at org.opencv.android.JavaCamera2View$3.onConfigured(JavaCamera2View.java:220)
at java.lang.reflect.Method.invoke(Native Method)
public class JavaCamera2View extends CameraBridgeViewBase {
private static final String LOGTAG = "JavaCamera2View";
private ImageReader mImageReader;
private int mPreviewFormat = ImageFormat.YUV_420_888;
public int widthP = 640;
public int heightP = 480;
public CameraDevice mCameraDevice;
private CameraCaptureSession mCaptureSession;
private CaptureRequest.Builder mPreviewRequestBuilder;
private String mCameraID;
private android.util.Size mPreviewSize = new android.util.Size(-1, -1);
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
public JavaCamera2View(Context context, int cameraId) {
super(context, cameraId);
}
public JavaCamera2View(Context context, AttributeSet attrs) {
super(context, attrs);
}
private void startBackgroundThread() {
Log.i(LOGTAG, "startBackgroundThread");
stopBackgroundThread();
mBackgroundThread = new HandlerThread("OpenCVCameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private void stopBackgroundThread() {
Log.i(LOGTAG, "stopBackgroundThread");
if (mBackgroundThread == null)
return;
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
Log.e(LOGTAG, "stopBackgroundThread", e);
}
}
protected boolean initializeCamera() {
Log.i(LOGTAG, "initializeCamera");
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
String camList[] = manager.getCameraIdList();
if (camList.length == 0) {
Log.e(LOGTAG, "Error: camera isn't detected.");
return false;
}
if (mCameraIndex == CameraBridgeViewBase.CAMERA_ID_ANY) {
mCameraID = camList[0];
} else {
for (String cameraID : camList) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraID);
if ((mCameraIndex == CameraBridgeViewBase.CAMERA_ID_BACK &&
characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK) ||
(mCameraIndex == CameraBridgeViewBase.CAMERA_ID_FRONT &&
characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT)
) {
mCameraID = cameraID;
break;
}
}
}
if (mCameraID != null) {
//CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraID);
//characteristics = manager.
Log.i(LOGTAG, "Opening camera: " + mCameraID);
manager.openCamera(mCameraID, mStateCallback, mBackgroundHandler);
}
return true;
} catch (CameraAccessException e) {
Log.e(LOGTAG, "OpenCamera - Camera Access Exception", e);
} catch (IllegalArgumentException e) {
Log.e(LOGTAG, "OpenCamera - Illegal Argument Exception", e);
} catch (SecurityException e) {
Log.e(LOGTAG, "OpenCamera - Security Exception", e);
}
return false;
}
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
#Override
public void onDisconnected(CameraDevice cameraDevice) {
cameraDevice.close();
mCameraDevice = null;
}
#Override
public void onError(CameraDevice cameraDevice, int error) {
cameraDevice.close();
mCameraDevice = null;
}
};
private void createCameraPreviewSession() {
final int w = widthP;//mPreviewSize.getWidth(), h = mPreviewSize.getHeight();
final int h = heightP;
Log.i(LOGTAG, "createCameraPreviewSession(" + w + "x" + h + ")");
if (w < 0 || h < 0)
return;
try {
if (null == mCameraDevice) {
Log.e(LOGTAG, "createCameraPreviewSession: camera isn't opened");
return;
}
if (null != mCaptureSession) {
Log.e(LOGTAG, "createCameraPreviewSession: mCaptureSession is already started");
return;
}
mImageReader = ImageReader.newInstance(w, h, mPreviewFormat, 2);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Image image = reader.acquireLatestImage();
if (image == null)
return;
// sanity checks - 3 planes
Image.Plane[] planes = image.getPlanes();
assert (planes.length == 3);
assert (image.getFormat() == mPreviewFormat);
// see also https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888
// Y plane (0) non-interleaved => stride == 1; U/V plane interleaved => stride == 2
assert (planes[0].getPixelStride() == 1);
assert (planes[1].getPixelStride() == 2);
assert (planes[2].getPixelStride() == 2);
ByteBuffer y_plane = planes[0].getBuffer();
ByteBuffer uv_plane = planes[1].getBuffer();
Mat y_mat = new Mat(h, w, CvType.CV_8UC1, y_plane);
Mat uv_mat = new Mat(h / 2, w / 2, CvType.CV_8UC2, uv_plane);
JavaCamera2Frame tempFrame = new JavaCamera2Frame(y_mat, uv_mat, w, h);
deliverAndDrawFrame(tempFrame);
tempFrame.release();
image.close();
}
}, mBackgroundHandler);
Surface surface = mImageReader.getSurface();
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
mCameraDevice.createCaptureSession(Arrays.asList(surface),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
Log.i(LOGTAG, "createCaptureSession::onConfigured");
if (null == mCameraDevice) {
return; // camera is already closed
}
mCaptureSession = cameraCaptureSession;
try {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_OFF);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_OFF);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<Integer>(30,30));
mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler);
Log.i(LOGTAG, "CameraPreviewSession has been started");
} catch (Exception e) {
Log.e(LOGTAG, "createCaptureSession failed", e);
}
}
#Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Log.e(LOGTAG, "createCameraPreviewSession failed");
}
},
null
);
} catch (CameraAccessException e) {
Log.e(LOGTAG, "createCameraPreviewSession", e);
}
}
#Override
protected void disconnectCamera() {
Log.i(LOGTAG, "closeCamera");
try {
CameraDevice c = mCameraDevice;
mCameraDevice = null;
if (null != mCaptureSession) {
mCaptureSession.close();
mCaptureSession = null;
}
if (null != c) {
c.close();
}
if (null != mImageReader) {
mImageReader.close();
mImageReader = null;
}
} finally {
stopBackgroundThread();
}
}
boolean calcPreviewSize(final int width, final int height) {
Log.i(LOGTAG, "calcPreviewSize: " + width + "x" + height);
if (mCameraID == null) {
Log.e(LOGTAG, "Camera isn't initialized!");
return false;
}
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraID);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
int bestWidth = 0, bestHeight = 0;
float aspect = (float) width / height;
android.util.Size[] sizes = map.getOutputSizes(ImageReader.class);
bestWidth = sizes[0].getWidth();
bestHeight = sizes[0].getHeight();
for (android.util.Size sz : sizes) {
int w = sz.getWidth(), h = sz.getHeight();
Log.d(LOGTAG, "trying size: " + w + "x" + h);
if (width >= w && height >= h && bestWidth <= w && bestHeight <= h
&& Math.abs(aspect - (float) w / h) < 0.2) {
bestWidth = w;
bestHeight = h;
}
}
Log.i(LOGTAG, "best size: " + bestWidth + "x" + bestHeight);
assert(!(bestWidth == 0 || bestHeight == 0));
if (mPreviewSize.getWidth() == bestWidth && mPreviewSize.getHeight() == bestHeight)
return false;
else {
mPreviewSize = new android.util.Size(widthP, heightP);
return true;
}
} catch (CameraAccessException e) {
Log.e(LOGTAG, "calcPreviewSize - Camera Access Exception", e);
} catch (IllegalArgumentException e) {
Log.e(LOGTAG, "calcPreviewSize - Illegal Argument Exception", e);
} catch (SecurityException e) {
Log.e(LOGTAG, "calcPreviewSize - Security Exception", e);
}
return false;
}
#Override
protected boolean connectCamera(int width, int height) {
Log.i(LOGTAG, "setCameraPreviewSize(" + width + "x" + height + ")");
startBackgroundThread();
initializeCamera();
try {
boolean needReconfig = calcPreviewSize(width, height);
mFrameWidth = mPreviewSize.getWidth();
mFrameHeight = mPreviewSize.getHeight();
if ((getLayoutParams().width == LayoutParams.MATCH_PARENT) && (getLayoutParams().height == LayoutParams.MATCH_PARENT))
mScale = Math.min(((float)height)/mFrameHeight, ((float)width)/mFrameWidth);
else
mScale = 0;
AllocateCache();
if (needReconfig) {
if (null != mCaptureSession) {
Log.d(LOGTAG, "closing existing previewSession");
mCaptureSession.close();
mCaptureSession = null;
}
createCameraPreviewSession();
}
} catch (RuntimeException e) {
throw new RuntimeException("Interrupted while setCameraPreviewSize.", e);
}
return true;
}
private class JavaCamera2Frame implements CvCameraViewFrame {
#Override
public Mat gray() {
return mYuvFrameData.submat(0, mHeight, 0, mWidth);
}
#Override
public Mat rgba() {
if (mPreviewFormat == ImageFormat.NV21)
Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGBA_NV21, 4);
else if (mPreviewFormat == ImageFormat.YV12)
Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2RGB_I420, 4); // COLOR_YUV2RGBA_YV12 produces inverted colors
else if (mPreviewFormat == ImageFormat.YUV_420_888) {
assert (mUVFrameData != null);
Imgproc.cvtColorTwoPlane(mYuvFrameData, mUVFrameData, mRgba, Imgproc.COLOR_YUV420sp2BGRA);
// TODO: Here we had to change vom Imgproc.COLOR_YUV2RGBA_NV21 to Imgproc.COLOR_YUV420sp2BGRA to get the correct colors.
} else
throw new IllegalArgumentException("Preview Format can be NV21 or YV12");
return mRgba;
}
public JavaCamera2Frame(Mat Yuv420sp, int width, int height) {
super();
mWidth = width;
mHeight = height;
mYuvFrameData = Yuv420sp;
mUVFrameData = null;
mRgba = new Mat();
}
public JavaCamera2Frame(Mat Y, Mat UV, int width, int height) {
super();
mWidth = width;
mHeight = height;
mYuvFrameData = Y;
mUVFrameData = UV;
mRgba = new Mat();
}
public void release() {
mRgba.release();
}
private Mat mYuvFrameData;
private Mat mUVFrameData;
private Mat mRgba;
private int mWidth;
private int mHeight;
};
}
On the face of it, there may be a problem with the modified calcPreviewSize() method: it may return true even if the preview size should not change.
You will see
I/JavaCamera2View best size: WWWWxHHH
in your logcat, where WWWW is not 640 and HHH is not 480.
Changing preview size involves close and reopen of previewSession, and takes time. The code that you use expects repeated calls to calcPreviewSize() to return false.
A possible fix is to rewrite the method this way:
boolean calcPreviewSize(final int width, final int height) {
Log.i(LOGTAG, "calcPreviewSize: " + width + "x" + height);
if (mCameraID == null) {
Log.e(LOGTAG, "Camera isn't initialized!");
return false;
}
if (mPreviewSize.getWidth() == widthP && mPreviewSize.getHeight() == heightP) {
return false;
}
else {
mPreviewSize = new android.util.Size(widthP, heightP);
return true;
}
}
I am new to Android development. I'm making a simple app, which has one Activity. In this Activity I'm trying to get frames from camera and process it real time, but I'm having camera orientation Issue, i.e. image received is 90 degree rotated. There are many solutions available to solve this problem but found no one for the "JavaCameraView". So please help me out how to solve the orientation issue only for "JavaCameraView".
This is my code:
public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
private static final String TAG = "MainActivity";
JavaCameraView javaCameraView;
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS: {
javaCameraView.enableView();
}
break;
default: {
super.onManagerConnected(status);
}
break;
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
//}
javaCameraView = (JavaCameraView) findViewById(R.id.java_camera_view);
javaCameraView.setVisibility(View.VISIBLE);
javaCameraView.setCvCameraViewListener(this);
}
#Override
protected void onPause() {
super.onPause();
if (javaCameraView != null)
javaCameraView.disableView();
}
#Override
protected void onDestroy() {
super.onDestroy();
if (javaCameraView != null)
javaCameraView.disableView();
}
#Override
protected void onResume() {
super.onResume();
if (OpenCVLoader.initDebug()) {
Log.i(TAG, "OpenCV loaded successfully.");
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
} else {
Log.i(TAG, "OpenCV not loaded.");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_1_0, this, mLoaderCallback);
}
}
#Override
public void onCameraViewStarted(int width, int height) {
frame = new Mat(height, width, CV_8UC4);
}
#Override
public void onCameraViewStopped() {
frame.release();
}
#Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
frame = inputFrame.rgba();
//frame=processFrame();
//Imgcodecs.imwrite("/storage/emulated/0/aaaaa+.jpg", frame);
return frame;
}
}
I have solve this issue :
Use below class instead of javaCameraView :
public class PortraitCameraView extends CameraBridgeViewBase implements Camera.PreviewCallback {
private static final int MAGIC_TEXTURE_ID = 10;
private static final String TAG = "JavaCameraView";
private byte mBuffer[];
private Mat[] mFrameChain;
private int mChainIdx = 0;
private Thread mThread;
private boolean mStopThread;
public Camera mCamera;
protected JavaCameraFrame[] mCameraFrame;
private SurfaceTexture mSurfaceTexture;
private int mCameraId;
Handler handler;
boolean callBuffer = false;
Camera.Size bestSize = null;
Camera.Size pictureSize = null;
private LayoutMode mLayoutMode;
private int mCenterPosX = -1;
private int mCenterPosY;
public static enum LayoutMode {
FitToParent, // Scale to the size that no side is larger than the parent
NoBlank // Scale to the size that no side is smaller than the parent
}
public static class JavaCameraSizeAccessor implements ListItemAccessor {
public int getWidth(Object obj) {
Camera.Size size = (Camera.Size) obj;
return size.width;
}
public int getHeight(Object obj) {
Camera.Size size = (Camera.Size) obj;
return size.height;
}
}
public PortraitCameraView(Context context, int cameraId) {
super(context, cameraId);
}
public PortraitCameraView(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected boolean initializeCamera(int width, int height) {
handler = new Handler();
Log.d(TAG, "Initialize java camera");
boolean result = true;
synchronized (this) {
mCamera = null;
boolean connected = false;
int numberOfCameras = android.hardware.Camera.getNumberOfCameras();
android.hardware.Camera.CameraInfo cameraInfo = new android.hardware.Camera.CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
android.hardware.Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) {
try {
mCamera = Camera.open(i);
mCameraId = i;
connected = true;
} catch (RuntimeException e) {
Log.e(TAG, "Camera #" + i + "failed to open: " + e.getMessage());
}
if (connected) break;
}
}
if (mCamera == null) return false;
/* Now set camera parameters */
try {
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
List<Camera.Size> Picturesizes = params.getSupportedPictureSizes();
pictureSize = Picturesizes.get(0);
List<Camera.Size> sizeList = sizes;
bestSize = sizeList.get(0);
Log.d(TAG, "getSupportedPreviewSizes() " + bestSize.width + " " + bestSize.height);
Log.d(TAG, "Picturesizes() " + pictureSize.width + " " + pictureSize.height);
// bestSize.width = GlobalArea.display_width;
//// bestSize.height = GlobalArea.display_height;
for (int i = 1; i < sizeList.size(); i++) {
if ((sizeList.get(i).width * sizeList.get(i).height) > (bestSize.width * bestSize.height)) {
Log.d(TAG, "getSupportedPreviewSizes() " + sizeList.get(i).width + " " + sizeList.get(i).height);
bestSize = sizeList.get(i);
}
}
if (sizes != null) {
/* Select the size that fits surface considering maximum size allowed */
Size frameSize = calculateCameraFrameSize(sizes, new JavaCameraSizeAccessor(), height, width); //use turn around values here to get the correct prev size for portrait mode
params.setPreviewFormat(ImageFormat.NV21);
Log.e(TAG, "Set preview size to " + Integer.valueOf((int) bestSize.width) + " x " + Integer.valueOf((int) bestSize.height));
Log.e(TAG, "Set preview size to " + width + " x " + height);
params.setPreviewSize((int) bestSize.width, (int) bestSize.height);
params.setPictureSize((int) pictureSize.width, (int) pictureSize.height);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
params.setRecordingHint(true);
List<String> FocusModes = params.getSupportedFocusModes();
if (FocusModes != null && FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
boolean hasFlash = SevenBitsDemo.getInstance().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (hasFlash) {
// mOpenCvCameraView.flashOn();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
List<int[]> ints = params.getSupportedPreviewFpsRange();
for (int i = 0; i < ints.size(); i++) {
Log.e("privew size", String.valueOf(ints.get(i).length));
}
// params.setPreviewFpsRange(10000,10000);
mCamera.setParameters(params);
// boolean mSurfaceConfiguring = adjustSurfaceLayoutSize(bestSize, true, width, height);
params = mCamera.getParameters();
GlobalArea.preview_size = params.getPreviewSize();
mFrameWidth = params.getPreviewSize().height; //the frame width and height of the super class are used to generate the cached bitmap and they need to be the size of the resulting frame
mFrameHeight = params.getPreviewSize().width;
int realWidth = mFrameHeight; //the real width and height are the width and height of the frame received in onPreviewFrame ...
int realHeight = mFrameWidth;
if ((getLayoutParams().width == LinearLayout.LayoutParams.MATCH_PARENT) && (getLayoutParams().height == LinearLayout.LayoutParams.MATCH_PARENT))
mScale = Math.min(((float) height) / mFrameHeight, ((float) width) / mFrameWidth);
else
mScale = 0;
if (mFpsMeter != null) {
mFpsMeter.setResolution((int) pictureSize.width, (int) pictureSize.height);
}
int size = mFrameWidth * mFrameHeight;
size = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
mBuffer = new byte[size];
mCamera.addCallbackBuffer(mBuffer);
mCamera.setPreviewCallbackWithBuffer(this);
mFrameChain = new Mat[2];
mFrameChain[0] = new Mat(realHeight + (realHeight / 2), realWidth, CvType.CV_8UC1); //the frame chane is still in landscape
mFrameChain[1] = new Mat(realHeight + (realHeight / 2), realWidth, CvType.CV_8UC1);
AllocateCache();
mCameraFrame = new JavaCameraFrame[2];
mCameraFrame[0] = new JavaCameraFrame(mFrameChain[0], mFrameWidth, mFrameHeight); //the camera frame is in portrait
mCameraFrame[1] = new JavaCameraFrame(mFrameChain[1], mFrameWidth, mFrameHeight);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mSurfaceTexture = new SurfaceTexture(MAGIC_TEXTURE_ID);
mCamera.setPreviewTexture(mSurfaceTexture);
} else
mCamera.setPreviewDisplay(null);
/* Finally we are ready to start the preview */
Log.d(TAG, "startPreview");
mCamera.startPreview();
} else
result = false;
} catch (Exception e) {
result = false;
e.printStackTrace();
}
}
return result;
}
protected void releaseCamera() {
synchronized (this) {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
}
mCamera = null;
if (mFrameChain != null) {
mFrameChain[0].release();
mFrameChain[1].release();
}
if (mCameraFrame != null) {
mCameraFrame[0].release();
mCameraFrame[1].release();
}
}
}
#Override
protected boolean connectCamera(int width, int height) {
/* 1. We need to instantiate camera
* 2. We need to start thread which will be getting frames
*/
/* First step - initialize camera connection */
Log.d(TAG, "Connecting to camera");
if (!initializeCamera(width, height))
return false;
/* now we can start update thread */
Log.d(TAG, "Starting processing thread");
mStopThread = false;
mThread = new Thread(new CameraWorker());
mThread.start();
return true;
}
protected void disconnectCamera() {
/* 1. We need to stop thread which updating the frames
* 2. Stop camera and release it
*/
Log.d(TAG, "Disconnecting from camera");
try {
mStopThread = true;
Log.d(TAG, "Notify thread");
synchronized (this) {
this.notify();
}
Log.d(TAG, "Wating for thread");
if (mThread != null)
mThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mThread = null;
}
/* Now release camera */
releaseCamera();
}
public void onPreviewFrame(byte[] frame, Camera arg1) {
synchronized (this) {
mFrameChain[1 - mChainIdx].put(0, 0, frame);
this.notify();
}
if (mCamera != null)
mCamera.addCallbackBuffer(mBuffer);
}
private class JavaCameraFrame implements CvCameraViewFrame {
private Mat mYuvFrameData;
private Mat mRgba;
private int mWidth;
private int mHeight;
private Mat mRotated;
public Mat gray() {
if (mRotated != null) mRotated.release();
mRotated = mYuvFrameData.submat(0, mWidth, 0, mHeight);
//submat with reversed width and height because its done on the
landscape frame
mRotated = mRotated.t();
Core.flip(mRotated, mRotated, 1);
return mRotated;
}
public Mat rgba() {
Imgproc.cvtColor(mYuvFrameData, mRgba, Imgproc.COLOR_YUV2BGR_NV12, 4);
if (mRotated != null) mRotated.release();
mRotated = mRgba.t();
Core.flip(mRotated, mRotated, 1);
return mRotated;
}
public JavaCameraFrame(Mat Yuv420sp, int width, int height) {
super();
mWidth = width;
mHeight = height;
mYuvFrameData = Yuv420sp;
mRgba = new Mat();
}
public void release() {
mRgba.release();
if (mRotated != null) mRotated.release();
}
}
private class CameraWorker implements Runnable {
public void run() {
do {
synchronized (PortraitCameraView.this) {
try {
PortraitCameraView.this.wait();
} catch (InterruptedException e) {
Log.e(TAG, "CameraWorker interrupted", e);
}
}
if (!mStopThread) {
if (!mFrameChain[mChainIdx].empty())
deliverAndDrawFrame(mCameraFrame[mChainIdx]);
mChainIdx = 1 - mChainIdx;
}
} while (!mStopThread);
Log.d(TAG, "Finish processing thread");
}
}
}
So now use PortraitCameraView in your xml and java file because i have convert javacamera view in portrait mode in this class.
You can use setMaxFrame size function.
javaCameraView.setMaxFrameSize(480, 640);
480 is width and 640 is height. Now javacameraview is portrait.
I am using the fallowing solution to resize the bitmap. But it results portion of the image is lost.
Here is is my code.
BitmapFactory.Options bmFactoryOptions = new BitmapFactory.Options();
bmFactoryOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
bmFactoryOptions.inMutable = true;
bmFactoryOptions.inSampleSize = 2;
Bitmap originalCameraBitmap = BitmapFactory.decodeByteArray(pData, 0, pData.length, bmFactoryOptions);
rotatedBitmap = getResizedBitmap(originalCameraBitmap, cameraPreviewLayout.getHeight(), cameraPreviewLayout.getWidth() - preSizePriviewHight(), (int) rotationDegrees);
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight, int angle) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postRotate(angle);
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
DeliverItApplication.getInstance().setImageCaptured(true);
return resizedBitmap;
}
And here is the image height and width : Preview surface size:352:288 Before resized bitmap width : 320 Height : 240 CameraPreviewLayout width : 1080 Height : 1362 Resized bitmap width : 1022 Height : 1307
Your java code is right but you haven't care about Aspect Ratio of Image thats whys your Image Portion is cutting.
Original Image Height and Width :
Height = 352;
Width = 288;
Aspect Ratio = h/w; => Ratio = 1.2;
and you taken new width and height :
newHeight = 320;
newWidth = 240;
But if we take Image Height as 320 then according Image Aspect Ratio Its Width becomes :
calculated width = newHeight /Ratio; => 320/1.2= 266.66= 267;
calculated width = 267;
difference of portion cutting is = calculated width -newWidth;
= 267 -240 ;
= 27 ;
So you need to take height and width for new bitmap.
newHeight = 320;
newWidth = 267 ;
public class MarkableImageCaptureActivity extends Activity implements OnClickListener {
private static Logger logger = LoggerFactory.getLogger(MarkableImageCaptureActivity.class);
#InjectView(R.id.top_menu_bar)
private LinearLayout topMenuLayout;
#InjectView(R.id.top_menu_title)
private TextView topMenuTitleTV;
#InjectView(R.id.image_desc_edittext)
private EditText imageDescEditText;
#InjectView(R.id.camerapreview_layout)
private FrameLayout cameraPreviewLayout;
#InjectView(R.id.btn_camera_capture)
private Button captureBtn;
#InjectView(R.id.btn_camera_save)
private Button saveBtn;
#InjectView(R.id.btn_camera_cancel)
private Button cancelBtn;
#InjectView(R.id.edit_captured_image_layout)
private RelativeLayout editCapturedImageLayout;
#InjectView(R.id.edit_captured_image)
private ImageView editCapturedImage;
#InjectView(R.id.color_container_layout)
private LinearLayout colorContainerLayout;
#InjectView(R.id.btn_markable_red)
private Button btnMarkableRed;
#InjectView(R.id.btn_markable_blue)
private Button btnMarkableBlue;
#InjectView(R.id.btn_markable_green)
private Button btnMarkableGreen;
#InjectView(R.id.btn_markable_white)
private Button btnMarkableWhite;
#InjectView(R.id.btn_markable_black)
private Button btnMarkableBlack;
#InjectView(R.id.btn_undo)
private TextView capturedImageUndo;
private MarkableImageView editableCapturedImageview;
#InjectView(R.id.flashSwitch)
private ToggleButton flashToggle;
private static final int DIALOG_CAPTURE_EXCEPTION = 2101;
private static final int DIALOG_CAPTURING_EXCEPTION = 2102;
private static final int DIALOG_SAVE_EXCEPTION = 0;
private String imageFileName = null;
private File imageFile = null;
private Stop targetStop = null;
private int stopId = DIntent.VALUE_INVALID_ID;
private float rotationDegrees = 0;
private Camera camera = null;
private CameraPreview cameraPreview;
private Bitmap rotatedBitmap;
private static final int PRIMARY_CAMERA_ID = 0;
private boolean imageCaptured = false;
private boolean inPreview = false;
private boolean isFlashSupports;
private boolean isCapturing = false;
private boolean isFlashOn;
private boolean isDocNameEditable;
private String imageDesc = "";
private Handler focusHandler = null;
private int captureType;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_start_camera_for_photo_capture);
setupTopMenuBar(topMenuLayout, null, getString(R.string.menuitem_back), getString(R.string.menuitem_done), true, true, new ImageCaptureTopMenuListener());
focusHandler = new Handler();
editableCapturedImageview = (MarkableImageView) findViewById(R.id.editable_captured_imageview);
Bundle intentBundle = getIntent().getExtras();
isDocNameEditable = getIntent().getBooleanExtra(DIntent.EXTRA_OBJECT_TYPE_DOCUMENT_EDITABLE, false);
imageDesc = getIntent().getStringExtra(DIntent.EXTRA_OBJECT_TYPE_DOCUMENT_NAME);
if (savedInstanceState != null) {
stopId = savedInstanceState.getInt(DIntent.EXTRA_STOP_ID);
imageDesc = savedInstanceState.getString(DIntent.EXTRA_IMAGE_DESC);
imageCaptured = savedInstanceState.getBoolean(DIntent.EXTRA_IS_IMAGE_CAPTURED);
inPreview = savedInstanceState.getBoolean(DIntent.EXTRA_IN_PREVIEW);
isFlashOn=savedInstanceState.getBoolean(DIntent.FLASH_MODE_ON);
if (imageCaptured) {
rotatedBitmap = savedInstanceState.getParcelable(DIntent.EXTRA_IMAGE_BITMAP);
}
}
captureType = intentBundle.getInt(DIntent.EXTRA_TYPE_CAPTURE);
if (captureType == DIntent.EXTRA_TYPE_IMAGE_CAPTURE) {
stopId = intentBundle.getInt(DIntent.EXTRA_STOP_ID);
try {
targetStop = getDbHelper().getStopDao().queryForId(stopId);
} catch (SQLException e) {
logger.error("Exception finding stop by Id!!", e);
}
}
isFlashSupports = getApplicationContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (isFlashSupports) {
flashToggle.setVisibility(View.VISIBLE);
flashToggle.setOnClickListener(this);
} else {
flashToggle.setVisibility(View.GONE);
}
captureBtn.setOnClickListener(this);
saveBtn.setOnClickListener(this);
cancelBtn.setOnClickListener(this);
imageDescEditText.setText(imageDesc);
if (AndroidUtility.isValidTrimmedString(imageDesc)) {
if (!isDocNameEditable) {
imageDescEditText.setEnabled(false);
}
} else {
imageDescEditText.setEnabled(true);
}
editCapturedImage.setOnClickListener(this);
btnMarkableWhite.setOnClickListener(this);
btnMarkableRed.setOnClickListener(this);
btnMarkableBlue.setOnClickListener(this);
btnMarkableGreen.setOnClickListener(this);
btnMarkableBlack.setOnClickListener(this);
capturedImageUndo.setOnClickListener(this);
}
#Override
protected void onStart() {
super.onStart();
logger.info("onStart:imageCaptured" + imageCaptured);
boolean isImageCaptured = DeliverItApplication.getInstance().isImageCaptured();
if (!isImageCaptured) {
if (rotatedBitmap != null) {
activateCapturedImageView(rotatedBitmap);
} else {
activatePreviewLayout();
}
}
}
private void activateCapturedImageView(Bitmap rotatedBitmap) {
cameraPreviewLayout.setVisibility(View.GONE);
editableCapturedImageview.setCapturedBitmap(rotatedBitmap);
editableCapturedImageview.setVisibility(View.VISIBLE);
editCapturedImageLayout.setVisibility(View.VISIBLE);
captureBtn.setVisibility(View.GONE);
saveBtn.setVisibility(View.VISIBLE);
saveBtn.requestFocus();
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) editableCapturedImageview.getLayoutParams();
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
layoutParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
layoutParams.width = rotatedBitmap.getWidth();
layoutParams.height = rotatedBitmap.getHeight();
editableCapturedImageview.setLayoutParams(layoutParams);
logger.info("Inside activateCapturedImageView");
releaseCamera();
}
private void activatePreviewLayout() {
logger.info("Insie activatePreviewLayout");
cameraPreviewLayout.setVisibility(View.VISIBLE);
editableCapturedImageview.setVisibility(View.GONE);
editCapturedImageLayout.setVisibility(View.GONE);
captureBtn.setVisibility(View.VISIBLE);
captureBtn.requestFocus();
saveBtn.setVisibility(View.GONE);
}
#Override
protected void onResume() {
super.onResume();
logger.info("onResume");
if (rotatedBitmap == null || inPreview) {
activateCameraPreview();
}
}
public void activateCameraPreview() {
logger.info("activateCameraPreview");
camera = getCameraInstance(camera);
if (camera != null) {
cameraPreview = new CameraPreview(this, camera);
rotationDegrees = getCameraDisplayOrientation(this, PRIMARY_CAMERA_ID);
camera.setDisplayOrientation((int) rotationDegrees);
cameraPreviewLayout.addView(cameraPreview);
inPreview = true;
isCapturing = false;
Camera.Parameters params = camera.getParameters();
if (isFlashSupported(params)) {
logger.info("activateCameraPreview: Flash Mode:"+ isFlashOn);
if (isFlashOn) {
params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
} else {
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
} else {
flashToggle.setVisibility(View.GONE);
}
camera.setParameters(params);
enableAutoFocusMode(camera);
}
}
private Runnable doFocusRunnable = new Runnable() {
#Override
public void run() {
if (camera != null) {
focusHandler.removeCallbacks(doFocusRunnable);
if (CameraPreview.isCameraPreviewStarted) {
try {
camera.autoFocus(autoFocusCallback);
logger.info("doFocusRunnable autofocus set");
} catch (Exception e) {
logger.error("Error while calling autofocus in camera."+e);
}
} else {
logger.info("doFocusRunnable isCameraPreviewStarted false. Postdelay for 2 seconds");
focusHandler.postDelayed(doFocusRunnable, 2000);
}
}
}
};
Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback(){
#Override
public void onAutoFocus(boolean arg0, Camera arg1) {
if (camera != null) {
logger.info("Excuting onAutoFocus callback");
focusHandler.postDelayed(doFocusRunnable, 2000);
}
}
};
public Camera getCameraInstance(Camera oldCamera) {
Camera newCamera = null;
try {
logger.info("attempt to get a Camera instance");
if (oldCamera == null) {
logger.info("oldCamera is null.Opening Camera");
newCamera = Camera.open(PRIMARY_CAMERA_ID);
} else {
logger.info("oldCamera is not null.Releasing it and Opening Camera");
oldCamera.release();
newCamera = Camera.open(PRIMARY_CAMERA_ID);
}
} catch (Exception e) {
logger.info("Camera is not available (in use or does not exist)");
}
return newCamera; // returns null if camera is unavailable
}
#Override
protected void onPause() {
super.onPause();
logger.info("onPause");
releaseCamera();
}
private void releaseCamera() {
if (null != camera) {
try {
focusHandler.removeCallbacks(doFocusRunnable);
CameraPreview.isCameraPreviewStarted = false;
camera.cancelAutoFocus();
camera.stopPreview();
camera.release();
camera = null;
cameraPreview.setVisibility(View.GONE);
cameraPreview = null;
inPreview = false;
logger.info("Camera released successfully ");
} catch (Exception e) {
logger.error("Error while releasing camera in releaseCamera()."+e);
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
logger.info("onSaveInstanceState");
outState.putInt(DIntent.EXTRA_STOP_ID, stopId);
outState.putBoolean(DIntent.EXTRA_IS_IMAGE_CAPTURED, imageCaptured);
outState.putBoolean(DIntent.EXTRA_IN_PREVIEW, inPreview);
outState.putString(DIntent.EXTRA_IMAGE_DESC, imageDesc);
}
#Override
protected void onDestroy() {
super.onDestroy();
logger.info("onDestroy");
DeliverItApplication.getInstance().setImageCaptured(false);
}
public float getCameraDisplayOrientation(Activity activity, int cameraId) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(cameraId, info);
int displayOrientation = activity.getWindowManager().getDefaultDisplay().getRotation();
int infoOrientation = info.orientation;
float degrees = 0;
switch (displayOrientation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
float result;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
logger.info("Camera.CameraInfo.CAMERA_FACING_FRONT");
result = (infoOrientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
logger.info("Camera.CameraInfo.CAMERA_FACING_BACK");
result = (infoOrientation - degrees + 360) % 360;
}
logger.info("Display Rotation:" + displayOrientation + " & infoOrientation:" + infoOrientation + " & degrees:"
+ degrees + " & info.facing:" + info.facing + " & result:" + result);
return result;
}
private void captureImage() {
try {
if (camera != null) {
//camera.autoFocus(autoFocusCallback);
isCapturing = true;
logger.info("Taking picture while clicking Capture button");
camera.takePicture(null, null, pictureCallBack);
} else {
if (rotatedBitmap == null) {
showDialog(DIALOG_CAMERA_UNAVAILABLE);
}
}
} catch (Exception e) {
releaseCamera();
logger.error("Error in camera initialization in StartCaptureForPhoto screen.");
activatePreviewLayout();
activateCameraPreview();
}
}
private PictureCallback pictureCallBack = new PictureCallback() {
#Override
public void onPictureTaken(byte[] pData, Camera pCamera) {
BitmapFactory.Options bmFactoryOptions = new BitmapFactory.Options();
bmFactoryOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
bmFactoryOptions.inMutable = true;
// bmFactoryOptions.inSampleSize = 2;
Bitmap originalCameraBitmap = BitmapFactory.decodeByteArray(pData, 0, pData.length, bmFactoryOptions);
logger.info("before resized bitmap width : "+originalCameraBitmap.getWidth() + " Hieght : "+ originalCameraBitmap.getHeight());
rotatedBitmap = getResizedBitmap(originalCameraBitmap, cameraPreviewLayout.getHeight(), cameraPreviewLayout.getWidth() - preSizePriviewHight(), (int) rotationDegrees);
logger.info("cameraPreviewLayout width : "+cameraPreviewLayout.getWidth() + " Hieght : "+ cameraPreviewLayout.getHeight());
if (rotatedBitmap != null) {
imageCaptured = true;
activateCapturedImageView(rotatedBitmap);
} else {
imageCaptured = false;
}
isCapturing = false;
originalCameraBitmap.recycle();
flashToggle.setVisibility(View.GONE);
}
};
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight, int angle) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postRotate(angle);
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
DeliverItApplication.getInstance().setImageCaptured(true);
return resizedBitmap;
}
#Override
public void onClick(View pView) {
switch (pView.getId()) {
case R.id.btn_camera_capture:
if (!isCapturing) {
captureImage();
} else {
logger.error("Picture being captured.User clicked so fast.");
}
break;
case R.id.btn_camera_save:
if (imageCaptured) {
String description = imageDescEditText.getText().toString();
if (description != null && description.length() > 0) {
saveCapturedImage();
} else {
imageDescEditText.setError((getString(R.string.error_photo_desc)));
}
}
break;
case R.id.edit_captured_image:
colorContainerLayout.setVisibility(View.VISIBLE);
capturedImageUndo.setVisibility(View.VISIBLE);
editableCapturedImageview.setPaintBrushColor(Color.WHITE);
break;
case R.id.btn_markable_green:
editableCapturedImageview.setPaintBrushColor(Color.parseColor("#6AD523"));
break;
case R.id.btn_markable_blue:
editableCapturedImageview.setPaintBrushColor(Color.parseColor("#407FF0"));
break;
case R.id.btn_markable_red:
editableCapturedImageview.setPaintBrushColor(Color.parseColor("#B0321B"));
break;
case R.id.btn_markable_white:
editableCapturedImageview.setPaintBrushColor(Color.parseColor("#F7F5FA"));
break;
case R.id.btn_markable_black:
editableCapturedImageview.setPaintBrushColor(Color.parseColor("#2A2A2C"));
break;
case R.id.btn_undo:
editableCapturedImageview.onClickUndo();
break;
case R.id.btn_camera_cancel:
releaseCamera();
finish();
break;
case R.id.flashSwitch:
switchFlash();
default:
break;
}
}
#Override
protected Dialog onCreateDialog(int id, Bundle bundle) {
switch (id) {
case DIALOG_CAPTURE_EXCEPTION:
DIAlertDialog captureErrorDialog = new DIAlertDialog(this, getText(R.string.dialog_camera_error)
.toString(), getText(R.string.dialog_capture_exception).toString(), null, null);
return captureErrorDialog;
case DIALOG_SAVE_EXCEPTION:
DIAlertDialog imageSaveErrorDialog = new DIAlertDialog(this, getText(R.string.dialog_camera_error)
.toString(), getText(R.string.dialog_image_save_exception).toString(), null, null);
return imageSaveErrorDialog;
case DIALOG_CAPTURING_EXCEPTION:
DIAlertDialog capturingDialog = new DIAlertDialog(this, getText(R.string.dialog_camera_error)
.toString(), getText(R.string.dialog_capturing_exception).toString(), null, null);
return capturingDialog;
default:
return super.onCreateDialog(id, bundle);
}
}
private class ImageCaptureTopMenuListener implements OnClickListener {
#Override
public void onClick(View v) {
if (v.getVisibility() == View.VISIBLE && v.getId() == R.id.top_left_menu_item) {
onBackPressed();
} else if (v.getVisibility() == View.VISIBLE && v.getId() == R.id.top_right_menu_item) {
if (imageCaptured) {
String description = imageDescEditText.getText().toString();
if (description != null && description.length() > 0) {
saveCapturedImage();
} else {
imageDescEditText.setError((getString(R.string.error_photo_desc)));
}
}
}
}
}
private void switchFlash() {
if (camera == null) {
return;
}
if (!isFlashOn) {
Camera.Parameters params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
camera.setParameters(params);
if (rotatedBitmap != null) {
activateCapturedImageView(rotatedBitmap);
} else {
activatePreviewLayout();
}
isFlashOn = true;
} else {
Camera.Parameters params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
if (rotatedBitmap != null) {
activateCapturedImageView(rotatedBitmap);
} else {
activatePreviewLayout();
}
isFlashOn = false;
}
}
private int preSizePriviewHight() {
int defaultSize = 100;
switch (getResources().getDisplayMetrics().densityDpi) {
case DisplayMetrics.DENSITY_LOW:
defaultSize = 75;
break;
case DisplayMetrics.DENSITY_MEDIUM:
defaultSize = 80;
break;
case DisplayMetrics.DENSITY_HIGH:
defaultSize = 120;
break;
case DisplayMetrics.DENSITY_XHIGH:
defaultSize = 160;
break;
case DisplayMetrics.DENSITY_XXHIGH:
defaultSize = 430;
break;
case DisplayMetrics.DENSITY_XXXHIGH:
defaultSize = 460;
break;
default:
break;
}
return defaultSize;
}
private void enableAutoFocusMode(Camera camera) {
try {
Camera.Parameters params = camera.getParameters();
List<String> focusParameterList = params.getSupportedFocusModes();
if (focusParameterList != null && focusParameterList.size() > 0) {
logger.info("Supported focus mode:"+focusParameterList);
if (focusParameterList.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
logger.info("enableAutoFocusMode: Starting focus mode");
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
camera.setParameters(params);
/*
Below line commented due to crash issue in focus mode because of autoFocus call before start preview
So we are giving 2 sec delay for autoFocus.
*/
//camera.autoFocus(autoFocusCallback);
focusHandler.postDelayed(doFocusRunnable, 2000);
}
}
} catch (Exception e) {
logger.error("Error while setting AutoFocus in Camera."+e);
}
}
private boolean isFlashSupported(Camera.Parameters params) {
if (params != null) {
List<String> flashModes = params.getSupportedFlashModes();
if(flashModes == null) {
return false;
}
for(String flashMode : flashModes) {
if(Camera.Parameters.FLASH_MODE_ON.equals(flashMode)) {
return true;
}
}
}
return false;
}
#Override
protected void onStop() {
super.onStop();
if (editableCapturedImageview != null) {
editableCapturedImageview.resetCanvas();
}
}
}
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static Logger logger = LoggerFactory.getLogger(CameraPreview.class);
private SurfaceHolder surfaceHolder;
private Camera camera;
private List<Size> cameraSizeList;
private Camera.Parameters cameraParameters;
public static boolean isCameraPreviewStarted = false;
public CameraPreview(Context context, Camera camera) {
super(context);
logger.info("Inside CameraPreview(Context context, Camera camera)");
this.camera = camera;
isCameraPreviewStarted = false;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (camera != null) {
logger.info("Camera Surface has been created, now tell the camera where to draw the preview.");
camera.setPreviewDisplay(holder);
camera.startPreview();
isCameraPreviewStarted = true;
}
} catch (IOException e) {
logger.error("Error occured in surfaceCreated.", e);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
logger.info("Camera SurfaceView Destroyed.");
isCameraPreviewStarted = false;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (surfaceHolder.getSurface() == null) {
if (logger.isDebugEnabled()) {
logger.debug("onsurfaceChanged : preview surface does not exist");
}
return;
}
try {
if (logger.isDebugEnabled()) {
logger.debug("onsurfaceChanged :stop preview before making resize/rotate/reformatting changes");
}
isCameraPreviewStarted = false;
camera.stopPreview();
} catch (Exception e) {
logger.error("onsurfaceChanged :Ignored surfaceChanged because tried to stop a non-existent preview", e);
}
if (camera != null) {
cameraParameters = camera.getParameters();
cameraSizeList = cameraParameters.getSupportedPreviewSizes();
cameraParameters.setPreviewSize(getMaxSupportedVideoSize().width, getMaxSupportedVideoSize().height);
surfaceHolder.setFixedSize(getMaxSupportedVideoSize().width, getMaxSupportedVideoSize().height);
camera.setParameters(cameraParameters);
if (logger.isDebugEnabled()) {
logger.debug("onsurfaceChanged : made resize/rotate/reformatting changes:preview size:"
+ String.valueOf(getMaxSupportedVideoSize().width) + ":"
+ String.valueOf(getMaxSupportedVideoSize().height));
}
}
try {
if (logger.isDebugEnabled()) {
logger.debug("onsurfaceChanged :start preview with new settings");
}
if (camera != null) {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
logger.info("onsurfaceChanged :start preview with new settings");
isCameraPreviewStarted = true;
}
} catch (Exception e) {
logger.error("onsurfaceChanged :Error while resetting camera preview on surfaceChanged.", e);
}
}
public Size getMaxSupportedVideoSize() {
int maximum = cameraSizeList.get(0).width;
int position = 0;
for (int i = 0; i < cameraSizeList.size() - 1; i++) {
if (cameraSizeList.get(i).width > maximum) {
maximum = cameraSizeList.get(i).width; // new maximum
position = i - 1;
}
}
if (position == 0) {
int secondMax = cameraSizeList.get(1).width;
position = 1;
for (int j = 1; j < cameraSizeList.size() - 1; j++) {
if (cameraSizeList.get(j).width > secondMax) {
secondMax = cameraSizeList.get(j).width; // new maximum
position = j;
}
}
}
return cameraSizeList.get(position);
}
}
I am working on Panning and cropping the landscape video using Texture View.I am in a half way that I can pan the landscape video from left to right vice versa by using this example
https://github.com/crust87/Android-VideoCropView.
FFMPEG can crop the particular portion of the video by using this command
ffmpeg -i /sdcard/videokit/in.mp4 -filter:v crop=720:1088:0:0 -c:a
copy /sdcard/videokit/out.mp4
How can I crop only the video which is visible in Texture View and save it local storage in Android.
crop=720:1088:0:0 is a hard coded width and height of the video and it is cropping fine.But how can I get the width and height of the visible video in Texture View to crop the visible video and Save it to the local storage in android.
public class MainActivity extends Activity {
// Layout Components
private FrameLayout top_frame;
// Attributes
private String originalPath;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.check);
top_frame = (FrameLayout)findViewById(R.id.top_frame);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1000 && resultCode == RESULT_OK) {
final VideoCropView mVideoCropView = new VideoCropView(this);
mVideoCropView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mVideoCropView.start();
}
});
top_frame.addView(mVideoCropView);
Uri selectedVideoUri = data.getData();
originalPath = getRealPathFromURI(selectedVideoUri);
mVideoCropView.setVideoURI(selectedVideoUri);
mVideoCropView.seekTo(1);
}
}
public void onButtonLoadClick(View v) {
top_frame.removeAllViews();
Intent lIntent = new Intent(Intent.ACTION_PICK);
lIntent.setType("video/*");
lIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivityForResult(lIntent, 1000);
}
public String getRealPathFromURI(Uri contentUri) { // getting image path from gallery.
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = getApplicationContext().getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
CropVideoView
public class VideoCropView extends TextureView implements MediaPlayerControl {
// Constants
private static final String LOG_TAG = "VideoCropView";
private static final int STATE_ERROR = -1;
private static final int STATE_IDLE = 0;
private static final int STATE_PREPARING = 1;
private static final int STATE_PREPARED = 2;
private static final int STATE_PLAYING = 3;
private static final int STATE_PAUSED = 4;
private static final int STATE_PLAYBACK_COMPLETED = 5;
// MediaPlayer Components
protected Context mContext;
private MediaPlayer mMediaPlayer;
private Surface mSurface;
private OnInfoListener mOnInfoListener;
private OnCompletionListener mOCompletionListener;
private OnErrorListener mOnErrorListener;
private OnPreparedListener mOnPreparedListener;
private OnTranslatePositionListener mOnTranslatePositionListener;
// CropView Components
private Matrix mMatrix;
// MediaPlayer Attributes
protected Uri mUri;
private int mCurrentBufferPercentage;
private int mSeekWhenPrepared;
protected int mVideoWidth;
protected int mVideoHeight;
// CropView Attributes
private float mRatioWidth;
private float mRatioHeight;
private float mPositionX;
private float mPositionY;
private float mBoundX;
private float mBoundY;
private int mRotate;
private float mScaleX;
private float mScaleY;
private float mScale;
// Working Variables
private int mCurrentState = STATE_IDLE;
private int mTargetState = STATE_IDLE;
// Touch Event
// past position x, y and move point
float mPastX;
float mPastY;
float mTouchDistance;
private Context context;
// Constructors
public VideoCropView(final Context context) {
super(context);
mContext = context;
initAttributes();
initVideoView();
}
public VideoCropView(final Context context, final AttributeSet attrs) {
super(context, attrs);
mContext = context;
initAttributes(context, attrs, 0);
initVideoView();
}
public VideoCropView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
initAttributes(context, attrs, defStyleAttr);
initVideoView();
}
private void initAttributes() {
mRatioWidth = 1;
mRatioHeight = 1;
}
private void initAttributes(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VideoCropView, defStyleAttr, 0);
mRatioWidth = typedArray.getInteger(R.styleable.VideoCropView_ratio_width, 3);
mRatioHeight = typedArray.getInteger(R.styleable.VideoCropView_ratio_height, 4);
}
#Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
int heightLayout;
int widthLayout;
widthLayout = MeasureSpec.getSize(widthMeasureSpec);
heightLayout = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthLayout, heightLayout);
/*if(widthMeasureSpec < heightMeasureSpec){
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = (int) ((width / mRatioWidth) * mRatioHeight);
setMeasuredDimension(width, height);
}else{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height =MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
*/
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(mCurrentState == STATE_ERROR || mCurrentState == STATE_IDLE || mCurrentState == STATE_PREPARING) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPastX = event.getX();
mPastY = event.getY();
mTouchDistance = 0;
case MotionEvent.ACTION_MOVE:
if(mBoundX!=0 || mBoundY!=0) {
float dx = event.getX() - mPastX;
float dy = event.getY() - mPastY;
updateViewPosition(dx, dy);
mPastX = event.getX();
mPastY = event.getY();
mTouchDistance += (Math.abs(dx) + Math.abs(dy));
}
break;
case MotionEvent.ACTION_UP:
if (mTouchDistance < 25) {
if (isPlaying()) {
pause();
} else {
start();
}
}
mTouchDistance = 0;
break;
}
return true;
}
#Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(VideoView.class.getName());
}
#Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(VideoView.class.getName());
}
public int resolveAdjustedSize(int desiredSize, int measureSpec) {
Log.d(LOG_TAG, "Resolve called.");
int result = desiredSize;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
/*
* Parent says we can be as big as we want. Just don't be larger
* than max size imposed on ourselves.
*/
result = desiredSize;
break;
case MeasureSpec.AT_MOST:
/*
* Parent says we can be as big as we want, up to specSize. Don't be
* larger than specSize, and don't be larger than the max size
* imposed on ourselves.
*/
result = Math.min(desiredSize, specSize);
break;
case MeasureSpec.EXACTLY:
// No choice. Do what we are told.
result = specSize;
break;
}
return result;
}
public void initVideoView() {
mVideoHeight = 0;
mVideoWidth = 0;
setFocusable(false);
setSurfaceTextureListener(mSurfaceTextureListener);
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
}
public void setVideoPath(String path) {
if (path != null) {
setVideoURI(Uri.parse(path));
}
}
public void setVideoURI(Uri pVideoURI) {
mUri = pVideoURI;
mSeekWhenPrepared = 0;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(mContext, pVideoURI);
// create thumbnail bitmap
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
String rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
try {
mRotate = Integer.parseInt(rotation);
} catch(NumberFormatException e) {
mRotate = 0;
}
}
retriever.release();
openVideo();
requestLayout();
invalidate();
}
public void stopPlayback() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
}
}
public void openVideo() {
if ((mUri == null) || (mSurface == null)) {
// not ready for playback just yet, will try again later
return;
}
// Tell the music playback service to pause
// TODO: these constants need to be published somewhere in the
// framework.
Intent intent = new Intent("com.android.music.musicservicecommand");
intent.putExtra("command", "pause");
mContext.sendBroadcast(intent);
// we shouldn't clear the target state, because somebody might have
// called start() previously
release(false);
try {
mMediaPlayer = new MediaPlayer();
// TODO: create SubtitleController in MediaPlayer, but we need
// a context for the subtitle renderers
mMediaPlayer.setOnPreparedListener(mPreparedListener);
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
mMediaPlayer.setOnInfoListener(mInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mCurrentBufferPercentage = 0;
mMediaPlayer.setDataSource(mContext, mUri);
mMediaPlayer.setSurface(mSurface);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
mMediaPlayer.setLooping(true);
mCurrentState = STATE_PREPARING;
} catch (IllegalStateException e) {
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
e.printStackTrace();
} catch (IOException e) {
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
e.printStackTrace();
}
}
private OnVideoSizeChangedListener mSizeChangedListener = new OnVideoSizeChangedListener() {
#Override
public void onVideoSizeChanged(final MediaPlayer mp, final int width,
final int height) {
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
if (mVideoWidth != 0 && mVideoHeight != 0) {
requestLayout();
if(mVideoWidth >= mVideoHeight)
initVideo();
}
}
};
private OnPreparedListener mPreparedListener = new OnPreparedListener() {
#Override
public void onPrepared(final MediaPlayer mp) {
mCurrentState = STATE_PREPARED;
if (mOnPreparedListener != null) {
mOnPreparedListener.onPrepared(mp);
}
mVideoWidth = mp.getVideoWidth();
mVideoHeight = mp.getVideoHeight();
int seekToPosition = mSeekWhenPrepared; // mSeekWhenPrepared may be
// changed after seekTo()
if (seekToPosition != 0) {
seekTo(seekToPosition);
}
if ((mVideoWidth != 0) && (mVideoHeight != 0)) {
if(mVideoWidth >= mVideoHeight) initVideo();
if (mTargetState == STATE_PLAYING) {
start();
}
} else {
// We don't know the video size yet, but should start anyway.
// The video size might be reported to us later.
if (mTargetState == STATE_PLAYING) {
start();
}
}
}
};
private OnCompletionListener mCompletionListener = new OnCompletionListener() {
#Override
public void onCompletion(final MediaPlayer mp) {
mCurrentState = STATE_PLAYBACK_COMPLETED;
mTargetState = STATE_PLAYBACK_COMPLETED;
if (mOCompletionListener != null) {
mOCompletionListener.onCompletion(mMediaPlayer);
}
}
};
private OnInfoListener mInfoListener = new OnInfoListener() {
public boolean onInfo(MediaPlayer mp, int arg1, int arg2) {
if (mOnInfoListener != null) {
mOnInfoListener.onInfo(mp, arg1, arg2);
}
return true;
}
};
private OnErrorListener mErrorListener = new OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
Log.d(LOG_TAG, "Error: " + framework_err + "," + impl_err);
mCurrentState = STATE_ERROR;
mTargetState = STATE_ERROR;
/* If an error handler has been supplied, use it and finish. */
if (mOnErrorListener != null) {
if (mOnErrorListener.onError(mMediaPlayer, framework_err,
impl_err)) {
return true;
}
}
return true;
}
};
private OnBufferingUpdateListener mBufferingUpdateListener = new OnBufferingUpdateListener() {
#Override
public void onBufferingUpdate(final MediaPlayer mp, final int percent) {
mCurrentBufferPercentage = percent;
}
};
public void setOnPreparedListener(OnPreparedListener listener) {
mOnPreparedListener = listener;
}
public void setOnCompletionListener(OnCompletionListener listener) {
mOCompletionListener = listener;
}
public void setOnErrorListener(OnErrorListener listener) {
mOnErrorListener = listener;
}
public void setOnInfoListener(OnInfoListener listener) {
mOnInfoListener = listener;
}
private void release(boolean cleartargetstate) {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
mCurrentState = STATE_IDLE;
if (cleartargetstate) {
mTargetState = STATE_IDLE;
}
}
}
#Override
public void start() {
if (isInPlaybackState()) {
mMediaPlayer.start();
mCurrentState = STATE_PLAYING;
}
mTargetState = STATE_PLAYING;
}
#Override
public void pause() {
if (isInPlaybackState()) {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
mCurrentState = STATE_PAUSED;
}
}
mTargetState = STATE_PAUSED;
}
#Override
public int getDuration() {
if (isInPlaybackState()) {
return mMediaPlayer.getDuration();
}
return -1;
}
#Override
public int getCurrentPosition() {
if (isInPlaybackState()) {
return mMediaPlayer.getCurrentPosition();
}
return 0;
}
#Override
public void seekTo(int msec) {
if (isInPlaybackState()) {
mMediaPlayer.seekTo(msec);
mSeekWhenPrepared = 0;
} else {
mSeekWhenPrepared = msec;
}
}
#Override
public boolean isPlaying() {
return isInPlaybackState() && mMediaPlayer.isPlaying();
}
#Override
public int getBufferPercentage() {
if (mMediaPlayer != null) {
return mCurrentBufferPercentage;
}
return 0;
}
private boolean isInPlaybackState() {
return (mMediaPlayer != null && mCurrentState != STATE_ERROR
&& mCurrentState != STATE_IDLE && mCurrentState != STATE_PREPARING);
}
#Override
public boolean canPause() {
return false;
}
#Override
public boolean canSeekBackward() {
return false;
}
#Override
public boolean canSeekForward() {
return false;
}
#Override
public int getAudioSessionId() {
return -1;
}
SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurface = new Surface(surface);
openVideo();
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
boolean isValidState = (mTargetState == STATE_PLAYING);
boolean hasValidSize = (mVideoWidth == width && mVideoHeight == height);
if (mMediaPlayer != null && isValidState && hasValidSize) {
start();
}
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if (mMediaPlayer != null) {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
if (mSurface != null) {
mSurface.release();
mSurface = null;
}
return true;
}
#Override
public void onSurfaceTextureUpdated(final SurfaceTexture surface) {
}
};
#Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility == View.INVISIBLE || visibility == View.GONE) {
if (isPlaying()) {
stopPlayback();
}
}
}
public float getScale() {
return mScale;
}
private void initVideo() {
try {
int width = getWidth();
int height = getHeight();
mScaleX = 1.0f;
mScaleY = 1.0f;
mPositionX = 0;
mPositionY = 0;
mBoundX = 0;
mBoundY = 0;
mMatrix = new Matrix();
mScaleX = (float) mVideoWidth / width;
mScaleY = (float) mVideoHeight / height;
mBoundX = width - mVideoWidth / mScaleY;
mBoundY = height - mVideoHeight / mScaleX;
if (mScaleX < mScaleY) {
mScale = mScaleX;
mScaleY = mScaleY * (1.0f / mScaleX);
mScaleX = 1.0f;
mBoundX = 0;
} else {
mScale = mScaleY;
mScaleX = mScaleX * (1.0f / mScaleY);
mScaleY = 1.0f;
mBoundY = 0;
}
mMatrix = new Matrix();
mMatrix.setScale(mScaleX, mScaleY);
setTransform(mMatrix);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
public void updateViewPosition(float x, float y) {
float nextX = mPositionX + x;
float nextY = mPositionY + y;
if(mScaleX == 1.0f) {
x = 0;
} else {
if(nextX > 0) {
x = -mPositionX;
mPositionX = mPositionX + x;
} else if(nextX < mBoundX) {
x = mBoundX - mPositionX;
mPositionX = mPositionX + x;
} else {
mPositionX = nextX;
}
}
if(mScaleY == 1.0f) {
y = 0;
} else {
if(nextY > 0) {
y = -mPositionY;
mPositionY = mPositionY + y;
} else if(nextY < mBoundY) {
y = mBoundY - mPositionY;
mPositionY = mPositionY + y;
} else {
mPositionY = nextY;
}
}
if(mOnTranslatePositionListener != null) {
mOnTranslatePositionListener.onTranslatePosition(mPositionX, mPositionY, mPositionX * -mScale, mPositionY * -mScale);
}
mMatrix.postTranslate(x, y);
setTransform(mMatrix);
invalidate();
}
// public void setOriginalRatio() {
// if(mVideoWidth != 0 && mVideoHeight != 0) {
// int gcd = gcd(mVideoWidth, mVideoHeight);
// setRatio(mVideoWidth / gcd, mVideoHeight / gcd);
// }
// }
public int gcd(int n, int m) {
while (m != 0) {
int t = n % m;
n = m;
m = t;
}
return Math.abs(n);
}
// public void setRatio(float ratioWidth, float ratioHeight) {
// mRatioWidth = ratioWidth;
// mRatioHeight = ratioHeight;
//
// int seek = getCurrentPosition();
//
// requestLayout();
// invalidate();
// openVideo();
//
// seekTo(seek);
// }
public float getRatioWidth() {
return mRatioWidth;
}
public float getRatioHeight() {
return mRatioHeight;
}
public float getRealPositionX() {
return mPositionX * -mScale;
}
public float getRealPositionY() {
return mPositionY * -mScale;
}
public int getVideoWidth() {
return mVideoWidth;
}
public int getVideoHeight() {
return mVideoHeight;
}
public int getRotate() {
return mRotate;
}
public void setOnTranslatePositionListener(OnTranslatePositionListener pOnTranslatePositionListener) {
mOnTranslatePositionListener = pOnTranslatePositionListener;
}
public void setContext(Context context) {
this.context = context;
}
public interface OnTranslatePositionListener {
public abstract void onTranslatePosition(float x, float y, float rx, float ry);
}
}
FFMPEG for cropping particular portion
ffmpeg -i /sdcard/videokit/in.mp4 -filter:v crop=720:1088:0:0 -c:a copy /sdcard/videokit/out.mp4
public class SimpleExample extends Activity {
String workFolder = null;
String demoVideoFolder = null;
String demoVideoPath = null;
String vkLogPath = null;
private boolean commandValidationFailedFlag = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ffmpeg_demo_client_1);
demoVideoFolder = Environment.getExternalStorageDirectory().getAbsolutePath() + "/videokit/";
demoVideoPath = demoVideoFolder + "in.mp4";
Log.i(Prefs.TAG, getString(R.string.app_name) + " version: " + GeneralUtils.getVersionName(getApplicationContext()) );
workFolder = getApplicationContext().getFilesDir().getAbsolutePath() + "/";
//Log.i(Prefs.TAG, "workFolder: " + workFolder);
vkLogPath = workFolder + "vk.log";
GeneralUtils.copyLicenseFromAssetsToSDIfNeeded(this, workFolder);
GeneralUtils.copyDemoVideoFromAssetsToSDIfNeeded(this, demoVideoFolder);
Button invoke = (Button)findViewById(R.id.invokeButton);
invoke.setOnClickListener(new OnClickListener() {
public void onClick(View v){
Log.i(Prefs.TAG, "run clicked.");
if (GeneralUtils.checkIfFileExistAndNotEmpty(demoVideoPath)) {
new TranscdingBackground(SimpleExample.this).execute();
}
else {
Toast.makeText(getApplicationContext(), demoVideoPath + " not found", Toast.LENGTH_LONG).show();
}
}
});
int rc = GeneralUtils.isLicenseValid(getApplicationContext(), workFolder);
Log.i(Prefs.TAG, "License check RC: " + rc);
}
public class TranscdingBackground extends AsyncTask<String, Integer, Integer>
{
ProgressDialog progressDialog;
Activity _act;
String commandStr;
public TranscdingBackground (Activity act) {
_act = act;
}
#Override
protected void onPreExecute() {
EditText commandText = (EditText)findViewById(R.id.CommandText);
commandStr = commandText.getText().toString();
progressDialog = new ProgressDialog(_act);
progressDialog.setMessage("FFmpeg4Android Transcoding in progress...");
progressDialog.show();
}
protected Integer doInBackground(String... paths) {
Log.i(Prefs.TAG, "doInBackground started...");
// delete previous log
boolean isDeleted = GeneralUtils.deleteFileUtil(workFolder + "/vk.log");
Log.i(Prefs.TAG, "vk deleted: " + isDeleted);
PowerManager powerManager = (PowerManager)_act.getSystemService(Activity.POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "VK_LOCK");
Log.d(Prefs.TAG, "Acquire wake lock");
wakeLock.acquire();
///////////// Set Command using code (overriding the UI EditText) /////
//commandStr = "ffmpeg -y -i /sdcard/videokit/in.mp4 -strict experimental -s 320x240 -r 30 -aspect 3:4 -ab 48000 -ac 2 -ar 22050 -vcodec mpeg4 -b 2097152 /sdcard/videokit/out.mp4";
//String[] complexCommand = {"ffmpeg", "-y" ,"-i", "/sdcard/videokit/in.mp4","-strict","experimental","-s", "160x120","-r","25", "-vcodec", "mpeg4", "-b", "150k", "-ab","48000", "-ac", "2", "-ar", "22050", "/sdcard/videokit/out.mp4"};
///////////////////////////////////////////////////////////////////////
LoadJNI vk = new LoadJNI();
try {
vk.run(GeneralUtils.utilConvertToComplex(commandStr), workFolder, getApplicationContext());
GeneralUtils.copyFileToFolder(vkLogPath, demoVideoFolder);
} catch (Throwable e) {
Log.e(Prefs.TAG, "vk run exeption.", e);
}
finally {
if (wakeLock.isHeld())
wakeLock.release();
else{
Log.i(Prefs.TAG, "Wake lock is already released, doing nothing");
}
}
Log.i(Prefs.TAG, "doInBackground finished");
return Integer.valueOf(0);
}
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onCancelled() {
Log.i(Prefs.TAG, "onCancelled");
//progressDialog.dismiss();
super.onCancelled();
}
#Override
protected void onPostExecute(Integer result) {
Log.i(Prefs.TAG, "onPostExecute");
progressDialog.dismiss();
super.onPostExecute(result);
// finished Toast
String rc = null;
if (commandValidationFailedFlag) {
rc = "Command Vaidation Failed";
}
else {
rc = GeneralUtils.getReturnCodeFromLog(vkLogPath);
}
final String status = rc;
SimpleExample.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(SimpleExample.this, status, Toast.LENGTH_LONG).show();
if (status.equals("Transcoding Status: Failed")) {
Toast.makeText(SimpleExample.this, "Check: " + vkLogPath + " for more information.", Toast.LENGTH_LONG).show();
}
}
});
}
}
}
try to use getBitmap: TextureView.getBitmap for VideoCropView
it returns bitmap wanted resolution.
Then you can crop using Bitmap.createBitmap
like this
resizedbitmap=Bitmap.createBitmap(bmp, 0,0,yourwidth, yourheight);
Use this library to crop video with visible portion
Video Trimmer Library
I've searched stack exchange and google for a solution but I can't seem to find one that works. My camera preview works beautifully in portrait, but when the orientation switches to landscape, it is not full screen and is highly distorted. I'm also trying to implement this as a fragment
Here is my code
CameraFragment.java
public class CameraFragment extends Fragment implements SurfaceHolder.Callback, Camera.PictureCallback {
public static final String TAG = CameraFragment.class.getSimpleName();
private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
private static final int PREVIEW_SIZE_MAX_WIDTH = 640;
private int cameraId;
private Camera camera;
private SurfaceHolder surfaceHolder;
private CameraFragmentListener listener;
private int displayOrientation;
private int layoutOrientation;
private CameraOrientationListener orientationListener;
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
if(!(activity instanceof CameraFragmentListener)){
throw new IllegalArgumentException("Must implement CameraFragmentListener interface");
}
listener = (CameraFragmentListener)activity;
orientationListener = new CameraOrientationListener(activity);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
CameraPreview previewView = new CameraPreview(getActivity());
previewView.getHolder().addCallback(this);
return previewView;
}
#Override
public void onResume() {
super.onResume();
orientationListener.enable();
try {
camera = Camera.open(cameraId);
} catch (Exception exception) {
Log.e(TAG, "Can't open camera with id " + cameraId, exception);
listener.onCameraError();
return;
}
}
#Override
public void onPause() {
super.onPause();
orientationListener.disable();
if(camera != null) {
stopCameraPreview();
camera.release();
}
}
private synchronized void startCameraPreview() {
determineDisplayOrientation();
setupCamera();
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception exception) {
Log.e(TAG, "Can't start camera preview due to Exception", exception);
listener.onCameraError();
}
}
private synchronized void stopCameraPreview() {
try {
camera.stopPreview();
} catch (Exception exception) {
Log.i(TAG, "Exception during stopping camera preview");
}
}
public void determineDisplayOrientation() {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int displayOrientation;
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
displayOrientation = (cameraInfo.orientation + degrees) % 360;
displayOrientation = (360 - displayOrientation) % 360;
} else {
displayOrientation = (cameraInfo.orientation - degrees + 360) % 360;
}
this.displayOrientation = displayOrientation;
this.layoutOrientation = degrees;
camera.setDisplayOrientation(displayOrientation);
}
public void setupCamera() {
Camera.Parameters parameters = camera.getParameters();
Camera.Size bestPreviewSize = determineBestPreviewSize(parameters);
Camera.Size bestPictureSize = determineBestPictureSize(parameters);
parameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
parameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);
camera.setParameters(parameters);
}
private Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
return determineBestSize(sizes, PREVIEW_SIZE_MAX_WIDTH);
}
private Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
return determineBestSize(sizes, PICTURE_SIZE_MAX_WIDTH);
}
protected Camera.Size determineBestSize(List<Camera.Size> sizes, int widthThreshold) {
Camera.Size bestSize = null;
for (Camera.Size currentSize : sizes) {
boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
boolean isBetterSize = (bestSize == null || currentSize.width > bestSize.width);
boolean isInBounds = currentSize.width <= PICTURE_SIZE_MAX_WIDTH;
if (isDesiredRatio && isInBounds && isBetterSize) {
bestSize = currentSize;
}
}
if (bestSize == null) {
listener.onCameraError();
return sizes.get(0);
}
return bestSize;
}
public void takePicture(){
orientationListener.rememberOrientation();
camera.takePicture(null, null, this);
}
#Override
public void onPictureTaken(byte[] data, Camera camera){
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
int rotation = (displayOrientation + orientationListener.getRememberedOrientation() + layoutOrientation) % 360;
if(rotation != 0){
Bitmap oldBitmap = bitmap;
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
oldBitmap.recycle();
}
listener.onPictureTaken(bitmap);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
this.surfaceHolder = holder;
startCameraPreview();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
//fragment handles release
}
}
CameraFragmentListener.java
public interface CameraFragmentListener {
public void onCameraError();
public void onPictureTaken(Bitmap bitmap);
}
CameraOrientationListener.java
public class CameraOrientationListener extends OrientationEventListener {
private int currentNormalizedOrientation;
private int rememberNormalizedOrientation;
public CameraOrientationListener (Context context){
super(context, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onOrientationChanged(int orientation) {
if(orientation != ORIENTATION_UNKNOWN){
currentNormalizedOrientation = normalize(orientation);
}
}
private int normalize(int degrees){
if(degrees > 315 || degrees <= 45)
return 0;
if(degrees > 45 && degrees <= 135)
return 90;
if(degrees > 135 && degrees <= 225)
return 180;
if(degrees > 225 && degrees <= 315)
return 270;
throw new RuntimeException("Wrong bruh");
}
public void rememberOrientation(){
rememberNormalizedOrientation = currentNormalizedOrientation;
}
public int getRememberedOrientation(){
return rememberNormalizedOrientation;
}
}
CameraPreview.java
public class CameraPreview extends SurfaceView {
private static final double ASPECT_RATIO = 3.0 / 4.0;
public CameraPreview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CameraPreview(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
if (width > height * ASPECT_RATIO) {
width = (int) (height * ASPECT_RATIO + .5);
} else {
height = (int) (width / ASPECT_RATIO + .5);
}
setMeasuredDimension(width, height);
}
}
CameraActivity.java
public class CameraActivity extends Activity implements CameraFragmentListener {
public static final String TAG = CameraActivity.class.getSimpleName();
private static final int PICTURE_QUALITY = 90;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
}
#Override
public void onCameraError(){
Toast.makeText(this, getString(R.string.toast_error_camera_preview), Toast.LENGTH_SHORT).show();
finish();
}
public void takePicture(View view){
view.setEnabled(false);
CameraFragment fragment = (CameraFragment)getFragmentManager().findFragmentById(R.id.camera_fragment);
fragment.takePicture();
}
public void onPictureTaken(Bitmap bitmap){
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
),
getString(R.string.app_name)
);
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
showSavingPictureErrorToast();
return;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile = new File(
mediaStorageDir.getPath() + File.separator + "MUSTACHE_"+ timeStamp + ".jpg"
);
try {
FileOutputStream stream = new FileOutputStream(mediaFile);
bitmap.compress(CompressFormat.JPEG, PICTURE_QUALITY, stream);
} catch (IOException exception) {
showSavingPictureErrorToast();
Log.w(TAG, "IOException during saving bitmap", exception);
return;
}
MediaScannerConnection.scanFile(
this,
new String[] { mediaFile.toString() },
new String[] { "image/jpeg" },
null
);
Intent intent = new Intent(this, PhotoActivity.class);
intent.setData(Uri.fromFile(mediaFile));
startActivity(intent);
finish();
}
private void showSavingPictureErrorToast() {
Toast.makeText(this, getText(R.string.toast_error_save_picture), Toast.LENGTH_SHORT).show();
}
}
Sorry for the extremely long post, I just want to be as thorough as possible. Thanks in advance guys!
If you want your preview to be full screen, you should set the full screen flag in your activity before you call setContentView:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_camera);
}