带有TextureView和MediaCodec的Android Stream H264

问题描述

我正在获取字节流[],这些字节最终是h264帧,我想使用TextureView将其流传输到android。

我知道字节的顺序和结构是可以的,因为我可以将它们保存到文件中,然后使用VLC媒体播放器将其打开并播放视频,尽管我一直在努力TextureView。

这是我的片段:

public class HelpFragment extends Fragment implements TextureView.SurfaceTextureListener {

    private static final Logger Log = Logger.getLogger(HelpFragment.class.getName());

    private TextureView m_surface;// View that contains the Surface Texture

    private H264Provider FrameProvider;// Object that connects to our server and gets H264 frames

    private MediaCodec m_codec;// Media decoder

    private DecodeFramesTask m_frameTask;// AsyncTask that takes H264 frames and uses the decoder to update the Surface Texture

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.help_fragment,container,false);

        // Get a referance to the TextureView in the UI
        m_surface = (TextureView) root.findViewById(R.id.textureView);

        // Add this class as a call back so we can catch the events from the Surface Texture
        m_surface.setSurfaceTextureListener(this);

        return root;
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface,int width,int height) {
        // Create the format settinsg for the MediaCodec
        MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC,1280,720);// MIMETYPE: a two-part identifier for file formats and format contents
        // Set the buffer size
        format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE,100000);

        format.setInteger(MediaFormat.KEY_FRAME_RATE,30);

        try {
            // Get an instance of MediaCodec and give it its Mime type
            m_codec = MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
            // Configure the Codec
            m_codec.configure(format,new Surface(m_surface.getSurfaceTexture()),null,0);
            // Start the codec
            m_codec.start();
            // Create the AsyncTask to get the frames and decode them using the Codec
            m_frameTask = new DecodeFramesTask();
            m_frameTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface,int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }

    private class DecodeFramesTask extends AsyncTask<String,String,String> {

        @Override
        protected String doInBackground(String... data) {
            while (!isCancelled()) {
                // Get the next frame
                byte[] frame = Frameprovider.getVideoFrame(); // -> this gives me the video frames ***
                if (frame != null) {
                    android.util.Log.i("tag",bytesToHex(frame));
                }

                // Now we need to give it to the Codec to decode into the surface

                // Get the input buffer from the decoder
                int inputIndex = m_codec.dequeueInputBuffer(-1);// Pass in -1 here as in this example we don't have a playback time reference

                // If  the buffer number is valid use the buffer with that index
                if (inputIndex >= 0 && frame != null) {
                    ByteBuffer buffer = m_codec.getInputBuffer(inputIndex);
                    buffer.put(frame);

                    // tell the decoder to process the frame
                    m_codec.queueInputBuffer(inputIndex,frame.length,0);
                }

                MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                int outputIndex = m_codec.dequeueOutputBuffer(info,0);
                if (outputIndex >= 0) {
                    m_codec.releaseOutputBuffer(outputIndex,true);
                }
            }
            return "";
        }

        @Override
        protected void onPostExecute(String result) {
            try {
                m_codec.stop();
                m_codec.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void onStop() {
        super.onStop();
        m_frameTask.cancel(true);
    }

}

当我运行它时,我不断收到此错误:

E/MediaCodec: getBufferAndFormat - invalid operation (the index 0 is not owned by client)
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
    Process: com.packagename._test,PID: 11740
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.os.AsyncTask$4.done(AsyncTask.java:399)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
        at java.util.concurrent.FutureTask.run(FutureTask.java:271)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:919)
     Caused by: java.lang.IllegalStateException
        at android.media.MediaCodec.getBuffer(Native Method)
        at android.media.MediaCodec.getInputBuffer(MediaCodec.java:3212)
        at com.packagename._test.ui.fragments.help.HelpFragment$DecodeFramesTask.doInBackground(HelpFragment.java:130)
        at com.packagename._test.ui.fragments.help.HelpFragment$DecodeFramesTask.doInBackground(HelpFragment.java:112)
        at android.os.AsyncTask$3.call(AsyncTask.java:378)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:919)

编辑: 我稍微改变了帧的顺序,现在我得到了这种类型的帧,但没有暗恋:

frame example

知道为什么吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...