Im creating a custom ViewGroup using annotations lib.
I want to load the camera in a SurfaceView that is in my ViewGroup. The problem is that when i put my ViewGroup inside my Layout, the camera is not loaded (SurfaceHolder.Callbacks are not called).
Is there a way to put a Camera in my custom View?
My code works fine in an Activity, but in my View its not showing camera.
Thats my code:
#EViewGroup(R.layout.activity_custom_camera)
public class TakePictureView extends RelativeLayout implements SurfaceHolder.Callback {
Context context;
Activity activity;
boolean previewing = false;
Camera camera;
#ViewById(R.id.camerapreview)
SurfaceView surfaceView;
#ViewById(R.id.button_take_picture)
ImageView takepicture;
SurfaceHolder surfaceHolder;
LayoutInflater controlInflater = null;
Camera.PictureCallback jpegCallback;
public TakePictureView(Context context, Activity activity) {
super(context);
this.context = context;
this.activity = activity;
}
public TakePictureView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public void bind(){
activity.getWindow().setFormat(PixelFormat.UNKNOWN);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (surfaceHolder != null){
camera.autoFocus(new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
}
});
}
}
});
jpegCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d("Log", "onPictureTaken - wrote bytes: " + data.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
Toast.makeText(activity, "Picture Saved", Toast.LENGTH_SHORT).show();
}
};
takepicture.setClickable(true);
takepicture.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
takePicture();
}
});
}
void takePicture(){
camera.autoFocus(new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
camera.takePicture(null, null, jpegCallback);
}
});
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d("CAMERA", "CRIADA");
camera = Camera.open();
Log.d("CAMERA", "CRIADA" + camera.getParameters().toString());
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d("CAMERA", "SURFACE CHANGED");
if(previewing){
camera.stopPreview();
previewing = false;
}
if (camera != null){
try {
Camera.Parameters parameters = camera.getParameters();
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
parameters.set("orientation", "portrait");
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
camera.setDisplayOrientation(90);
parameters.setRotation(90);
}
else {
// This is an undocumented although widely known feature
parameters.set("orientation", "landscape");
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// For Android 2.2 and above
camera.setDisplayOrientation(0);
// Uncomment for Android 2.0 and above
parameters.setRotation(0);
}
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
previewing = true;
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
}
}
Hi Instead of extends the view group you should have to extends the SurfaceView & Use the custom class inside your activity and layout. see the below code, It will sure help you.
Packager com.test.cam;
public class AdvancePreview extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mSurfaceHolder;
public Camera mCamera;
public Activity mActivity;
public AdvancePreview(Context context) {
super(context);
}
public AdvancePreview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setUpSurface(Activity activity){
try
{
mActivity = activity;
this.mSurfaceHolder = getHolder();
this.mSurfaceHolder.setFormat(PixelFormat.JPEG);
this.mSurfaceHolder.addCallback(this);
this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
catch(Exceptions e){
e.printStackTrace();
}
}
private SurfaceHolder getSurfaceHolder(){
return this.mSurfaceHolder;
}
// SurfaceHolder.Callback
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.print(this.getClass().toString(), "surfaceCreated()");
try {
mCamera = Camera.open();
mCamera.setPreviewDisplay(getSurfaceHolder());
} catch (Exception e) {
e.printStackTrace();
}
}
// SurfaceHolder.Callback
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Parameters params = null;
Log.print(this.getClass().toString(), "surfaceChanged()");
try {
if (camera != null) {
params = mCamera.getParameters();
params.setPictureFormat(PixelFormat.JPEG);
mCamera.setParameters(params);
mCamera.startPreview();
}
} catch (Exception e) {
e.printStackTrace();
}
}
// SurfaceHolder.Callback
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
try {
mCamera.stopPreview();
mCamera.release();
} catch (Exception e) {
e.printStackTrace();
}
mCamera = null;
}
public void startTakePicture() {
Parameters params = null;
AudioManager mgr = null;
Log.debug(this.getClass().toString(), "startTakePictre()");
try {
mgr = (AudioManager)Const.CONTEXT.getSystemService(Context.AUDIO_SERVICE);
mgr.setStreamMute(AudioManager.STREAM_SYSTEM, true);
if (mCamera != null){
params = mCamera.getParameters();
params.setPictureFormat(PixelFormat.JPEG);
mCamera.setParameters(params);
mCamera.autoFocus(new CustomAutoFoucsCallback(activity));
}else{
activity.finish();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
In next step how to use this AdvancePreview class in your activity, see the below code with activity and it layout xml file.
Packager com.test.cam;
public class CamActivity extends Activity {
public AdvancePreview mAdvancePreview;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cam_activity);
mAdvancePreview = (AdvancePreview)findViewById(R.id.advancepreview);
mAdvancePreview.setUpSurface(this);
}
// class this function on click event of button
public void takePicture(){
mAdvancePreview.startTakePicture();
}
}
cam_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<com.test.cam.AdvancePreview
android:id="#+id/advancepreview"
android:layout_width="1dp"
android:layout_height="1dp"
/>
</LinearLayout>
For save the captured photo save use the CustomAutoFocusCallback see the below line from AdvancePreview
camera.autoFocus(new CustomAutoFoucsCallback(activity));
Let me know if you any question or query. Thank you
Related
What I am having: I am having a surface view where i am capturing a image
What I am trying to do:
Once i captured the image I want to show a like a flash effect
indicating image is captured and a sound that camera gives
How to achieve this
public class FrgCamera extends Fragment implements SurfaceHolder.Callback {
private Unbinder unbinder;
private String mFileUriCreated;
#BindView(R.id.surfaceview) SurfaceView surfaceview;
private SurfaceHolder surfaceHolder;
private Camera camera;
private boolean previewing = false;
private Camera.PictureCallback jpegCallback;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return init(inflater, container);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initOnActivityCreated();
}
#Override
public void onDestroyView() {
super.onDestroyView();
stopTheCamera(camera);
unbinder.unbind();
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
initSurfaceView();
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
refreshCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
stopTheCamera(camera);
}
#OnClick(R.id.surfaceview)
public void stopcamerapreview(View view) {
camera.takePicture(null, null, jpegCallback);
}
/**
* INIT OnCreateView
*/
private View init(LayoutInflater inflater, ViewGroup container) {
View rootView = inflater.inflate(R.layout.frg_camera, container, false);
ButterKnife.bind(this, rootView);
unbinder = ButterKnife.bind(this, rootView);
return rootView;
}
/**
* INIT OnActivityCreated
*/
private void initOnActivityCreated() {
getActivity().getWindow().setFormat(PixelFormat.UNKNOWN);
surfaceHolder = surfaceview.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
jpegCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
try {
FileUtil imgDevice = new FileUtil(getActivity());
mFileUriCreated = imgDevice.createFile(data);
} catch (IOException e) {
Timber.d(e, e.getMessage());
}
refreshCamera();
}
};
}
/**
* Refresh Camera
*/
public void refreshCamera() {
if (surfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
camera.stopPreview();
} catch (Exception e) {
Timber.d(e, e.getMessage());
}
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
Timber.d(e, e.getMessage());
}
}
/**
* Initialize Surface view
*/
private void initSurfaceView() {
try {
// open the camera
camera = Camera.open();
camera.setParameters(setCameraParams());
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
Timber.d(e, e.getMessage());
return;
}
}
/**
* SET the camera params for the device
*/
private Camera.Parameters setCameraParams() {
Camera.Parameters param = camera.getParameters();
ImgParmUtil imgParams = new ImgParmUtil(param);
return imgParams.getImageParam();
}
/**
* STOP the camera
*/
private void stopTheCamera(Camera camera) {
if (camera != null && this.previewing) {
camera.stopPreview();
camera.release();
previewing = false;
}
}
}
How can Take picture from front camera in service without showing camera on screen.
I have service class
public class PhotoTakingService extends Service {
//Camera variables
//a surface holder
private SurfaceHolder sHolder;
//a variable to control the camera
private Camera mCamera;
//the camera parameters
private Parameters parameters;
boolean mPreviewRunning = false;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStart(Intent intent,int startId) {
// TODO Auto-generated method stub
super.onStart(intent,startId);
mCamera = Camera.open();
SurfaceView sv = new SurfaceView(getBaseContext());
try {
Camera.Parameters p = mCamera.getParameters();
mCamera.setParameters(p);
mCamera.startPreview();
mCamera.takePicture(null,null,mPictureCallback);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Get a surface
sHolder = sv.getHolder();
//tells Android that this surface will have its data constantly replaced
sHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData,Camera c) {
Log.e("Callback TAG","Here in jpeg Callback");
if (imageData != null) {
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream("/sdcard/car_final/Image.jpg");
outputStream.write(imageData);
// Removed the finish call you had here
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) try {
outputStream.close();
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
}
}
};
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
and main activity. I want to call from main activity.
public class MainActivity extends Activity implements SurfaceHolder.Callback {
private static final String TAG = MainActivity.class.getSimpleName();
public static SurfaceView mSurfaceView;
public static SurfaceHolder mSurfaceHolder;
public static Camera mCamera;
public static boolean mPreviewRunning;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
Button btnStart = (Button) findViewById(R.id.button1);
btnStart.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent(MainActivity.this, PhotoTakingService.class);
//intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startService(intent);
}
});
/* Button btnStop = (Button) findViewById(R.id.StopService);
btnStop.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
stopService(new Intent(CameraRecorder.this, RecorderService.class));
}
});*/
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
When you are in background thread such as service use SurfaceTexture instead of SurfaceHolder. If you are looking for implementation here is a opensource app where I have implemented background video stream and UI video stream both.
So I was following the android developers build a camera application sample and have my camera activity up and running. However when I go to another activity then hit the back button I am getting a crash because the camera is null in the surface view's on surface created. Can someone explain how this error is happening. Thanks!
** Activity
public class PhotoCaptureActivity extends AppCompatActivity implements View.OnClickListener{
public static final String TAG = "PhotoCaptureActivity";
CameraPreview mPreviewScreen;
Button mCaptureButton;
ImageView mPreviewThumbnail;
TextView mPhotoActionLabel;
TextView mImageLogText;
Camera mCamera;
Camera.PictureCallback mPicture;
ArrayList<Bitmap> mPictures = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo_capture);
getSupportActionBar().hide();
mCaptureButton = (Button) findViewById(R.id.button_capture);
mPreviewThumbnail = (ImageView) findViewById(R.id.thumb_nail_image);
mPhotoActionLabel = (TextView) findViewById(R.id.photo_action_text);
mImageLogText = (TextView) findViewById(R.id.image_log);
mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
BitmapFactory.Options scalingOptions = new BitmapFactory.Options();
scalingOptions.inSampleSize = camera.getParameters().getPictureSize().width / mPreviewThumbnail.getMeasuredWidth();
final Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length, scalingOptions);
mPictures.add(bmp);
mPreviewThumbnail.setImageBitmap(bmp);
mPreviewThumbnail.setVisibility(ImageView.VISIBLE);
mCamera.startPreview();
mPhotoActionLabel.setText(getString(R.string.done));
}
};
mCaptureButton.setOnClickListener(this);
mPhotoActionLabel.setOnClickListener(this);
mImageLogText.setOnClickListener(this);
}
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
e.printStackTrace();
}
return c; // returns null if camera is unavailable
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_capture:
mCamera.takePicture(null, null, mPicture);
break;
case R.id.photo_action_text:
if (mPhotoActionLabel.getText().toString().equalsIgnoreCase(getString(R.string.cancel)))
finish();
else {
Intent photoReviewIntent = new Intent(this,PhotoReviewActivity.class);
startActivity(photoReviewIntent);
}
break;
case R.id.image_log:
Intent imageLogIntent = new Intent(this,ImageLogActivity.class);
startActivity(imageLogIntent);
break;
}
}
#Override
public void onPause(){
super.onPause();
mCamera.stopPreview();
mCamera.release();
}
#Override
public void onResume(){
super.onResume();
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
mCamera = getCameraInstance();
if (mCamera != null){
mPreviewScreen = new CameraPreview(this,mCamera);
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.camera_preview);
frameLayout.addView(mPreviewScreen);
}
else
Toast.makeText(this, R.string.failed_to_open_camera, Toast.LENGTH_LONG).show();
}
else
Toast.makeText(this, R.string.no_camera_available, Toast.LENGTH_LONG).show();
}
}
** preview screen java class
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
this.mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
Log.i("Error starting camera", e.getLocalizedMessage());
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
}
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.i("Error starting camera", e.getLocalizedMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
//Handeled in activity
}
}
In onResume(), an old mPreviewScreen may still exist, and cause problems. Consider adding the following to onPause():
if (mPreviewScreen != null) {
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.camera_preview);
frameLayout.removeView(mPreviewScreen);
mPreviewScreen = null;
}
mCamera = null;
I come to you because my custom camera has a big problem : the image is stretched! I have rade that the problem from dimensions but i don't solved it.
If you want pictures to show the problem I will post it
This is my code :
public class CameraActivity extends Activity{
private SurfaceView surface_view;
private Camera mCamera;
SurfaceHolder.Callback sh_ob = null;
SurfaceHolder surface_holder = null;
SurfaceHolder.Callback sh_callback = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
surface_view = new SurfaceView(getApplicationContext());
addContentView(surface_view, new WindowManager.LayoutParams(WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.FILL_PARENT));
if (surface_holder == null) {
surface_holder = surface_view.getHolder();
}
sh_callback = my_callback();
surface_holder.addCallback(sh_callback);
}
SurfaceHolder.Callback my_callback() {
SurfaceHolder.Callback ob1 = new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mCamera.startPreview();
}
};
return ob1;
}
}
Thanks for your help :D
You cannot stretch the surface on full screen; you should set it according to camera aspect ratio. To cover all situations, you need more callbacks. See a nice wrapper class here: http://www.vogella.com/code/de.vogella.android.gallery/src/com/example/android/hcgallery/CameraFragment.html
I have searched some solutions with my problem and sure there are many related issues regarding it but nothing solves my concern.
I am receiving a runtime exception : takepicture failed:native_autofocus..etc.
I tried to take picture from camera using autofocus and I can't seem to understand what could have caused the error.
Here is my code.
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mholder;
private Camera mcamera;
private Handler handler = new Handler();
public CameraPreview(Context context, Camera camera) {
super(context);
this.mcamera = camera;
mholder = getHolder();
mholder.addCallback(this);
mholder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
if (mholder.getSurface() == null) {
return;
}
try {
mcamera.stopPreview();
} catch (Exception e) {
Log.d("surfaceChanged", e.toString());
}
try {
mcamera.setPreviewDisplay(holder);
mcamera.startPreview();
} catch (IOException e) {
Log.d("surfaceChanged--->surfaceCreated", e.toString());
}
}
I think somethings is lacking in my runnable code, I tried to omit the runnable and execute autofocus once, it removed the runtime error. Did I missed to reinitialize something in this part?
private void autoFocus(Camera mcamera){
final Camera cam=mcamera;
handler.postDelayed(new Runnable() {
#Override
public void run() {
cam.autoFocus(autoFocusCallback);
handler.postDelayed(this, 1500L);
}
}, 1500L);
}
AutoFocusCallback autoFocusCallback=new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
camera.takePicture(null, null, mPicture);
}
};
private PictureCallback mPicture=new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
//do something
}
};
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mcamera.setPreviewDisplay(holder);
mcamera.startPreview();
mcamera.autoFocus(autoFocusCallback);
} catch (IOException e) {
Log.d("surfaceCreated", e.toString());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
You didn't mention it but be sure to include the permission in your manifest.
< uses-feature android:name="android.hardware.camera.autofocus" />
Have a look here
or here
and you are calling autofocus on surfacecreated ,
It should be called on surface changed