繁体   English   中英

使用MediaCodec获取H264 IP摄像机流

[英]Get H264 ip camera stream using mediacodec

我正在尝试获取网络上的摄像机产生的流。 主要问题是此相机产生的流是H264流。 我四处寻找找到管理这种流的最佳方法,并且我发现mediacodec是最合适的类。 不幸的是,该API的文档非常差,但是尽管如此,我还是找到了一些资源来获取此类的基本信息,并且编写了以下代码。

公共类DecodeActivity扩展Activity实现了SurfaceHolder.Callback {

private final String sampleStreamAddress = "http://192.168.0.240:80";
private PlayerThread mPlayer = null;

String mimeType = "video/avc";
MediaFormat format = MediaFormat.createVideoFormat(mimeType, 640, 360);

final byte[] header_sps = { 0, 0, 0, 1, 103, 100, 0, 40, -84, 52, -59, 1,
        -32, 17, 31, 120, 11, 80, 16, 16, 31, 0, 0, 3, 3, -23, 0, 0, -22,
        96, -108 };
final byte[] header_pps = { 0, 0, 0, 1, 104, -18, 60, -128 };

private static final String tag = DecodeActivity.class.getSimpleName();

@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final SurfaceView sv = new SurfaceView(this);
    sv.getHolder().addCallback(this);
    setContentView(sv);

    format.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps));
    format.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps));

}

@Override
protected void onDestroy() {
    super.onDestroy();
}

@Override
public void surfaceCreated(final SurfaceHolder holder) {

    Log.i(tag, "surfaceCreated");

    if (mPlayer == null) {
        mPlayer = new PlayerThread(holder.getSurface());
        mPlayer.start();
    }
}

@Override
public void surfaceChanged(final SurfaceHolder holder, final int format,
        final int width, final int height) {

    Log.i(tag, "surfaceChanged");

    if (mPlayer == null) {
        mPlayer = new PlayerThread(holder.getSurface());
        mPlayer.start();
    }
}

@Override
public void surfaceDestroyed(final SurfaceHolder holder) {

    Log.i(tag, "surfaceDestroyed");

    if (mPlayer != null) {
        mPlayer.interrupt();
    }
}

private class PlayerThread extends Thread {
    private MediaCodec decoder;
    private final Surface surface;

    public PlayerThread(final Surface surface) {
        this.surface = surface;
    }

    @Override
    public void run() {

        try {

            Log.i(tag, "running PlayerThrad");

            decoder = MediaCodec.createDecoderByType(format.toString());
            decoder.configure(format, surface, null, 0);

            decoder.start();

            final ByteBuffer[] inputBuffers = decoder.getInputBuffers();
            ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
            final BufferInfo info = new BufferInfo();
            boolean isEOS = false;
            final long startMs = System.currentTimeMillis();

            //
            HttpResponse res;
            final DefaultHttpClient httpclient = new DefaultHttpClient();

            while (!Thread.interrupted()) {
                if (!isEOS) {

                    final int inIndex = decoder.dequeueInputBuffer(10000);
                    if (inIndex >= 0) {
                        final byte buffer2[] = new byte[18800 * 8 * 8 * 8];
                        final ByteBuffer buffer = inputBuffers[inIndex];

                        final HttpParams httpParameters = new BasicHttpParams();
                        HttpConnectionParams.setConnectionTimeout(
                                httpParameters, 200);
                        httpclient.setParams(httpParameters);
                        Log.d(tag, " URL : " + sampleStreamAddress);
                        res = httpclient.execute(new HttpGet(URI
                                .create(sampleStreamAddress)));

                        final DataInputStream mjpegInputStream = new DataInputStream(
                                res.getEntity().getContent());

                        final int sampleSize = mjpegInputStream.read(
                                buffer2, 0, 18800 * 4);

                        buffer.clear();
                        buffer.put(buffer2, 0, sampleSize);
                        buffer.clear();

                        if (sampleSize < 0) {
                            // We shouldn't stop the playback at this point,
                            // just pass the EOS
                            // flag to decoder, we will get it again from
                            // the
                            // dequeueOutputBuffer
                            Log.d("DecodeActivity",
                                    "InputBuffer BUFFER_FLAG_END_OF_STREAM");
                            decoder.queueInputBuffer(inIndex, 0, 0, 0,
                                    MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                            isEOS = true;
                        } else {
                            decoder.queueInputBuffer(inIndex, 0,
                                    sampleSize, 0, 0);
                            // extractor.advance();
                        }
                    }
                }

                final int outIndex = decoder.dequeueOutputBuffer(info,
                        10000);
                switch (outIndex) {
                case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                    Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED");
                    outputBuffers = decoder.getOutputBuffers();
                    break;
                case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                    Log.d("DecodeActivity",
                            "New format " + decoder.getOutputFormat());
                    break;
                case MediaCodec.INFO_TRY_AGAIN_LATER:
                    Log.d("DecodeActivity",
                            "dequeueOutputBuffer timed out!");
                    break;
                default:
                    final ByteBuffer buffer = outputBuffers[outIndex];
                    Log.v("DecodeActivity",
                            "We can't use this buffer but render it due to the API limit, "
                                    + buffer);

                    // We use a very simple clock to keep the video FPS, or
                    // the
                    // video
                    // playback will be too fast
                    while (info.presentationTimeUs / 1000 > System
                            .currentTimeMillis() - startMs) {
                        try {
                            sleep(10);
                        } catch (final InterruptedException e) {
                            e.printStackTrace();
                            break;
                        }
                    }
                    decoder.releaseOutputBuffer(outIndex, true);
                    break;
                }

                // All decoded frames have been rendered, we can stop
                // playing
                // now
                if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                    Log.d("DecodeActivity",
                            "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
                    break;
                }
            }

            decoder.stop();
            decoder.release();
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }
}

}

问题是,当我尝试运行此活动时,出现以下错误:

(20736):无法实例化类型为'{csd-1 = java.nio.ReadWriteHeapByteBuffer'的解码器,状态:容量= 8位置= 0限制= 8,高度= 360,哑剧=视频/ avc,csd-0 = java .nio.ReadWriteHeapByteBuffer,状态:容量= 31位置= 0限制= 31,宽度= 640}'。

E / MediaCodec(20736):编解码器报告了一个错误。 (omx错误0x80001003,内部错误-2147483648)

F / libc(20736):致命信号11(SIGSEGV)位于0x00000008(代码= 1),线程20752(线程324)

有人能够指出我正确的方向吗? 因为我看不到我在做什么错。 提前致谢

可以肯定的是,MediaExtractor丢失了。 使用您的解决方案时,您会错过解析出解码器不感兴趣的标头信息的机会。

这个家伙走了正确的方向,但仍然没有解决方案。

Android从套接字使用MediaExtractor和MediaCodec(流mpeg)

接下来,您没有正确实例化解码器。 更换线

decoder = MediaCodec.createDecoderByType(format.toString());

decoder = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME));

如果我想出一个具体的解决方案,我将发布它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM