Video broadcast with Android's Camera2 API - android

I'm trying to make an app which broadcast video through internet, currently I am using the deprecated Camera API, adding a Camera.PreviewCallback to the Camera object and then sending the byte array which comes in the onPreviewFrame() method from Camera.PreviewCallback.
But now I want to test the new Camera2 API, I am watching at the Camera2BasicTutorial , and I think that I need to make a CameraCaptureSession.CaptureCallback object to get the image byte array, something like the tutorial says:
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();
}
};
And then add it to the CameraCaptureSession:
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
The problem is that I don't know how to retrieve each image byte array from any of the parameters in onCaptureCompleted() from the CaptureCallback.
Any help?

You're kind of right- you can't get the image data from the onCaptureCompleted() method. That callback only returns the metadata about the exposure for your own bookkeeping. The actual image information gets sent to whatever Surface you indicated in the exposure's CaptureRequest.

At least I realized how to do what I wanted, from the Camera2BasicTutorial, I did the following changes to the Camera2BasicFragment class:
Modify captureStillPicture() method to delete stuff which I determined that was unneccessary with my broadcast needs, also don't allow this method to stop the repeating mode:
private void captureStillPicture() {
try {
final Activity activity = getActivity();
if (null == activity || null == mCameraDevice) {
return;
}
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
}
};
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
In createCameraPreviewSession() method, disable the automaticall flash:
// When the session is ready, we start displaying the preview.
mCaptureSession = cameraCaptureSession;
try {
// Auto focus should be continuous for camera preview.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// Flash is automatically enabled when necessary.
// mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
// CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
// Finally, we start displaying the camera preview.
mPreviewRequest = mPreviewRequestBuilder.build();
mCaptureSession.setRepeatingRequest(mPreviewRequest,
mCaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
I created a boolean var to detect if there is an image currently being under process, to not queue all the frames that the camera captures; and another boolean to track if there is a frame sending through internet:
private boolean mWorking = false;
private boolean mNetworkWorking = false;
Modify the CaptureCallback object to run the captureStillPicture() method in each frame (only if there is no frame processing at the moment).
case STATE_PREVIEW: {
if (!mWorking){
Log.d(TAG, "capturing..");
mWorking = true;
mBackgroundHandler.post(new Runnable() {
#Override
public void run() {
captureStillPicture();
}
});
} else {
Log.d(TAG, "thread working, doing nothing");
}
break;
Finally, read the frame and send it; I achieved this modifying the OnImageAvailableListener object:
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(final ImageReader reader) {
// Process the image.
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
final byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
image.close();
if (!mNetworkWorking){
Thread thread = new Thread(){
#Override
public void run(){
mNetworkWorking = true;
HttpResponse response = null;
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(mBroadcastUrl);
post.setEntity(new ByteArrayEntity(bytes));
try {
response = client.execute(post);
} catch (ClientProtocolException e) {
if (BuildConfig.LOCAL_LOG)
Log.w(TAG, "ClientProtocolException: "+e.getMessage());
} catch (IOException e) {
if (BuildConfig.LOCAL_LOG)
Log.w(TAG, "IOException: "+e.getMessage());
}
mNetworkWorking = false;
}
};
thread.setName("networkThread");
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
}
mWorking = false;
}
};
That's all.

Related

Surface had no valid native Surface for Camera2

I've integrated camera2 with textureVIew. It works on all devices but on tablet when we capture image for first time, it crashesand displays following logs.
Fatal Exception: java.lang.IllegalArgumentException: Surface had no valid native Surface.
at android.hardware.camera2.legacy.LegacyCameraDevice.nativeGetSurfaceId(LegacyCameraDevice.java)
at android.hardware.camera2.legacy.LegacyCameraDevice.getSurfaceId(LegacyCameraDevice.java:658)
at android.hardware.camera2.legacy.LegacyCameraDevice.containsSurfaceId(LegacyCameraDevice.java:678)
at android.hardware.camera2.legacy.RequestThreadManager$2.onPictureTaken(RequestThreadManager.java:220)
at android.hardware.Camera$EventHandler.handleMessage(Camera.java:1248)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.hardware.camera2.legacy.CameraDeviceUserShim$CameraLooper.run(CameraDeviceUserShim.java:136)
at java.lang.Thread.run(Thread.java:818)
Following code is used to capture the image.
protected void takePicture() {
if (getContext() == null || cameraDevice == null) return;
lockFocus();
CameraManager manager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
if (characteristics != null) {
sizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
ImageReader reader = getImageReader();
if (reader == null) return;
List<Surface> outputSurfaces = getSurfaces(reader);
final CaptureRequest.Builder captureBuilder = getCaptureBuilder(reader);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
}
};
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, null);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
Any help would be appreciated.
That can happen if the ImageReader gets garbage collected before the camera picture capture completes.
Does the getImageReader method store the image reader somewhere permanent (like as a class member)? If not, the Surface from the ImageReader is like a weak reference, and will not keep it from being removed.

Image processing framework using Android camera2 API and OpenCV

I am new to camera2 api. I want to build an image processing framework on my Android phone.
Step1: use the Camera2 API to open a camera preview stream
Step2: feed the preview frame data to OpenCV for processing
Step3: display the processed result live on the screen
Currently, I have finished Step1 using ImageReader and C++ OpenCV code. However, I don't know how to do step3.
How do I display the processed image on the screen? (I want to display the normal image, and overlay an icon if I detect predefined object)
Here are some key codes:
protected void createCameraPreview() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
// Surface surface = new Surface(texture);
Surface mImageSurface = mImageReader.getSurface();
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
// captureRequestBuilder.addTarget(surface);
captureRequestBuilder.addTarget(mImageSurface);
cameraDevice.createCaptureSession(Arrays.asList(mImageSurface), new CameraCaptureSession.StateCallback(){
#Override
public void onConfigured(#NonNull CameraCaptureSession cameraCaptureSession) {
//The camera is already closed
if (null == cameraDevice) {
return;
}
cameraCaptureSessions = cameraCaptureSession;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
protected void updatePreview() {
if(null == cameraDevice) {
Log.e(TAG, "updatePreview error, return");
}
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Log.e(TAG, "onImageAvailable: " + count++);
Image img = null;
img = reader.acquireNextImage();
try {
if (img == null) throw new NullPointerException("cannot be null");
ByteBuffer buffer = img.getPlanes()[0].getBuffer();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
int width = img.getWidth();
int height = img.getHeight();
// ****try to get captured img for display here (synchronized)
// ****try to process image for detecting the object here (asynchronized)
} catch (NullPointerException ex) {
ex.printStackTrace();
}finally {
Log.e(TAG, "in the finally! ------------");
if (img != null)
img.close();
}
}
};

Images get interlaced when using camera2 API

I'm trying to create an app using the camera2 api, what I need is to create a burst of 30 fps which I was able to create.
The problems is both the preview images and the saved images interlaced (I'm photographing some blinking leds so its easy to see).
I tried to disable the auto exposure and set the sensitivity myself but that didn't work.
private void captureStillPicture() {
try {
final Activity activity = getActivity();
mPictureCounter = 0;
if (null == activity || null == mCameraDevice) {
return;
}
List<CaptureRequest> captureList = new ArrayList<CaptureRequest>();
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// Use the same AE and AF modes as the preview.
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
captureBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, 2000);
//Auto focus - should keep that
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, Consts.aeMode);
captureBuilder.addTarget(mImageReader.getSurface());
for(int i = 0; i < Consts.frameAmount; i++) {
captureList.add(captureBuilder.build());
}
CameraCaptureSession.CaptureCallback CaptureCallback = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
mPictureCounter++;
unlockFocus();
}
};
mCaptureSession.stopRepeating();
mCaptureSession.captureBurst(captureList, CaptureCallback, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
Any thought?

Enable a preview during a capture session on Camera2

I'm building a camera app based on Camera2, but the picture I save is not matching the latest one I saw on my surface view. It seems that the Preview session works but when I ask for a capture, the new request stop the preview and capture the image. The surface view freeze on the latest pic and that create a gap between the time I press the shutter button (preview running and request capture) and the onCaptureCompleted from the capture request.
Here is the preview session
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Log.d(TAG, "here is the width of texture" + mPreviewSize.getWidth());
Log.d(TAG, "here is the height of texture" +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 {
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();
}
}
the mCaptureCallback is defined as below :
private CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (mState) {
case STATE_PREVIEW:
break;
case STATE_CAPTURE:
mState = STATE_PREVIEW;
capturePicture();
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) {
TotalCaptureResult iResult = result;
Log.d(TAG, "Frame on Completed: "+result.getFrameNumber());
process(result);
}
}
What's happening is that I repeating the preview and it works. the process is just used to keep it running and nothing happened until the mState is set to CAPTURE.
It's set to capture when we click on the shutter button. When I click on the button, I call:
private void takePicture(){
try {
mFile = ImageSaver.generateNewFileImage();
mState = STATE_CAPTURE;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
mBackgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG,"Camera exception",e);
}
}
I call then CapturePicture as mState is in Capture as defined in the mCaptureCallback
private void capturePicture() {
mTakePictureRunnable = new Runnable() {
#Override
public void run() {
takePictureNow();
}
};
mBackgroundHandler.post(mTakePictureRunnable);
}
the takePicutreNow is defined
private void takePictureNow() {
Log.d(TAG, "Running captureStillPicture");
try {
if (null == mCameraDevice) {
return;
}
// This is the CaptureRequest.Builder that we use to take a picture.
final CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Log.d(TAG, "here is the width of texture" + mPreviewSize.getWidth());
Log.d(TAG, "here is the height of texture" + mPreviewSize.getHeight());
Surface surface = new Surface(texture);
captureBuilder.addTarget(surface);
// Orientation
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
//Location if needed
boolean Location_Saved = CameraSettings.Instance().getBoolean(CameraSettings.SAVE_LOCATION,
getResources().getBoolean(R.bool.action_camera_settings_dflt_location));
if(Location_Saved == true) {
captureBuilder.set(CaptureRequest.JPEG_GPS_LOCATION, mLocationManager.getCurrentLocation());
} else {
captureBuilder.set(CaptureRequest.JPEG_GPS_LOCATION, null);
}
CameraCaptureSession.CaptureCallback CaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureStarted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull long timestamp,
#NonNull long framenumber) {
playShutterSound();
showShutterAnimation();
}
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session,
#NonNull CaptureRequest request,
#NonNull TotalCaptureResult result) {
Log.d(TAG, mFile.toString());
mState = STATE_PREVIEW;
}
};
mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
mCaptureSession.stopRepeating();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
This process is working but I got a lag between the press and the imagesave and the latest pic I saw on the screen from the preview is not exactly the same saved if I move quickly.
It seems that the capture do not update the surface and the surface only show when we were in Preview
Any idea to see what I save ?
Thanks
The surface will freeze when you take an image, that might not be the image that gets saved. If you still want to show camera preview on the screen, you just have to restart the camera preview by calling the function you used to create preview at the first time.

android Camera2 Hit timeout for jpeg callback

I am creating an app on android 5.0.2 using new camera API(camera2). The app is to take a picture every 2.5 sec for 3 hours(4320 pictures in total). As you can see in the code below I coded repeating stuff with "timer" and no preview referring to Capture picture without preview using camera2 API. I am using NEXUS7 2013 16G 5.0.2 for the test. It works fine for the beginning 200-300 pictures and failed with the following error message. The fail always starts with "E/RequestThread-1﹕ Hit timeout for jpeg callback!", it must trigger something. Would anyone help to get rid of this trigger? Or this is going to fixed in 5.1.0 if it is android bug??
03-30 15:46:04.472 11432-11432/com.example.android.camera2basic V/yo click﹕ ---- 174 ---- click
03-30 15:46:05.026 11432-11537/com.example.android.camera2basic E/RequestThread-1﹕ Hit timeout for jpeg callback!
03-30 15:46:05.027 11432-11537/com.example.android.camera2basic W/CaptureCollector﹕ Jpeg buffers dropped for request: 173
03-30 15:46:05.076 11432-11480/com.example.android.camera2basic E/CameraDevice-JV-1﹕ Lost output buffer reported for frame 173
03-30 15:46:05.090 11432-11537/com.example.android.camera2basic W/LegacyRequestMapper﹕ convertRequestMetadata - control.awbRegions setting is not supported, ignoring value
03-30 15:46:05.090 11432-11537/com.example.android.camera2basic W/LegacyRequestMapper﹕ Only received metering rectangles with weight 0.
03-30 15:46:05.091 11432-11537/com.example.android.camera2basic W/LegacyMetadataMapper﹕ convertAfModeToLegacy - ignoring unsupported mode 4, defaulting to fixed
03-30 15:46:05.091 11432-11537/com.example.android.camera2basic W/LegacyRequestMapper﹕ convertRequestToMetadata - Ignoring android.lens.focusDistance false, only 0.0f is supported
03-30 15:46:05.098 11432-11537/com.example.android.camera2basic E/AndroidRuntime﹕ FATAL EXCEPTION: RequestThread-1
Process: com.example.android.camera2basic, PID: 11432
java.lang.RuntimeException: startPreview failed
at android.hardware.Camera.startPreview(Native Method)
at android.hardware.camera2.legacy.RequestThreadManager.startPreview(RequestThreadManager.java:275)
at android.hardware.camera2.legacy.RequestThreadManager.doJpegCapturePrepare(RequestThreadManager.java:288)
at android.hardware.camera2.legacy.RequestThreadManager.access$1700(RequestThreadManager.java:61)
at android.hardware.camera2.legacy.RequestThreadManager$5.handleMessage(RequestThreadManager.java:767)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
Here is my code::
public class CameraActivity extends Activity {
Timer mTimer = null;
Handler mHandler = new Handler();
private ImageReader imageReader;
private Handler backgroundHandler;
private HandlerThread backgroundThread;
private String cameraId;
private CameraDevice cameraDevice;
private CameraCaptureSession cameraCaptureSession;
static int count = 0;
static int count2 = 0;
/**
* Conversion from screen rotation to JPEG orientation.
*/
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
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);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_camera);
setContentView(R.layout.activity_main);
Button takePicture = (Button)findViewById(R.id.takepic);
takePicture.setOnClickListener(onClickPicture);
//(1) setting up camera but stop before camera createCaptureRequest
setupCamera2();
}
private void setupCamera2() {
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
//if (characteristics.get(CameraCharacteristics.LENS_FACING) != CameraCharacteristics.LENS_FACING_BACK) {
if (characteristics.get(CameraCharacteristics.LENS_FACING) != CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
StreamConfigurationMap configs = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
this.cameraId = cameraId;
manager.openCamera(this.cameraId, cameraStateCallback, backgroundHandler);
Size[] sizes = configs.getOutputSizes(ImageFormat.JPEG);
int picWidth = 640;//1920;
int picHeight = 480;//1080;
imageReader = ImageReader.newInstance(picWidth, picHeight, ImageFormat.JPEG, 2);
imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);
}
} catch (CameraAccessException | NullPointerException e) {
e.printStackTrace();
}
}
private final CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice device) {
cameraDevice = device;
//(2) Camera capture session
createCameraCaptureSession();
}
#Override
public void onDisconnected(CameraDevice cameraDevice) {}
#Override
public void onError(CameraDevice cameraDevice, int error) {}
};
//private void createCaptureSession() {
private void createCameraCaptureSession() {
List<Surface> outputSurfaces = new LinkedList<>();
outputSurfaces.add(imageReader.getSurface());
Log.v("-yo(2)-", "in createcameraCaptureSession now");
try {
cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
//cameraCaptureSession = session;
cameraCaptureSession = session;
//commented out to invoked from button
//createCaptureRequest();
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
//createCaptureRequest();
Log.v("yo ireader ","---- "+(count2++)+" ---- ireader");
//Image mImage = imageReader.acquireLatestImage();
Image mImage = reader.acquireLatestImage();
File mFile = new File(Environment.getExternalStorageDirectory() + "/yP2PTEST/0P2Pimage.jpg");
Log.v("--yo--", "In ImageReader now writing to "+mFile);
/////////////////////////////////////
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 (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ImageView curPic = (ImageView)findViewById(R.id.imageView1);
Bitmap mCurrentBitmap = BitmapFactory.decodeFile(mFile.getPath());
curPic.setImageBitmap(mCurrentBitmap);
}
///////////////////////////////////
};
private void createCaptureRequest() {
Log.v("-yo(3)-", "in createCaptureRequest now");
try {
CaptureRequest.Builder requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
requestBuilder.addTarget(imageReader.getSurface());
// Focus
requestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// Orientation
//yo int rotation = windowManager.getDefaultDisplay().getRotation();
int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
requestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
// cameraCaptureSession.capture(requestBuilder.build(), camera2Callback, null);
cameraCaptureSession.capture(requestBuilder.build(), mCaptureCallback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
CameraCaptureSession.CaptureCallback mCaptureCallback
= new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
TotalCaptureResult result) {
//showToast("JPEG Saved : ");
//Log.v("yo save","- saved JPEG -");
//unlockFocus();
}
};
private Handler mMessageHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (this != null) {
Toast.makeText(CameraActivity.this, (String) msg.obj, Toast.LENGTH_SHORT).show();
}
}
};
private void showToast(String text) {
// We show a Toast by sending request message to mMessageHandler. This makes sure that the
// Toast is shown on the UI thread.
Message message = Message.obtain();
message.obj = text;
mMessageHandler.sendMessage(message);
}
//------------------------------------------------------------//
public View.OnClickListener onClickPicture = new View.OnClickListener() {
public void onClick(View v) {
/*------- camera2 --------------*/
mTimer = null;
mTimer = new Timer(true);
mTimer.schedule( new TimerTask(){
#Override
public void run() {
/*------------------------*/
mHandler.post( new Runnable() {
public void run() {
createCaptureRequest();
Log.v("yo click ","---- "+(count++)+" ---- click");
}
});
}
}, 1000, 2500);//1500,1600, 1800 etc
};
};
};
Thanks in advance.
EDIT
I looked into source program of CAMERA2 API and found where the error message comes.
JPEG_FRAME_TIMEOUT is currently 300ms, I guess it is so small and want to increase it. If anyone know how to do it, please let me know?
if (holder.hasJpegTargets()) {
doJpegCapture(holder);
if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
Log.e(TAG, "Hit timeout for jpeg callback!");
mCaptureCollector.failNextJpeg();
}
}
I've had same issue with modified google sample.
After taking two pictures I got this error, so you just need to extend last parameter as much as you need, and it will work.
imageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),ImageFormat.JPEG, 2);
But keep in mind this:
#param maxImages The maximum number of images the user will want to access simultaneously. This should be as small as possible to limit memory use. Once maxImages Images are obtained by the user, one of them has to be released before a new Image will become available for access through {#link #acquireLatestImage()} or {#link #acquireNextImage()}. Must be greater than 0.

Categories

Resources