Ⅰ android 中實現網頁調用攝像頭功能怎麼實現
android 中實現網頁調用攝像頭功能方法·如下: 1/apk/res/android" xmlns:tools="schemas/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".CameraWebviewActivity" > <Button android:id="@+id/bt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Camera" android:layout_alignParentTop="true" /> <WebView android:id="@+id/wv" android:layout_width="fill_parent" android:layout_height="match_parent" android:layout_below="@+id/bt" /> </RelativeLayout> 4.、編寫activity: public class CameraWebviewActivity extends Activity { private final static String TAG = "CameraWebviewActivity"; private Button bt; private WebView wv; public String fileFullName;//照相後的照片的全整路徑 private boolean fromTakePhoto; //是否是從攝像界面返回的webview @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera_webview); initViews(); } private void initViews() { bt = (Button) findViewById(R.id.bt); bt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { System.out.println("----------------"); takePhoto( Math.random()*1000+1 + ".jpg"); } }); wv = (WebView) findViewById(R.id.wv); WebSettings setting = wv.getSettings(); setting.setjavaScriptEnabled(true); wv.setWebViewClient(new WebViewClient(){ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return super.shouldOverrideUrlLoading(view, url); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); } }); wv.setWebChromeClient(new WebChromeClient(){ @Override//實現js中的alert彈窗在Activity中顯示 public boolean onJsAlert(WebView view, String url, String message, JsResult result) { Log.d(TAG, message); result.confirm(); return true; } }); wv.loadUrl("file:///android_asset/index.html"); final Handler mHandler = new Handler(); //webview增加javascript介面,監聽html頁面中的js點擊事件 wv.addJavascriptInterface(new Object(){ public String clickOnAndroid() {//將被js調用 mHandler.post(new Runnable() { public void run() { fromTakePhoto = true; //調用 啟用攝像頭的自定義方法 takePhoto("testimg" + Math.random()*1000+1 + ".jpg"); System.out.println("========fileFullName: " + fileFullName); } }); return fileFullName; } }, "demo"); } /* * 調用攝像頭的方法 */ public void takePhoto(String filename) { System.out.println("----start to take photo2 ----"); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_MEDIA_TITLE, "TakePhoto"); //判斷是否有SD卡 String sdDir = null; boolean isSDcardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); if(isSDcardExist) { sdDir = Environment.getExternalStorageDirectory().getAbsolutePath(); } else { sdDir = Environment.getRootDirectory().getAbsolutePath(); } //確定相片保存路徑 String targetDir = sdDir + "/" + "webview_camera"; File file = new File(targetDir); if (!file.exists()) { file.mkdirs(); } fileFullName = targetDir + "/" + filename; System.out.println("----taking photo fileFullName: " + fileFullName); //初始化並調用攝像頭 intent.putExtra(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(fileFullName))); startActivityForResult(intent, 1); } /* * (non-Javadoc) * @see android.app.Activity#onActivityResult(int, int, android.content.Intent) * 重寫些方法,判斷是否從攝像Activity返回的webview activity */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { System.out.println("----requestCode: " + requestCode + "; resultCode " + resultCode + "; fileFullName: " + fileFullName); if (fromTakePhoto && requestCode ==1 && resultCode ==-1) { wv.loadUrl("javascript:wave2('" + fileFullName + "')"); } else { wv.loadUrl("javascript:wave2('Please take your photo')"); } fromTakePhoto = false; super.onActivityResult(requestCode, resultCode, data); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.camera_webview, menu); return true; } }
Ⅱ android camera如何判斷當前使用的攝像頭是前置還是後置
現在 android 平台的智能手機一般都標配有兩顆攝像頭。在 Camera 中都存在攝像頭切換的功能。
並且有一些功能前後置攝像頭上會有所不同。譬如人臉檢測,人臉識別,自動對焦,閃光燈等功能,
如果前置攝像頭的像素太低,不支持該功能的話,就需要在前置攝像頭上關掉該 feature.
那麼是如何判斷並切換前後置攝像頭的呢?
我們先來看下 CameraInfo 這個類,
[java] view plain
/**
* Information about a camera
*/
public static class CameraInfo {
/**
* The facing of the camera is opposite to that of the screen.
*/
public static final int CAMERA_FACING_BACK = 0;
/**
* The facing of the camera is the same as that of the screen.
*/
public static final int CAMERA_FACING_FRONT = 1;
/**
* The direction that the camera faces. It should be
* CAMERA_FACING_BACK or CAMERA_FACING_FRONT.
*/
public int facing;
/**
* <p>The orientation of the camera image. The value is the angle that the
* camera image needs to be rotated clockwise so it shows correctly on
* the display in its natural orientation. It should be 0, 90, 180, or 270.</p>
*
* <p>For example, suppose a device has a naturally tall screen. The
* back-facing camera sensor is mounted in landscape. You are looking at
* the screen. If the top side of the camera sensor is aligned with the
* right edge of the screen in natural orientation, the value should be
* 90. If the top side of a front-facing camera sensor is aligned with
* the right of the screen, the value should be 270.</p>
*
* @see #setDisplayOrientation(int)
* @see Parameters#setRotation(int)
* @see Parameters#setPreviewSize(int, int)
* @see Parameters#setPictureSize(int, int)
* @see Parameters#setJpegThumbnailSize(int, int)
*/
public int orientation;
};
見名知義,它就是一個 Camera 信息類。它是通過與屏幕的方向是否一致來定義前後置攝像頭的。
與屏幕方向相反即為 BACK_FACING_CAMERA
與屏幕方向一致即為 FRONT_FACING_CAMERA
那麼在代碼中我們是如何獲取當前使用的 CamerInfo 呢
[java] view plain
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
當然,使用該代碼的前提是要 import android.hardware.Camera.CameraInfo;
判斷使用是前置還是後置攝像頭,可以通過if (info.facing == CameraInfo.CAMERA_FACING_FRONT) 來判斷。
當Camera 的實例已經創建了的情況下,則需要通過如下方式來判斷。
[java] view plain
CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
//stopFaceDetection();
}
也可以通過 if(mCameraId == CameraInfo.CAMERA_FACING_FRONT) 來判斷。
其中 mCameraId 是當前使用的 CameraId, 一般前置為1, 後置為 0。
Ⅲ android app 如何與uvc攝像頭通訊
來看看是怎麼操作UVC攝像頭的吧.我們實現了一個專門檢測UVC攝像頭的服務:UVCCameraService類,主要代碼如下:
監聽
mUSBMonitor = new USBMonitor(this, new USBMonitor.OnDeviceConnectListener() { @Override
public void onAttach(final UsbDevice device) {
Log.v(TAG, "onAttach:" + device);
mUSBMonitor.requestPermission(device);
} @Override
public void onConnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock, final boolean createNew) {
releaseCamera(); if (BuildConfig.DEBUG) Log.v(TAG, "onConnect:"); try { final UVCCamera camera = new MyUVCCamera();
camera.open(ctrlBlock);
camera.setStatusCallback(new IStatusCallback() { // ... uvc 攝像頭鏈接成功
Toast.makeText(UVCCameraService.this, "UVCCamera connected!", Toast.LENGTH_SHORT).show(); if (device != null)
cameras.append(device.getDeviceId(), camera);
}catch (Exception ex){
ex.printStackTrace();
}
} @Override
public void onDisconnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) { // ... uvc 攝像頭斷開鏈接
if (device != null) {
UVCCamera camera = cameras.get(device.getDeviceId()); if (mUVCCamera == camera) {
mUVCCamera = null;
Toast.makeText(UVCCameraService.this, "UVCCamera disconnected!", Toast.LENGTH_SHORT).show();
liveData.postValue(null);
}
cameras.remove(device.getDeviceId());
}else {
Toast.makeText(UVCCameraService.this, "UVCCamera disconnected!", Toast.LENGTH_SHORT).show();
mUVCCamera = null;
liveData.postValue(null);
}
} @Override
public void onCancel(UsbDevice usbDevice) {
releaseCamera();
} @Override
public void onDettach(final UsbDevice device) {
Log.v(TAG, "onDettach:");
releaseCamera();// AppContext.getInstance().bus.post(new UVCCameraDisconnect());
}
});
這個類主要實現UVC攝像頭的監聽\鏈接\銷毀\反監聽.當有UVC攝像頭鏈接成功後,會創建一個mUVCCamera對象.
然後在MediaStream里, 我們改造了switchCamera,當參數傳2時,表示要切換到UVCCamera(0,1分別表示切換到後置\前置攝像頭).
創建
在創建攝像頭時,如果是要創建uvc攝像頭,那直接從服務裡面獲取之前創建的mUVCCamera實例:
if (mCameraId == 2) {
UVCCamera value = UVCCameraService.liveData.getValue(); if (value != null) { // uvc camera.
uvcCamera = value;
value.setPreviewSize(width, height,1, 30, UVCCamera.PIXEL_FORMAT_YUV420SP,1.0f); return; // value.startPreview();
}else{
Log.i(TAG, "NO UVCCamera");
uvcError = new Exception("no uvccamera connected!"); return;
} // mCameraId = 0;
}123456789101112131415
預覽
在預覽時,如果uvc攝像頭已經創建了,那執行uvc攝像頭的預覽操作:
UVCCamera value = uvcCamera;if (value != null) {
SurfaceTexture holder = mSurfaceHolderRef.get(); if (holder != null) {
value.setPreviewTexture(holder);
} try {
value.setFrameCallback(uvcFrameCallback, UVCCamera.PIXEL_FORMAT_YUV420SP/*UVCCamera.PIXEL_FORMAT_NV21*/);
value.startPreview();
cameraPreviewResolution.postValue(new int[]{width, height});
}catch (Throwable e){
uvcError = e;
}
}1234567891011121314
這里我們選的colorFormat為PIXEL_FORMAT_YUV420SP 相當於標准攝像頭的NV21格式.
關閉預覽
同理,關閉時,調用的是uvc攝像頭的關閉.
UVCCamera value = uvcCamera; if (value != null) {
value.stopPreview();
}1234
銷毀
因為我們這里並沒有實質性的創建,所以銷毀時也僅將實例置為null就可以了.
UVCCamera value = uvcCamera;if (value != null) { // value.destroy();
uvcCamera = null;
}12345
有了這些操作,我們看看上層怎麼調用,
首先需要在Manifest裡面增加若干代碼,具體詳見UVCCamera工程說明.如下:
<activity android:name=".UVCActivity" android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
然後,的代碼在UVCActivity里,這個類可以在library分支的myapplication工程里找到.即這里.
啟動或者停止UVC攝像頭推送:
public void onPush(View view) { // 非同步獲取到MediaStream對象.
getMediaStream().subscribe(new Consumer<MediaStream>() { @Override
public void accept(final MediaStream mediaStream) throws Exception { // 判斷當前的推送狀態.
MediaStream.PushingState state = mediaStream.getPushingState(); if (state != null && state.state > 0) { // 當前正在推送,那終止推送和預覽
mediaStream.stopStream();
mediaStream.closeCameraPreview();
}else{ // switch 0表示後置,1表示前置,2表示UVC攝像頭
// 非同步開啟UVC攝像頭
RxHelper.single(mediaStream.switchCamera(2), null).subscribe(new Consumer<Object>() { @Override
public void accept(Object o) throws Exception { // 開啟成功,進行推送.
// ...
mediaStream.startStream("cloud.easydarwin.org", "554", id);
}
}, new Consumer<Throwable>() { @Override
public void accept(final Throwable t) throws Exception { // ooop...開啟失敗,提示下...
t.printStackTrace();
runOnUiThread(new Runnable() { @Override
public void run() {
Toast.makeText(UVCActivity.this, "UVC攝像頭啟動失敗.." + t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
});
}
}
});
}
這樣,整個推送就完成了.如果一切順利,應當能在VLC播放出來UVC攝像頭的視頻了~~
我們再看看如何錄像.也非常簡單…
public void onRecord(View view) { // 開始或結束錄像.
final TextView txt = (TextView) view;
getMediaStream().subscribe(new Consumer<MediaStream>() { @Override
public void accept(MediaStream mediaStream) throws Exception { if (mediaStream.isRecording()){ // 如果正在錄像,那停止.
mediaStream.stopRecord();
txt.setText("錄像");
}else { // 沒在錄像,開始錄像...
// 表示最大錄像時長為30秒,30秒後如果沒有停止,會生成一個新文件.依次類推...
// 文件格式為test_uvc_0.mp4,test_uvc_1.mp4,test_uvc_2.mp4,test_uvc_3.mp4
String path = getExternalFilesDir(Environment.DIRECTORY_MOVIES) + "/test_uvc.mp4";
mediaStream.startRecord(path, 30000); final TextView pushingStateText = findViewById(R.id.pushing_state);
pushingStateText.append("\n錄像地址:" + path);
txt.setText("停止");
}
}
});
}21
UVC攝像頭還支持後台推送,即不預覽的情況下進行推送,同時再切換到前台繼續預覽.只需要調用一個介面即可實現,如下:
@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
ms.setSurfaceTexture(surfaceTexture); // 設置預覽的surfaceTexture}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
ms.setSurfaceTexture(null); // 設置預覽窗口為null,表示關閉預覽功能
return true;
}123456789
如果要徹底退出uvc攝像頭的預覽\推送,那隻需要同時退出服務即可.
public void onQuit(View view) { // 退出
finish(); // 終止服務...
Intent intent = new Intent(this, MediaStream.class);
stopService(intent);
}1234567
## 獲取更多信息 ##
Ⅳ Android開發 如何打開前置攝像頭的代碼
找到surficeView
surfaceView = (SurfaceView)findViewById(R.id.surfaceview);
設置它的像素為800x600
surfaceView.getHolder().setFixedSize(800,480);
//下面設置surfaceView不維護自己的緩沖區,而是等待屏幕的渲染引擎將內容推送到用戶面前
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
然後就是回調
surfaceView.getHolder().addCallback(newSurfaceCallback());
上面的回調類是我們自己定義的,代碼如下
private class SurfaceCallback implementsSurfaceHolder.Callback{
@Override
public void surfaceCreated(SurfaceHolderholder) {
try {
camera = Camera.open();//打開硬體攝像頭,這里導包得時候一定要注意是android.hardware.Camera
WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);//得到窗口管理器
Display display = wm.getDefaultDisplay();//得到當前屏幕
Camera.Parameters parameters =camera.getParameters();//得到攝像頭的參數
parameters.setPreviewSize(display.getWidth(),display.getHeight());//設置預覽照片的大小
parameters.setPreviewFrameRate(3);//設置每秒3幀
parameters.setPictureFormat(PixelFormat.JPEG);//設置照片的格式
parameters.setJpegQuality(85);//設置照片的質量
parameters.setPictureSize(display.getHeight(),display.getWidth());//設置照片的大小,默認是和屏幕一樣大
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceView.getHolder());//通過SurfaceView顯示取景畫面
camera.startPreview();//開始預覽
isPreview = true;//設置是否預覽參數為真
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
@Override
public void surfaceChanged(SurfaceHolderholder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceDestroyed(SurfaceHolderholder) {
if(camera!=null){
if(isPreview){//如果正在預覽
camera.stopPreview();
camera.release();
}
}
}
}