Not called surfaceCreated when add camera object in surface in new runOnUiThread - android

Sorry for my english. I have activity1, and activity2. In activity1 i have button, when i click this button this button freezes for a few seconds and after this open activity2. To remove a freeze when click button in activity1 I added code that launches the camera in new runOnUiThread but now not called surfaceCreated.
mPreview - my custom surfaceView
mCamera - object camera
My code:
new Thread(new Runnable() {
#Override
public void run() {
CameraActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mPreview.addCamera(mCamera);
mPreview.addParent(CameraActivity.this);
mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mPreview.refreshDrawableState();
mCamera.startPreview();
}
});
}
}).start();
My costom SurfaceView ( i add only important code)
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
public CameraPreview (Context context){
super(context);
}
public CameraPreview(Context context, AttributeSet attrs){
super(context, attrs);
}
public CameraPreview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void addCamera(Camera camera){
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
try {
if(mCamera!=null){
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
} catch (Exception e){
Toast.makeText(this.getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//code
mCamera.startPreview();
}
}

That's the expected behaviour, the Surface is maintained by the SurfaceView, as a workaround you could check if the surface is valid and has non-0 dimentions and call your surfaceCreated/surfaceChangedfunctions manually
the code you need:
Surface surface = mHolder.getSurface();
if(surface != null && surface.isValid()){
Rect frame = mHolder.getSurfaceFrame();
if(frame.width() > 0 && frame.height() > 0){
surfaceCreated(mHolder);
surfaceChaged(mHolder, PixelFormat.OPAQUE, frame.width(), frame.height()); //pixel format OPAQUE is the default one
}
}

Related

The application may be doing too much work on its main thread is catched when I try set surfaceview in center of FrameLayout

I have an activity which creates my custom SurfaceView for camera previewing in center of FrameLayout. In xml I have a FrameLayout with button and ImageView. When I click on button, I want ImageView shows over SurfaceView in center of FrameLayout. So when I run application I catch warning:
Skipped XX frames! The application may be doing too much work on its main thread
Here is my XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.rcd.perfecto.ui.CameraActivity">
<FrameLayout
android:id="#+id/fl_camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/iv_avatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ic_launcher"/>
<Button
android:id="#+id/btn_photo_capture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/btn_photo_capture"
android:layout_gravity="center_horizontal|bottom"/>
</FrameLayout>
</LinearLayout>
Here is my custom SurfaceView
public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
private Path mClipPath;
private Camera mCamera;
private WeakReference<FrameLayout> mFrameLayoutWeakReference;
private Context mContext;
private SurfaceHolder mHolder;
public CameraView(Context context) {
super(context);
init(context);
}
public CameraView(Context context, Camera camera, FrameLayout layout) {
super(context);
mCamera = camera;
mFrameLayoutWeakReference = new WeakReference<FrameLayout>(layout);
mHolder = getHolder();
mHolder.addCallback(this);
init(context);
}
public CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CameraView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
mContext = context;
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
float radius;
FrameLayout layout = mFrameLayoutWeakReference.get();
if (display.getRotation() == Surface.ROTATION_0 || display.getRotation() == Surface.ROTATION_180) {
radius = layout.getWidth() / 2;
} else {
radius = layout.getHeight() / 2;
}
mClipPath = new Path();
mClipPath.addCircle(layout.getWidth() / 2, layout.getHeight() / 2, radius, Path.Direction.CW);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.clipPath(mClipPath);
super.dispatchDraw(canvas);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null) {
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
}
Camera.Parameters parameters = mCamera.getParameters();
Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
parameters.setPreviewSize(height, width);
mCamera.setDisplayOrientation(90);
}
if (display.getRotation() == Surface.ROTATION_90) {
parameters.setPreviewSize(width, height);
}
if (display.getRotation() == Surface.ROTATION_180) {
parameters.setPreviewSize(height, width);
}
if (display.getRotation() == Surface.ROTATION_270) {
parameters.setPreviewSize(width, height);
mCamera.setDisplayOrientation(180);
}
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
And my activity:
public class CameraActivity extends AppCompatActivity {
#Bind(R.id.btn_photo_capture) Button mPhotoCaptureButton;
#Bind(R.id.fl_camera_preview) FrameLayout mCameraPreviewFrameLayout;
#Bind(R.id.iv_avatar) CircleImageView mAvatarImageView;
private Camera mCamera;
private CameraView mCameraView;
public CameraActivity() {
}
#OnClick(R.id.btn_photo_capture)
void takePicture() {
if (mAvatarImageView.getVisibility() == View.VISIBLE) {
mAvatarImageView.setVisibility(View.GONE);
} else {
mAvatarImageView.setVisibility(View.VISIBLE);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
ButterKnife.bind(this);
if (checkCameraHardware()) {
if (Camera.getNumberOfCameras() > 1) {
mCamera = getCameraInstance(Camera.CameraInfo.CAMERA_FACING_FRONT);
} else mCamera = getCameraInstance();
}
ViewTreeObserver observer = mCameraPreviewFrameLayout.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mCameraView = new CameraView(CameraActivity.this, mCamera, mCameraPreviewFrameLayout);
mCameraPreviewFrameLayout.addView(mCameraView, 0);
}
});
}
private static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
e.printStackTrace();
}
return c;
}
private static Camera getCameraInstance(int id) {
Camera c = null;
try {
c = Camera.open(id);
} catch (Exception e) {
e.printStackTrace();
}
return c;
}
private boolean checkCameraHardware() {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
}
So my question is how can I avoid warning above or is there another way to set surfaceview in center of FrameLayout programmatically?

Android SurfaceView IllegalArgumentException lockCanvas

I'm working on a video into a SurfaceView.
My goal is to get recurrent bitmaps of the running video.
Here is my Custom implementation:
private static final String TAG = "XXX";
private Activity activity;
private SurfaceHolder mSurface;
private MediaPlayer mMediaPlayer;
private SurfaceHolder mActiveSurface;
public ImageView imageView;
boolean locked, locked1;
private boolean isCreated;
public AlphaSurfaceView(Context context,Activity activity) {
super(context);
getHolder().addCallback(this);
setWillNotDraw(false);
this.activity = activity;
}
public AlphaSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AlphaSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
}
#Override
public void onDraw(Canvas canvas) {
//super.onDraw(canvas);
if(isCreated){
if(getHolder() != null && getHolder().getSurface().isValid()){
Canvas c = null;
try {
if(!locked){
try {
c = getHolder().lockCanvas();
locked = true;
}catch (IllegalArgumentException e){
e.printStackTrace();
locked = false;
}
BitmapDrawable bdrawable = new BitmapDrawable();
bdrawable.draw(c);
}
}catch (Exception e){
e.printStackTrace();
locked = false;
}finally {
if(c != null && locked){
getHolder().unlockCanvasAndPost(c);
locked = false;
}
}
}
}else{
super.onDraw(canvas);
}
invalidate();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mSurface = holder;
mMediaPlayer = MediaPlayer.create(getContext(), Uri.parse("XX"), mSurface);
mActiveSurface = mSurface;
try {
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mMediaPlayer.start();
mMediaPlayer.setLooping(true);
}
});
} catch (Exception e) {
e.printStackTrace();
}
this.isCreated = true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "surfacechanged");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mMediaPlayer.stop();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mMediaPlayer.stop();
}
The problem is an IllegalArgumentException occured by the lockCanvas() method.
I tried many possibilities as:
Adding some boolean (locked & creation of surfaceview)
Test if surface is valid
even add exported="true" in targeted activity in Manifest's xml
By the way the first idea was to use getDrawingCache() but even i added setCacheEnabled(true), the return was null.
So how to resolve this Exception or using another way to get each frame?
Thanks!
You can't draw on a Surface and send a video to it. A Surface is the producer end of a producer-consumer pair, and you can only have one producer at a time.
The easiest way to have a Canvas overlap a SurfaceView Surface is to draw on the View part of the SurfaceView. Send the video to the Surface, and use onDraw() (like a custom view) to draw on the View.
Bear in mind that the Surface is a separate layer that sits behind the View UI layer, so you will need to draw on the View with transparency to see the Surface contents.
Another approach is to use multiple overlapping SurfaceViews, but this is less efficient and more limited. An example with three overlapping Surfaces can be found in Grafika's multi-surface test Activity.
surfaceHolder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
Log.e("video","surfaceChanged");
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
Log.e("video","surfaceCreated");
mediaPlayer.setDisplay(surfaceHolder);
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.e("video","surfaceDestroyed");
if (mediaPlayer != null) mediaPlayer.release();
}
});
That should help.
Let the MediaPlayer do the drawing thing.

unable to focus on small text in android

I am making an app for reading small text but i am not able to get sharp focus . i am using SCENE_MODE_BARCODE for scene mode for small text but it seems to be not working i tried autofocus also but no result either.
sorry for bad english.
my preview class code is
public class MyView extends SurfaceView implements SurfaceHolder.Callback {
Camera surfacecmr;
SurfaceHolder mholder;
#SuppressWarnings("deprecation")
public MyView(Context context, Camera cmr) {
super(context);
surfacecmr = cmr;
mholder = getHolder();
mholder.addCallback(this);
mholder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
// surfacecmr.setDisplayOrientation(90);
surfacecmr.setPreviewDisplay(holder);
surfacecmr.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
if (mholder.getSurface() == null)
return;
surfacecmr.stopPreview();
// get Camera parameters
Camera.Parameters params = surfacecmr.getParameters();
params.setSceneMode(Camera.Parameters.SCENE_MODE_BARCODE);
surfacecmr.setParameters(params);
try {
surfacecmr.setPreviewDisplay(mholder);
} catch (IOException e) {
e.printStackTrace();
}
surfacecmr.startPreview();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
surfacecmr.release();
}
}

onPreviewFrame not being called for every frame that is displayed on SurfaceView

My subclass of SurfaceView implements Camera.PreviewCallback & SurfaceHolder.Callback.
private SurfaceHolder mHolder;
private Camera mCamera;
private final FPSCounter fpscounter = new FPSCounter();
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
fpscounter.logFrame();
Log.d("fps", String.valueOf(fpscounter.getLastFrameCount()));
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
synchronized (this) {
mCamera.stopPreview();
Camera.Parameters parameters = mCamera.getParameters();
parameters.setRecordingHint(true);
parameters.setPreviewFormat(ImageFormat.NV21);
mCamera.setParameters(parameters);
try {
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(this);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
synchronized (this) {
setWillNotDraw(false);
mCamera = Camera.open();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
synchronized (this) {
try {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
} catch (Exception e) {
Log.e("cam error", e.getMessage());
}
}
}
and the FPSCounter class
private long startTime;
private int frames, lastFrameCount;
public void logFrame() {
frames++;
if (System.nanoTime() - startTime >= 1000000000) {
lastFrameCount = frames;
frames = 0;
startTime = System.nanoTime();
}
}
public int getLastFrameCount() {
return lastFrameCount;
}
Even though the camera preview is extremely smooth, the onPreviewFrame() method is only called about 5 times a second. Why isn't it being called for every frame?
You probably figured it out already: Camera.setPreviewCallback() puts too much pressure on Garbage Collector. You can use Camera.setPreviewCallbackWithBuffer() instead.
Second, if onPreviewFrame() arrives on the main (UI) thread, then it competes for single CPU time with UI events like touch, layout, or even rendering. To keep onPreviewFrame() on a separate thread, you should open() the camera on a secondary Looper thread, see e.g. https://stackoverflow.com/a/19154438/192373.
Third, even in this case, the preview callbacks are serialized. If fpscounter.logFrame() and Log().d take X milliseconds, then the FPS will not exceed 1000/X.
It is called for every frame. You can refer to online reference of Camera. Look at this sentence "Installs a callback to be invoked for every preview frame in addition to displaying them on the screen."

Camera.open() is not available/accessible?

i'm trying to create cameraPreview, and I found in the below code "Camera.open()"
this method is not accessible or not available to me, there no such method the Object Camera
can have access to.
Is there any thing i should do, or it's amistake inthe tutorial?
Java Code:
#Override
public void surfaceCreated(SurfaceHolder holder)
{
try
{
//Open the Camera in preview mode
this.camera = Camera.open();
this.camera.setPreviewDisplay(this.holder);
}
catch(IOException ioe)
{
ioe.printStackTrace(System.out);
}
}
You most likely imported the wrong camera class at the top of your source file, which is android.graphics.Camera.
You need android.hardware.Camera instead.
Here is complete Camera view class ::
class Preview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "Preview";
SurfaceHolder mHolder;
public Camera camera;
Preview(Context context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
camera.setDisplayOrientation(90);
try {
camera.setPreviewDisplay(holder);
camera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d(TAG, "onPreviewFrame called at: "
+ System.currentTimeMillis());
Preview.this.invalidate();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
camera.release();
camera = null;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
camera.startPreview();
}
}

Categories

Resources