Ⅰ 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();
}
}
}
}