eyu*_*kul 57 android android-service android-camera
我正在编写一个Android 1.5应用程序,它在启动后启动.这是一个Service,应该拍照没有预览.此应用程序将记录某些区域的光密度.我能够拍照,但照片是黑色的.
经过长时间的研究,我遇到了一个关于它的bug线程.如果您不生成预览,则图像将为黑色,因为Android相机需要预览才能设置曝光和对焦.我创建了一个SurfaceView和听众,但onSurfaceCreated()事件永远不会被解雇.
我想原因是,表面没有在视觉上创造.我还看到了静态调用相机的一些例子,MediaStore.CAPTURE_OR_SOMETHING它们拍摄照片并用两行代码保存在所需的文件夹中,但它也没有拍照.
我是否需要使用IPC并bindService()调用此功能?或者是否有另一种方法来实现这一目标?
小智 50
Android平台上的摄像头在给出有效的预览表面之前无法流式传输视频真的很奇怪.似乎该平台的架构师根本没有考虑第三方视频流应用程序.即使对于增强现实案例,图片也可以呈现为某种视觉替代,而不是实时相机流.
无论如何,您只需将预览曲面的大小调整为1x1像素,并将其放在窗口小部件的角落(视觉元素).请注意 - 调整预览面大小,而不是相机框架尺寸.
当然,这种技巧并不能消除消耗一些系统资源和电池的不需要的数据流(用于预览).
Phi*_*ens 38
我在Android Camera Docs中找到了答案.
注意:可以先使用
MediaRecorder而不先创建相机预览,然后跳过此过程的前几个步骤.但是,由于用户通常更喜欢在开始录制之前看到预览,因此这里不讨论该过程.
您可以在上面的链接中找到分步说明.在说明之后,它将说明我在上面提供的报价.
Fra*_*ank 36
实际上它是可能的,但您必须使用虚拟SurfaceView伪造预览
SurfaceView view = new SurfaceView(this);
c.setPreviewDisplay(view.getHolder());
c.startPreview();
c.takePicture(shutterCallback, rawPictureCallback, jpegPictureCallback);
Run Code Online (Sandbox Code Playgroud)
更新9/21/11:显然这对每个Android设备都不起作用.
Sam*_*Sam 34
在尝试隐藏预览之前先使其工作.
SurfaceView(Android-4.0之前的兼容性)或SurfaceTexture(Android 4+,可以透明)SurfaceView的SurfaceHolder(通过getHolder())报告surfaceCreated()或TextureView报告onSurfaceTextureAvailable其SurfaceTextureListener 设置和初始化前预览.WindowManagerMATCH_PARENTx MATCH_PARENT进行测试)View.VISIBLE(如果您未指定它,这似乎是默认值)FLAG_HARDWARE_ACCELERATED的LayoutParams,如果这是一个TextureView.takePicture的是JPEG回调,因为文档说所有设备都不支持其他回调surfaceCreated/ onSurfaceTextureAvailable没有被调用时,SurfaceView/ TextureView可能不被显示.takePicture失败,请首先确保预览正常.您可以移除takePicture呼叫并让预览运行以查看它是否显示在屏幕上.takePicture以便在预览开始后相机有时间调整其曝光.预览View1x1尺寸以最小化其可见性(或尝试8x16以获得更高的可靠性)
new WindowManager.LayoutParams(1, 1, /*...*/)
Run Code Online (Sandbox Code Playgroud)将预览移出中心以降低其醒目性:
new WindowManager.LayoutParams(width, height,
Integer.MIN_VALUE, Integer.MIN_VALUE, /*...*/)
Run Code Online (Sandbox Code Playgroud)使预览透明(仅适用于TextureView)
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
width, height, /*...*/
PixelFormat.TRANSPARENT);
params.alpha = 0;
Run Code Online (Sandbox Code Playgroud)/** Takes a single photo on service start. */
public class PhotoTakingService extends Service {
@Override
public void onCreate() {
super.onCreate();
takePhoto(this);
}
@SuppressWarnings("deprecation")
private static void takePhoto(final Context context) {
final SurfaceView preview = new SurfaceView(context);
SurfaceHolder holder = preview.getHolder();
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new Callback() {
@Override
//The preview must happen at or after this point or takePicture fails
public void surfaceCreated(SurfaceHolder holder) {
showMessage("Surface created");
Camera camera = null;
try {
camera = Camera.open();
showMessage("Opened camera");
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
throw new RuntimeException(e);
}
camera.startPreview();
showMessage("Started preview");
camera.takePicture(null, null, new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
showMessage("Took picture");
camera.release();
}
});
} catch (Exception e) {
if (camera != null)
camera.release();
throw new RuntimeException(e);
}
}
@Override public void surfaceDestroyed(SurfaceHolder holder) {}
@Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
});
WindowManager wm = (WindowManager)context
.getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
1, 1, //Must be at least 1x1
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
0,
//Don't know if this is a safe default
PixelFormat.UNKNOWN);
//Don't set the preview visibility to GONE or INVISIBLE
wm.addView(preview, params);
}
private static void showMessage(String message) {
Log.i("Camera", message);
}
@Override public IBinder onBind(Intent intent) { return null; }
}
Run Code Online (Sandbox Code Playgroud)
小智 21
在Android 4.0及更高版本(API级别> = 14),您可以使用TextureView预览相机流并使其不可见,以便不向用户显示.这是如何做:
首先创建一个类来实现SurfaceTextureListener,它将获得预览表面的创建/更新回调.该类还将摄像机对象作为输入,以便在创建曲面后立即调用摄像机的startPreview函数:
public class CamPreview extends TextureView implements SurfaceTextureListener {
private Camera mCamera;
public CamPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
setLayoutParams(new FrameLayout.LayoutParams(
previewSize.width, previewSize.height, Gravity.CENTER));
try{
mCamera.setPreviewTexture(surface);
} catch (IOException t) {}
mCamera.startPreview();
this.setVisibility(INVISIBLE); // Make the surface invisible as soon as it is created
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Put code here to handle texture size change if you want to
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Update your view here!
}
}
Run Code Online (Sandbox Code Playgroud)
您还需要实现一个回调类来处理预览数据:
public class CamCallback implements Camera.PreviewCallback{
public void onPreviewFrame(byte[] data, Camera camera){
// Process the camera data here
}
}
Run Code Online (Sandbox Code Playgroud)
使用上面的CamPreview和CamCallback类在活动的onCreate()或类似的启动函数中设置相机:
// Setup the camera and the preview object
Camera mCamera = Camera.open(0);
CamPreview camPreview = new CamPreview(Context,mCamera);
camPreview.setSurfaceTextureListener(camPreview);
// Connect the preview object to a FrameLayout in your UI
// You'll have to create a FrameLayout object in your UI to place this preview in
FrameLayout preview = (FrameLayout) findViewById(R.id.cameraView);
preview.addView(camPreview);
// Attach a callback for preview
CamCallback camCallback = new CamCallback();
mCamera.setPreviewCallback(camCallback);
Run Code Online (Sandbox Code Playgroud)
Vla*_*lad 20
有一种方法可以做到这一点,但它有点棘手.应该做什么,是从服务附加一个Surfaceholder到窗口管理器
WindowManager wm = (WindowManager) mCtx.getSystemService(Context.WINDOW_SERVICE);
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
wm.addView(surfaceview, params);
Run Code Online (Sandbox Code Playgroud)
然后设置
surfaceview.setZOrderOnTop(true);
mHolder.setFormat(PixelFormat.TRANSPARENT);
Run Code Online (Sandbox Code Playgroud)
其中mHolder是您从表面视图获得的持有者.
这样,您可以使用surfaceview的alpha,使其完全透明,但相机仍然会获得帧.
这就是我的表现.希望能帮助到你 :)
mnl*_*mnl 13
我们通过在3.0以下版本中使用虚拟SurfaceView(未添加到实际GUI)解决了这个问题(或者说4.0作为平板电脑上的摄像头服务并不真正有意义).在版本> = 4.0中,这只在模拟器中工作;(使用SurfaceTexture(和setSurfaceTexture())而不是SurfaceView(和setSurfaceView())在这里工作.至少这适用于Nexus S.
我认为这确实是Android框架的一个缺点.
| 归档时间: |
|
| 查看次数: |
72955 次 |
| 最近记录: |