1

有人问过这个问题,但这里从未回答过——但无论如何,它与我的需要有些不同。

我想录制视频,同时在后台运行 Google Vision 库,所以每当我的用户举起条形码(或足够接近条形码)时,相机都会自动检测并扫描条形码 - 并且一直在记录视频。我知道 Google Vision 演示是相当 CPU 密集型的,但是当我尝试一个更简单的版本时(即没有一直抓取每一帧并将其交给检测器)我没有得到可靠的条形码读取。

(我在 KitKat 4.4.3 上运行三星 Galaxy S4 Mini 不幸的是,由于只有三星知道的原因,他们不再报告 OnCameraFocused 事件,因此无法知道相机是否抓住焦点并调用读取条形码。这使得抓取和检查每一帧似乎是唯一可行的解​​决方案。)

所以至少为了证明这个概念,我想简单地修改 Google Vision Demo。(在这里找到)

似乎最简单的事情就是简单地跳入代码并添加一个媒体记录器。我在表面创建期间在 CameraSourcePreview 方法中执行了此操作。

像这样:

private class SurfaceCallback implements SurfaceHolder.Callback
{
    @Override
    public void surfaceCreated(SurfaceHolder surface)
    {
        mSurfaceAvailable = true;
        try
        {
            startIfReady();
            if (mSurfaceAvailable)
            {
                Camera camera = mCameraSource.getCameraSourceCamera();
                /** ADD MediaRecorder to Google Example  **/
                if (camera != null && recordThis)
                {
                    if (mMediaRecorder == null)
                    {
                        mMediaRecorder = new MediaRecorder();
                        camera.unlock();
                        SurfaceHolder sh = mSurfaceView.getHolder();
                        mMediaRecorder.setPreviewDisplay(sh.getSurface());
                        mMediaRecorder.setCamera(camera);
                        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
                        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                        mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
                        String OutputFile = Environment.getExternalStorageDirectory() + "/" +
                                DateFormat.format("yyyy-MM-dd_kk-mm-ss", new Date().getTime()) + ".mp4";
                        File newOutPut = getVideoFile();
                        String newOutPutFileName = newOutPut.getPath();
                        mMediaRecorder.setOutputFile(newOutPutFileName);
                        Log.d("START MR", OutputFile);
                        try { mMediaRecorder.prepare(); } catch (Exception e) {}
                        mCameraSource.mediaRecorder = mMediaRecorder;
                        mMediaRecorder.start();
                    }
                }
            }
        }
        catch (SecurityException se)
        {
            Log.e(TAG, "Do not have permission to start the camera", se);
        }
        catch (IOException e)
        {
            Log.e(TAG, "Could not start camera source.", e);
        }
    }

这确实记录了事情,同时仍将每一帧交给视觉代码。但是,奇怪的是,当我这样做时,相机似乎没有正确调用自动对焦,并且没有扫描条形码——因为它们从未真正聚焦,因此无法识别。

我的下一个想法是在条形码检测器处理帧时简单地捕获帧,并将它们一个一个地保存到磁盘(我可以稍后将它们混合在一起。)

我在 CameraSource.java 中做到了这一点。

这似乎没有捕获所有帧,即使我将它们写在后台运行的单独 AsyncTask 中,我认为最终会得到它们——即使需要一段时间才能赶上。保存没有优化,但它看起来好像在整个丢帧,而不仅仅是在最后。

要添加此代码,我尝试将其放在 run() 方法中的私有类 FrameProcessingRunnable 中。

在 FrameBuilder 代码之后,我添加了以下内容:

            if (saveImagesIsEnabled)
            {
                if (data == null)
                {
                    Log.d(TAG, "data == NULL");
                }
                else
                {
                    SaveImageAsync saveImage = new SaveImageAsync(mCamera.getParameters().getPreviewSize() );
                    saveImage.execute(data.array());
                }
            }

哪个调用这个类:

Camera.Size lastKnownPreviewSize = null;
public class SaveImageAsync extends AsyncTask<byte[], Void, Void>
{
    Camera.Size previewSize;

    public SaveImageAsync(Camera.Size _previewSize)
    {
        previewSize = _previewSize;
        lastKnownPreviewSize = _previewSize;
    }
    @Override
    protected Void doInBackground(byte[]... dataArray)
    {
        try
        {
            if (previewSize == null)
            {
                if (lastKnownPreviewSize != null)
                    previewSize = lastKnownPreviewSize;
                else
                    return null;
            }
            byte[] bitmapData = dataArray[0];
            if (bitmapData == null)
            {
                Log.d("doInBackground","NULL: ");
                return null;
            }
                // where to put the output file (note: /sdcard requires WRITE_EXTERNAL_STORAGE permission)
                File storageDir = Environment.getExternalStorageDirectory();
                String imageFileName = baseFileName + "_" +  Long.toString(sequentialCount++) + ".jpg";
                String filePath = storageDir + "/" + "tmp" + "/" + imageFileName;
                FileOutputStream out = null;
                YuvImage yuvimage = new YuvImage(bitmapData, ImageFormat.NV21, previewSize.width,
                        previewSize.height, null);
            try
            {
                out = new FileOutputStream(filePath);
                yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width,
                        previewSize.height), 100, out);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                try
                {
                    if (out != null)
                    {
                        out.close();
                    }
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            Log.d("doInBackground", ex.getMessage());
        }
        return null;
    }
}

我对 mediarecorder 的想法或蛮力帧捕获的想法很满意,但似乎都没有正常工作。

4

0 回答 0