/** * galaxy inc. * meetup client for android */ package com.galaxy.meetup.client.android.hangout; import java.io.IOException; import java.util.Iterator; import java.util.List; import android.content.Context; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.view.SurfaceHolder; import android.view.TextureView; import android.view.WindowManager; import com.galaxy.meetup.client.util.Property; /** * * @author sihai * */ public class VideoCapturer implements android.view.SurfaceHolder.Callback { static final boolean $assertionsDisabled; private volatile Camera camera; private Cameras.CameraProperties cameraProperties; private Cameras.CameraType cameraType; private final Context context; private volatile int deviceRotation; private boolean flashLightEnabled; private volatile int frameRotationBeforeDisplaying; private volatile int frameRotationBeforeSending; private final SurfaceHolder holder; private final Host host; protected volatile boolean isCapturing; protected boolean isSurfaceReady; private final GCommNativeWrapper nativeWrapper; private volatile int previewFrameHeight; private volatile int previewFrameWidth; protected boolean startCapturingWhenSurfaceReady; private boolean supportsFlashLight; protected SurfaceTexture surfaceTexture; private final WindowManager windowManager; static { boolean flag; if(!VideoCapturer.class.desiredAssertionStatus()) flag = true; else flag = false; $assertionsDisabled = flag; } public VideoCapturer(Context context1, GCommNativeWrapper gcommnativewrapper, SurfaceHolder surfaceholder, Host host1) { context = context1; nativeWrapper = gcommnativewrapper; holder = surfaceholder; holder.setType(3); holder.addCallback(this); host = host1; windowManager = (WindowManager)context1.getSystemService("window"); deviceRotation = -1; } protected VideoCapturer(Context context1, GCommNativeWrapper gcommnativewrapper, Host host1) { context = context1; nativeWrapper = gcommnativewrapper; holder = null; host = host1; windowManager = (WindowManager)context1.getSystemService("window"); deviceRotation = -1; } private void configureCamera() { try { Log.debug("*** configureCamera"); if(!isSurfaceReady || surfaceTexture == null) { if(holder == null) { Log.error("No surface for camera preview."); } else { camera.setPreviewDisplay(holder); } } else { camera.setPreviewTexture(surfaceTexture); } } catch (IOException e) { Log.error("setPreviewDisplay failed. Ignoring, but video capture is disabled"); camera.release(); camera = null; return; } android.hardware.Camera.Size size; int i; int j; android.hardware.Camera.Parameters parameters = camera.getParameters(); size = getBestMatchPreviewSize(cameraProperties, parameters); parameters.setPreviewFormat(17); parameters.setPreviewSize(size.width, size.height); Object aobj[] = new Object[2]; aobj[0] = Integer.valueOf(size.width); aobj[1] = Integer.valueOf(size.height); Log.info("Setting camera preview size to %d x %d", aobj); supportsFlashLight = false; List list = parameters.getSupportedFlashModes(); if(list != null) supportsFlashLight = list.contains("torch"); Log.info((new StringBuilder("Camera flash light in torch mode supports: ")).append(supportsFlashLight).toString()); if(supportsFlashLight && flashLightEnabled) { parameters.setFlashMode("torch"); Log.debug("Turning on flash light in torch mode"); } camera.setParameters(parameters); long l = ImageFormat.getBitsPerPixel(17); long l1 = l * (long)(size.width * size.height); i = (int)((7L + l1) / 8L); Object aobj1[] = new Object[3]; aobj1[0] = Long.valueOf(l); aobj1[1] = Long.valueOf(l1); aobj1[2] = Integer.valueOf(i); Log.info("BitsPerPixel: %d BitsPerFrame: %d BufferSize: %d", aobj1); camera.setPreviewCallbackWithBuffer(null); for(j = 0; j < 5; j++) { camera.addCallbackBuffer(new byte[i + 1024]); } camera.setPreviewCallbackWithBuffer(new android.hardware.Camera.PreviewCallback() { public final void onPreviewFrame(byte abyte0[], Camera camera1) { synchronized(VideoCapturer.this) { if(isCapturing) { if(VideoCapturer.access$000(VideoCapturer.this)) { camera1.stopPreview(); configureCamera(); camera1.startPreview(); } nativeWrapper.provideOutgoingVideoFrame(abyte0, System.nanoTime(), frameRotationBeforeSending); camera.addCallbackBuffer(abyte0); } } } }); int k = 0; deviceRotation = windowManager.getDefaultDisplay().getRotation(); if(0 == deviceRotation) { k = 0; } else if(1 == deviceRotation) { k = 90; } else if(2 == deviceRotation) { k = 180; } else if(3 == deviceRotation) { k = 270; } else { throw new IllegalArgumentException("Invalid value of deviceOrientation"); } Object aobj2[]; Object aobj3[]; int j1; int k1; boolean flag; int i1 = Compatibility.getCameraOrientation(cameraProperties); if(cameraProperties.isFrontFacing()) { if(!Property.HANGOUT_CAMERA_MIRRORED.get().toUpperCase().equals("FALSE")) flag = true; else flag = false; if(flag) frameRotationBeforeSending = (360 - (k + i1) % 360) % 360; else frameRotationBeforeSending = (i1 + k) % 360; frameRotationBeforeDisplaying = (360 - (k + i1) % 360) % 360; } else { frameRotationBeforeSending = (360 + (i1 - k)) % 360; frameRotationBeforeDisplaying = (360 + (i1 - k)) % 360; } aobj2 = new Object[2]; aobj2[0] = Integer.valueOf(k); aobj2[1] = Integer.valueOf(i1); Log.info("Device orientation is %d; camera orientation is %d", aobj2); aobj3 = new Object[2]; aobj3[0] = Integer.valueOf(frameRotationBeforeDisplaying); aobj3[1] = Integer.valueOf(frameRotationBeforeSending); Log.info("frameRotationBeforeDisplaying is %d; frameRotationBeforeSending is %d", aobj3); camera.setDisplayOrientation(frameRotationBeforeDisplaying); j1 = previewFrameWidth; k1 = previewFrameHeight; if(0 == frameRotationBeforeDisplaying || 180 == frameRotationBeforeDisplaying) { previewFrameWidth = size.width; previewFrameHeight = size.height; } else if(90 == frameRotationBeforeDisplaying || 270 ==frameRotationBeforeDisplaying) { previewFrameWidth = size.height; previewFrameHeight = size.width; } else { // TODO } if(previewFrameWidth != j1 || previewFrameHeight != k1) GCommApp.sendObjectMessage(context, 204, new RectangleDimensions(previewFrameWidth, previewFrameHeight)); } private static android.hardware.Camera.Size getBestMatchPreviewSize(Cameras.CameraProperties cameraproperties, android.hardware.Camera.Parameters parameters) { List list = Compatibility.getSupportedPreviewSizes(parameters, cameraproperties); android.hardware.Camera.Size size = null; if(list != null) { Iterator iterator = list.iterator(); do { if(!iterator.hasNext()) break; android.hardware.Camera.Size size1 = (android.hardware.Camera.Size)iterator.next(); long l = getMisMatchArea(size1); Object aobj[] = new Object[4]; aobj[0] = Integer.valueOf(size1.width); aobj[1] = Integer.valueOf(size1.height); int i; if(parameters != null) i = parameters.getPreviewFrameRate(); else i = 0; aobj[2] = Integer.valueOf(i); aobj[3] = Long.valueOf(l); Log.info("Supported camera preview size: %d x %d x %d. mismatch area=%d", aobj); if(size == null) size = size1; else if(l < getMisMatchArea(size)) size = size1; } while(true); } return size; } private static long getMisMatchArea(android.hardware.Camera.Size size) { long l; if(size.width <= 480 && size.height <= 360) l = (long)(480 - size.width) * (long)size.height + 480L * (long)(360 - size.height); else if(size.width > 480 && size.height > 360) l = 360L * (long)(-480 + size.width) + (long)(-360 + size.height) * (long)size.width; else if(size.width > 480) { if(!$assertionsDisabled && size.height > 360) throw new AssertionError(); l = (long)(-480 + size.width) * (long)size.height + 480L * (long)(360 - size.height); } else { if(!$assertionsDisabled && (size.width > 480 || size.height <= 360)) throw new AssertionError(); l = 360L * (long)(480 - size.width) + (long)(-360 + size.height) * (long)size.width; } return l; } public static android.hardware.Camera.Size getSizeOfCapturedFrames(Cameras.CameraType cameratype) { try { Cameras.CameraResult cameraresult = Cameras.open(cameratype); android.hardware.Camera.Size size; Camera camera1 = cameraresult.getCamera(); size = getBestMatchPreviewSize(cameraresult.getProperties(), camera1.getParameters()); if(size != null) { Object aobj[] = new Object[2]; aobj[0] = Integer.valueOf(size.width); aobj[1] = Integer.valueOf(size.height); Log.info("Size of captured frames %d x %d", aobj); } camera1.release(); return size; } catch (RuntimeException runtimeexception) { Log.error((new StringBuilder("Error opening camera: ")).append(runtimeexception).toString()); return null; } } public final boolean flashLightEnabled() { return flashLightEnabled; } public final boolean isCapturing() { return isCapturing; } public final void start(Cameras.CameraType cameratype) { cameraType = cameratype; startCapturingWhenSurfaceReady = true; if(isSurfaceReady) startCapturing(); } protected final synchronized boolean startCapturing() { if(isCapturing) { return true; } try { Cameras.CameraResult cameraresult = Cameras.open(cameraType); camera = cameraresult.getCamera(); cameraProperties = cameraresult.getProperties(); configureCamera(); camera.startPreview(); isCapturing = true; Host host2 = host; host2.onCapturingStateChanged(); return true; } catch (RuntimeException runtimeexception) { if(camera != null) { camera.release(); camera = null; } isCapturing = false; Host host1 = host; host1.onCapturingStateChanged(); host.onCameraOpenError(runtimeexception); return false; } } public final void stop() { stopCapturing(); startCapturingWhenSurfaceReady = false; } protected final synchronized void stopCapturing() { Log.debug("*** stopCapturing"); if(isCapturing) { camera.stopPreview(); camera.release(); camera = null; isCapturing = false; Host host1 = host; host1.onCapturingStateChanged(); previewFrameWidth = 0; previewFrameHeight = 0; } } public final boolean supportsFlashLight() { return supportsFlashLight; } public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) { isSurfaceReady = true; if(startCapturingWhenSurfaceReady && !isCapturing) startCapturing(); } public void surfaceCreated(SurfaceHolder surfaceholder) { } public void surfaceDestroyed(SurfaceHolder surfaceholder) { isSurfaceReady = false; stopCapturing(); } public final void toggleFlashLightEnabled() { if(supportsFlashLight) { boolean flag; android.hardware.Camera.Parameters parameters; if(!flashLightEnabled) flag = true; else flag = false; flashLightEnabled = flag; parameters = camera.getParameters(); if(flashLightEnabled) { parameters.setFlashMode("torch"); Log.debug("Turning on flash light in torch mode"); } else { parameters.setFlashMode("off"); Log.debug("Turning off flash light in torch mode"); } camera.setParameters(parameters); } } static boolean access$000(VideoCapturer videocapturer) { boolean flag; if(videocapturer.windowManager.getDefaultDisplay().getRotation() != videocapturer.deviceRotation) flag = true; else flag = false; return flag; } //=================================================================================== // Inner class //=================================================================================== static interface Host { public abstract void onCameraOpenError(RuntimeException runtimeexception); public abstract void onCapturingStateChanged(); } public static final class TextureViewVideoCapturer extends VideoCapturer implements android.view.TextureView.SurfaceTextureListener { public final void onSurfaceTextureAvailable(SurfaceTexture surfacetexture, int i, int j) { surfaceTexture = surfacetexture; isSurfaceReady = true; if(startCapturingWhenSurfaceReady && !isCapturing) startCapturing(); } public final boolean onSurfaceTextureDestroyed(SurfaceTexture surfacetexture) { isSurfaceReady = false; stopCapturing(); surfaceTexture = null; return true; } public final void onSurfaceTextureSizeChanged(SurfaceTexture surfacetexture, int i, int j) { } public final void onSurfaceTextureUpdated(SurfaceTexture surfacetexture) { } protected final TextureView textureView; public TextureViewVideoCapturer(Context context1, GCommNativeWrapper gcommnativewrapper, TextureView textureview, Host host1) { super(context1, gcommnativewrapper, host1); textureView = textureview; textureView.setSurfaceTextureListener(this); } } }