私はAndroid 1.5アプリケーションを起動直後に起動します。これはService
であり、プレビューなしで写真を撮る必要があります。このアプリは、私は写真を撮ることができましたが、写真は黒でした。
長い間研究した後、私はそれについてバグスレッドに出会いました。プレビューを生成しない場合、Androidカメラは露出と焦点を設定するためにプレビューが必要です。SurfaceView
とリスナーを作成しましたが、 onSurfaceCreated()
イベントは発生しません。
その理由は、表面が視覚的に作成されていないためだと思います。また、_MediaStore.CAPTURE_OR_SOMETHING
_を使用して静的にカメラを呼び出す例をいくつか見てきました。これは写真を撮り、2行のコードで目的のフォルダーに保存しますが、写真も撮りません。
この関数を呼び出すためにIPCおよびbindService()
_を使用する必要がありますか?または、これを実現する代替方法はありますか?
Androidプラットフォームは、有効なプレビューサーフェスが与えられるまでビデオをストリーミングできません。プラットフォームの設計者は、サードパーティのビデオストリーミングアプリケーションについてまったく考えていなかったようです。拡張現実の場合でも、リアルタイムのカメラストリームではなく、何らかの視覚的な代替として画像を表示できます。
とにかく、単純にプレビューサーフェスのサイズを1x1ピクセルに変更にして、ウィジェット(視覚要素)の隅のどこかに置くことができます。注意してください-カメラのフレームサイズではなく、プレビュー面のサイズを変更してください。
もちろん、このようなトリックは、システムリソースとバッテリーを消費する不要なデータストリーミング(プレビュー用)を排除しません。
Android Camera Docs でこれに対する答えを見つけました。
注:最初にカメラプレビューを作成せずに
MediaRecorder
を使用し、このプロセスの最初の数ステップをスキップすることが可能です。ただし、ユーザーは通常、記録を開始する前にプレビューを表示することを好むため、このプロセスについてはここでは説明しません。
上記のリンクで手順を追って説明しています。指示の後、それは私が上で提供した引用を述べます。
実際には可能ですが、ダミーのSurfaceViewでプレビューを偽造する必要があります
SurfaceView view = new SurfaceView(this);
c.setPreviewDisplay(view.getHolder());
c.startPreview();
c.takePicture(shutterCallback, rawPictureCallback, jpegPictureCallback);
pdate 9/21/11:どうやらこれはすべてのAndroidデバイスに対して機能しません。
プレビューを非表示にする前に、最初にこれを機能させてください。
SurfaceView
(Android-4.0以前の互換性)またはSurfaceTexture
(Android 4以降、透明にすることができます)を使用しますSurfaceView
のSurfaceHolder
が(getHolder()
を介して)surfaceCreated()
を報告するのを待つか、TextureView
がonSurfaceTextureAvailable
を報告するのを待ちますSurfaceTextureListener
プレビューを設定および初期化する前。WindowManager
に追加しますMATCH_PARENT
x MATCH_PARENT
にすることから始めることをお勧めします)View.VISIBLE
であることを確認します(指定しない場合はデフォルトのようです)LayoutParams
の場合は、TextureView
でFLAG_HARDWARE_ACCELERATED
を使用するようにしてください。takePicture
のJPEGコールバックを使用しますsurfaceCreated
/onSurfaceTextureAvailable
が呼び出されない場合、SurfaceView
/TextureView
はおそらく表示されていません。takePicture
が失敗した場合、最初にプレビューが正しく機能していることを確認してください。 takePicture
呼び出しを削除し、プレビューを実行して、画面に表示されるかどうかを確認できます。takePicture
を呼び出す前に約1秒間遅延して、プレビューが開始されたらカメラが露出を調整できるようにする必要があります。プレビューをView
1x1サイズにして、可視性を最小限に抑えます( または、信頼性を高めるために8x16を試してください )
new WindowManager.LayoutParams(1, 1, /*...*/)
プレビューを中央から移動して、目立たないようにします。
new WindowManager.LayoutParams(width, height,
Integer.MIN_VALUE, Integer.MIN_VALUE, /*...*/)
プレビューを透明にします(TextureView
でのみ機能します)
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
width, height, /*...*/
PixelFormat.TRANSPARENT);
params.alpha = 0;
/** 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; }
}
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!
}
}
また、プレビューデータを処理するコールバッククラスを実装する必要があります。
public class CamCallback implements Camera.PreviewCallback{
public void onPreviewFrame(byte[] data, Camera camera){
// Process the camera data here
}
}
上記の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);
これを行う方法はありますが、ややトリッキーです。行うべきことは、サービスからウィンドウマネージャーに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);
そして、設定
surfaceview.setZOrderOnTop(true);
mHolder.setFormat(PixelFormat.TRANSPARENT);
ここで、mHolderは表面ビューから取得するホルダーです。
このようにして、Surfaceviewのアルファを完全に透明にすることができますが、カメラはまだフレームを取得します。
それは私がそれをする方法です。それが役に立てば幸い :)
3.0より前のバージョンでダミーのSurfaceView(実際のGUIに追加されていない)を使用することでこの問題を解決しました(または、タブレットのカメラサービスとしての4.0は実際には意味がありません)。 4.0以降のバージョンでは、これはエミュレーターでのみ機能しました;(SurfaceView(およびsetSurfaceView())の代わりにSurfaceTexture(およびsetSurfaceTexture())の使用はここで機能しました。少なくともこれはNexus Sで機能します。
これはAndroidフレームワークの欠点だと思います。
「Samによる実例」(Thank you Sam ...)
istructionで「wm.addView(preview、params);」の場合
例外「ウィンドウAndroid.view.ViewRootを追加できません-このウィンドウタイプの許可は拒否されました」を取得
androidManifestでこの権限を使用して解決します。
<uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW"/>
この作業コードを試すことができます。このサービスは、フロントカメラの画像をクリックします。バックカメラの画像をキャプチャし、コードでbackCameraのコメントを解除し、frontCameraをコメントします。
注:-アクティビティまたは任意の場所からApp And startServiceにカメラとストレージのアクセス許可を許可します。
public class MyService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
CapturePhoto();
}
private void CapturePhoto() {
Log.d("kkkk","Preparing to take photo");
Camera camera = null;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
int frontCamera = 1;
//int backCamera=0;
Camera.getCameraInfo(frontCamera, cameraInfo);
try {
camera = Camera.open(frontCamera);
} catch (RuntimeException e) {
Log.d("kkkk","Camera not available: " + 1);
camera = null;
//e.printStackTrace();
}
try {
if (null == camera) {
Log.d("kkkk","Could not get camera instance");
} else {
Log.d("kkkk","Got the camera, creating the dummy surface texture");
try {
camera.setPreviewTexture(new SurfaceTexture(0));
camera.startPreview();
} catch (Exception e) {
Log.d("kkkk","Could not set the surface preview texture");
e.printStackTrace();
}
camera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFileDir=new File("/sdcard/CaptureByService");
if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
pictureFileDir.mkdirs();
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
String date = dateFormat.format(new Date());
String photoFile = "ServiceClickedPic_" + "_" + date + ".jpg";
String filename = pictureFileDir.getPath() + File.separator + photoFile;
File mainPicture = new File(filename);
try {
FileOutputStream fos = new FileOutputStream(mainPicture);
fos.write(data);
fos.close();
Log.d("kkkk","image saved");
} catch (Exception error) {
Log.d("kkkk","Image could not be saved");
}
camera.release();
}
});
}
} catch (Exception e) {
camera.release();
}
}
}