Ответ 1
Я также заметил, что mCamera.takePicture(null, null, обработчик) замерзает. Я попытался очистить обработчик предварительного просмотра: mCamera.setPreviewCallback(null) перед вызовом takePicture(), и теперь он работает.
У меня есть некоторые коды для съемки, которые работают в Android 2.1 и 2.2. Но эти коды сломались на Android 2.3. Проведя время, чтобы исправить эту проблему, которая пропала даром, я хотел бы попросить о помощи здесь.
Мой поток кода для съемки выглядит следующим образом:
создать класс Camlayer расширяет SurfaceView
public class CamLayer extends SurfaceView implements SurfaceHolder.Callback {
private void init(Context context){
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mCamera = Camera.open();
}
public CamLayer(Context context) {
super(context);
init(context);
}
public CamLayer(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.i(TAG+".surfaceChanged", "being called!");
Log.i(TAG+".surfaceChanged", "w="+w);
Log.i(TAG+".surfaceChanged", "h="+h);
if (isPreviewRunning) {
mCamera.stopPreview();
}
try {
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(mPreviewCallback);
} catch (IOException e) {
Log.e(TAG+".surfaceCreated", "mCamera.setPreviewDisplay(holder);");
}
Camera.Parameters p = mCamera.getParameters();
setOptimalSize(p, w, h, SIZEOFPREVIEW);
setOptimalSize(p, w, h, SIZEOFPICTURE);
mCamera.setParameters(p);
mCamera.startPreview();
isPreviewRunning = true;
}
public void takePicture(){
Log.i(TAG+".takePicture", "being called!");
mCamera.takePicture(null, null, mPictureCallback);
Log.i(TAG+".takePicture", "call ended!");
}
}
CamLayer.takePicture()
будет вызван внешними классами для запуска.
Проблема заключается в том, что на Android 2.3.3, takePicture
будет зависать, поэтому проблема ANR найдена. В /data/anr/traces.txt
найдено ниже. Как вы можете видеть, native_takePicture
никогда не возвращается.
DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1 NATIVE
| group="main" sCount=1 dsCount=0 obj=0x40022170 self=0xce68
| sysTid=2411 nice=0 sched=0/0 cgrp=default handle=-1345006464
at android.hardware.Camera.native_takePicture(Native Method)
at android.hardware.Camera.takePicture(Camera.java:746)
at android.hardware.Camera.takePicture(Camera.java:710)
at oms.cj.tube.camera.CamLayer.takePicture(CamLayer.java:256)
at oms.cj.tube.camera.DefineColor.takePicture(DefineColor.java:61)
at oms.cj.tube.camera.DefineColor.onKeyUp(DefineColor.java:71)
at android.view.KeyEvent.dispatch(KeyEvent.java:1280)
at android.app.Activity.dispatchKeyEvent(Activity.java:2078)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:16
66)
at android.view.ViewRoot.deliverKeyEventToViewHierarchy(ViewRoot.java:2571)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2546)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Есть ли у кого-то одинаковые проблемы? И знаете, как это исправить?
Я также заметил, что mCamera.takePicture(null, null, обработчик) замерзает. Я попытался очистить обработчик предварительного просмотра: mCamera.setPreviewCallback(null) перед вызовом takePicture(), и теперь он работает.
У меня была такая же проблема сегодня, когда мы тестировали наше приложение на Samsung Exhibit 4G с Android 2.3.3 и решили его с помощью обходного пути.
Я больше не называю takepicture, но использую последний обратный вызов предварительного просмотра в качестве изображения.
Проблема заключается в том, что обратный вызов предварительного просмотра отправляет буфер данных с использованием формата NV21.
Итак, вам нужно преобразовать изображение, используя этот процесс: NV21 → RGB → Загрузка растрового изображения → Сжатие в JPEG
Наш код прямо сейчас выглядит следующим образом:
camera.setPreviewCallback(new PreviewCallback() {
@Override
public synchronized void onPreviewFrame(byte[] data, Camera arg1) {
if (!mTakePicture) {
CameraPreview.this.invalidate();
} else {
if (mTakePictureCallback != null && !mPictureTaken) {
int rgb[] = new int[previewSize.width*previewSize.height];
decodeYUV420SP(rgb, data, previewSize.width, previewSize.height);
Bitmap memoryImage = Bitmap.createBitmap(rgb, previewSize.width, previewSize.height, Bitmap.Config.ARGB_8888);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
memoryImage.compress(CompressFormat.JPEG, 100, baos);
shutterSound();
setBackgroundDrawable(new BitmapDrawable(getContext().getResources(), memoryImage));
mTakePictureCallback.onPictureTaken(baos.toByteArray(), arg1);
}
mPictureTaken = true;
camera.stopPreview();
}
}
});
Код decodeYUV420SP находится здесь http://www.41post.com/3470/programming/android-retrieving-the-camera-preview-as-a-pixel-array, который нашел его на Ketai http://code.google.com/p/ketai/
Когда вы делаете снимок, просто установите переменную mTakePicture в true
Я работаю над лучшей версией, но это должно заставить вас идти.
Я не уверен, какой метод setOptimalSize используется в вашем коде, но убедитесь, что вы установили параметр камеры
mCamera.setPictureSize(captureSize.width, captureSize.height);
mCamera.setPictureFormat(ImageFormat.JPEG);
Проблема заключается в том, что ниже коды записываются.
Определен PreviewCallback,
PreviewCallback mPreviewCallback = new PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
//Log.i(TAG+".mPreviewCallback.onPreviewFrame", "being called!");
}
};
mCamera.setPreviewCallback(mPreviewCallback);
Это работает в 2.1/2.2, но не в 2.3.
Не уверен, что Android-группа поддерживает этот способ использования камеры. Если ожидаемый поток ожидается, команда Android должна исправить эту проблему.
Я столкнулся с этой проблемой с телефонами GB, и для меня это оказалось потому, что я вызывал camera.startPreview() сразу после вызова camera.takePicture(), и это вызывало некоторую блокировку потока в Android. Исправление заключалось в том, чтобы переместить camera.startPreview() в обратный вызов, переданный в camera.takePicture(), так, чтобы он вызывался только после того, как были представлены данные изображения (пример кода ниже). Это, конечно, актуально только в том случае, если вы заинтересованы в перезапуске предварительного просмотра после того, как сделана фотография.
// BAD BAD DON'T DO THIS!
public void myTakePicture(Camera.PictureCallback callback) {
mCamera.takePicture(null, null, null, callback);
mCamera.startPreview();
}
// ...
// The way that worked for me
public void myTakePicture(final Camera.PictureCallback callback) {
mCamera.takePicture(null, null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] pictureData, Camera camera) {
callback.onPictureTaken(pictureData, camera);
mCamera.takePicture();
}
});
}
Это не только заставило ANR уйти при вызове takePicture, но и зафиксировал собственный сбой на startPreview, который происходил на некоторых телефонах с более высоким номером (в частности, >= 4.3 Nexus 5). Надеюсь, это поможет!