本文介绍了机器人:SurfaceTexure,摄像头帧等待时间出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图用媒体codeC和MediaMux,我遇到一些麻烦。

I'm trying to use MediaCodec and MediaMux, and I meet some trouble.

下面是从logcat的错误:

Here is the errors from the logcat:

12-13 11:59:58.238: E/AndroidRuntime(23218): FATAL EXCEPTION: main
12-13 11:59:58.238: E/AndroidRuntime(23218): java.lang.RuntimeException: Unable to resume activity {com.brendon.cameratompeg/com.brendon.cameratompeg.CameraToMpeg}: java.lang.IllegalStateException: Can't stop due to wrong state.
12-13 11:59:58.238: E/AndroidRuntime(23218):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2918)

在code拿错在mStManager.awaitNewImage();,这是在onResume功能。而logcat的说,相机架等待时间了。结果
mStManager是类SurfaceTextureManager的一个实例。而相机架等待超时来自awaitNewImage()函数。我添加了类,我的职务。

The code get wrong at "mStManager.awaitNewImage();", which is in the onResume function. And the logcat says "camera frame wait time out".
mStManager is an instance of the class SurfaceTextureManager. And "camera frame wait time out" comes from the awaitNewImage() function. I've added that class to my post.

我的code的部分原因是这样的(该功能的onCreate和onResume功能):

Part of my code is like this(The onCreate function and onResume function):

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        // arbitrary but popular values
        int encWidth = 640;
        int encHeight = 480;
        int encBitRate = 6000000;      // Mbps
        Log.d(TAG, MIME_TYPE + " output " + encWidth + "x" + encHeight + " @" + encBitRate);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera_to_mpeg);

           prepareCamera(encWidth, encHeight);
           prepareEncoder(encWidth, encHeight, encBitRate);
           mInputSurface.makeCurrent();
           prepareSurfaceTexture();

           mCamera.startPreview();
}


@Override
public void onResume(){

    try {

         long startWhen = System.nanoTime();
           long desiredEnd = startWhen + DURATION_SEC * 1000000000L;
           SurfaceTexture st = mStManager.getSurfaceTexture();
           int frameCount = 0;

        while (System.nanoTime() < desiredEnd) {
            // Feed any pending encoder output into the muxer.
            drainEncoder(false);

            // Switch up the colors every 15 frames.  Besides demonstrating the use of
            // fragment shaders for video editing, this provides a visual indication of
            // the frame rate: if the camera is capturing at 15fps, the colors will change
            // once per second.
            if ((frameCount % 15) == 0) {
                String fragmentShader = null;
                if ((frameCount & 0x01) != 0) {
                    fragmentShader = SWAPPED_FRAGMENT_SHADER;
                }
                mStManager.changeFragmentShader(fragmentShader);
            }
            frameCount++;

            // Acquire a new frame of input, and render it to the Surface.  If we had a
            // GLSurfaceView we could switch EGL contexts and call drawImage() a second
            // time to render it on screen.  The texture can be shared between contexts by
            // passing the GLSurfaceView's EGLContext as eglCreateContext()'s share_context
            // argument.
            mStManager.awaitNewImage();
            mStManager.drawImage();

            // Set the presentation time stamp from the SurfaceTexture's time stamp.  This
            // will be used by MediaMuxer to set the PTS in the video.
            if (VERBOSE) {
                Log.d(TAG, "present: " +
                        ((st.getTimestamp() - startWhen) / 1000000.0) + "ms");
            }
            mInputSurface.setPresentationTime(st.getTimestamp());

            // Submit it to the encoder.  The eglSwapBuffers call will block if the input
            // is full, which would be bad if it stayed full until we dequeued an output
            // buffer (which we can't do, since we're stuck here).  So long as we fully drain
            // the encoder before supplying additional input, the system guarantees that we
            // can supply another frame without blocking.
            if (VERBOSE) Log.d(TAG, "sending frame to encoder");
            mInputSurface.swapBuffers();
        }

        // send end-of-stream to encoder, and drain remaining output
        drainEncoder(true);
    } catch(Exception e) {
        Log.d(TAG,  e.getMessage());
        // release everything we grabbed
        releaseCamera();
        releaseEncoder();
        releaseSurfaceTexture();
    }
}

在code一类是相关的误差

a class in the code that is relevant to the error

 private static class SurfaceTextureManager
            implements SurfaceTexture.OnFrameAvailableListener {
        private SurfaceTexture mSurfaceTexture;
        private CameraToMpeg.STextureRender mTextureRender;

        private Object mFrameSyncObject = new Object();     // guards mFrameAvailable
        private boolean mFrameAvailable;

        /**
         * Creates instances of TextureRender and SurfaceTexture.
         */
        public SurfaceTextureManager() {
            mTextureRender = new CameraToMpeg.STextureRender();
            mTextureRender.surfaceCreated();

            if (VERBOSE) Log.d(TAG, "textureID=" + mTextureRender.getTextureId());
            mSurfaceTexture = new SurfaceTexture(mTextureRender.getTextureId());

            // This doesn't work if this object is created on the thread that CTS started for
            // these test cases.
            //
            // The CTS-created thread has a Looper, and the SurfaceTexture constructor will
            // create a Handler that uses it.  The "frame available" message is delivered
            // there, but since we're not a Looper-based thread we'll never see it.  For
            // this to do anything useful, OutputSurface must be created on a thread without
            // a Looper, so that SurfaceTexture uses the main application Looper instead.
            //
            // Java language note: passing "this" out of a constructor is generally unwise,
            // but we should be able to get away with it here.
            mSurfaceTexture.setOnFrameAvailableListener(this);
        }

        public void release() {
            // this causes a bunch of warnings that appear harmless but might confuse someone:
            //  W BufferQueue: [unnamed-3997-2] cancelBuffer: BufferQueue has been abandoned!
            //mSurfaceTexture.release();

            mTextureRender = null;
            mSurfaceTexture = null;
        }

        /**
         * Returns the SurfaceTexture.
         */
        public SurfaceTexture getSurfaceTexture() {
            return mSurfaceTexture;
        }

        /**
         * Replaces the fragment shader.
         */
        public void changeFragmentShader(String fragmentShader) {
            mTextureRender.changeFragmentShader(fragmentShader);
        }

        /**
         * Latches the next buffer into the texture.  Must be called from the thread that created
         * the OutputSurface object.
         */
        public void awaitNewImage() {
            final int TIMEOUT_MS = 2500;

            synchronized (mFrameSyncObject) {
                while (!mFrameAvailable) {
                    try {
                        // Wait for onFrameAvailable() to signal us.  Use a timeout to avoid
                        // stalling the test if it doesn't arrive.
                        mFrameSyncObject.wait(TIMEOUT_MS);
                        if (!mFrameAvailable) {
                            // TODO: if "spurious wakeup", continue while loop
                            throw new RuntimeException("Camera frame wait timed out");
                        }
                    } catch (InterruptedException ie) {
                        // shouldn't happen
                        throw new RuntimeException(ie);
                    }
                }
                mFrameAvailable = false;
            }

            // Latch the data.
            mTextureRender.checkGlError("before updateTexImage");
            mSurfaceTexture.updateTexImage();
        }

        /**
         * Draws the data from SurfaceTexture onto the current EGL surface.
         */
        public void drawImage() {
            mTextureRender.drawFrame(mSurfaceTexture);
        }

        @Override
        public void onFrameAvailable(SurfaceTexture st) {
            if (VERBOSE) Log.d(TAG, "new frame available");
            synchronized (mFrameSyncObject) {
                if (mFrameAvailable) {
                    throw new RuntimeException("mFrameAvailable already set, frame could be dropped");
                }
                mFrameAvailable = true;
                mFrameSyncObject.notifyAll();
            }
        }
    }

有没有人有什么想法?谢谢!

Does anyone have any ideas? Thank you!

推荐答案

我遇到过这个问题为好。因此,原因是你的code是有一个弯一个线程中运行。你必须确保code为在不具有一个弯一个线程中运行。如果是这样,SurfaceTexture.OnFrameAvailableListener将提供框架可用消息的等待线程,而不是将消息发送给处理程序的主线程上,你会被卡住。

I encountered this issue as well. The reason therefore is that your code is running on a thread that has a looper. You have to make sure that the code is running on a thread that does not have a looper. If it does, SurfaceTexture.OnFrameAvailableListener will deliver the "frame available" message to the waiting thread, rather than sending the Message to the Handler on the main thread, and you'll get stuck.

Bigflake的例子为您提供上的详细描述:

Bigflake's examples provide you with a detailed description on that:

/**
 * Wraps testEditVideo, running it in a new thread.  Required because of the way
 * SurfaceTexture.OnFrameAvailableListener works when the current thread has a Looper
 * configured.
 */
private static class VideoEditWrapper implements Runnable {
    private Throwable mThrowable;
    private DecodeEditEncodeTest mTest;
    private VideoEditWrapper(DecodeEditEncodeTest test) {
        mTest = test;
    }
    @Override
    public void run() {
        try {
            mTest.videoEditTest();
        } catch (Throwable th) {
            mThrowable = th;
        }
    }
    /** Entry point. */
    public static void runTest(DecodeEditEncodeTest obj) throws Throwable {
        VideoEditWrapper wrapper = new VideoEditWrapper(obj);
        Thread th = new Thread(wrapper, "codec test");
        th.start();
        th.join();
        if (wrapper.mThrowable != null) {
            throw wrapper.mThrowable;
        }
    }
}

这篇关于机器人:SurfaceTexure,摄像头帧等待时间出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 09:03