如何将Media Recorder添加到Android Google Play服务Vision条形码扫描仪

时间:2016-03-03 23:33:54

标签: android android-camera mediarecorder android-vision

这个问题被问到但从未回答过here - 但不管怎么说,它与我的需求有所不同。

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

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

所以至少要证明这个概念,我想简单地修改一下Google Vision Demo。 (找到Here

似乎最简单的事情就是跳转代码并添加一个媒体记录器。我在表面创建过程中在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);
        }
    }

那些记录的东西,同时仍然将每一帧交给Vision代码。但是,奇怪的是,当我这样做时,相机似乎没有正确调用自动对焦,并且条形码不会被扫描 - 因为它们从未真正聚焦,因此无法识别。

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

我是在CameraSource.java中做到的。

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

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

在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的想法,或强力帧捕获的想法,但似乎都没有正常工作。

0 个答案:

没有答案