当前位置: 首页 > 知识库问答 >
问题:

使用mediacodec获取H264 ip摄像机流

平俊茂
2023-03-14

我正在尝试获取我网络上的摄像头产生的流。主要问题是这台相机产生的流是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,Status:Capacity=8 Position=0 Limit=8,Height=360,Mime=Video/AVC,csd-0=java.nio.ReadWriteHeapByteBuffer,Status:Capacity=31 Position=0 Limit=31,Width=640}”的解码器。

E/MediaCodec(20736):编解码器报告错误。(omx错误0x80001003,internalError-2147483648)

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

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

共有1个答案

华良平
2023-03-14

很确定mediaextractor不见了。使用ur解决方案,您没有解析出解码器不感兴趣的头信息。

这家伙往正确的方向走,但还是没有解决办法。

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

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

如果我想出了具体的解决方案,我会贴出来的。

 类似资料:
  • 前面的教程中我们讨论了观察矩阵以及如何使用观察矩阵移动场景(我们向后移动了一点)。OpenGL本身没有摄像机(Camera)的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种我们在移动的感觉,而不是场景在移动。 本节我们将会讨论如何在OpenGL中配置一个摄像机,并且将会讨论FPS风格的摄像机,让你能够在3D场景中自由移动。我们也会讨论键盘和鼠标输入,最终完成一个

  • 我想知道人与摄像机之间的距离。我使用的是android摩托罗拉平板电脑。 我使用的是android的摄像头api——api级别14。 我使用以下公式: imageHeight是我预览屏幕的高度<我从相机api获得的焦距:4.42毫米 我输入的物体高度是人的身高,单位为mm:1620mm 我想计算人与摄像机的距离。 通过使用这个公式,我得到了错误的距离,它给了我60毫米,但实际上它超过了2500毫米

  • 摄像机是玩家观察游戏世界的窗口,场景中至少需要有一个摄像机,也可以同时存在多个摄像机。创建场景时,Creator 会默认创建一个名为 Main Camera 的摄像机,作为这个场景的主摄像机。多摄像机的支持可以让你轻松实现高级的自定义效果,比如双人分屏效果,或者场景小地图的生成。 摄像机属性 backgroundColor 当指定了摄像机需要清除颜色的时候,摄像机会使用设定的背景色来清除场景。 d

  • 摄像机的抽象基类。在构建新摄像机时,应始终继承此类。 构造函数 Camera() 创建一个新的Camera(摄像机)。注意:这个类并不是被直接调用的;你所想要的或许是一个 PerspectiveCamera(透视摄像机)或者 OrthographicCamera(正交摄像机)。 属性 共有属性请参见其基类Object3D .layers : Layers 摄像机是一个layers的成员. 这是一个

  • 摄像机,如同大家拍照时使用的相机,用来确定观察 3D 场景的视角。 摄像机包含两个重要的位置参数:镜头位置 position 和被拍摄物体的位置 target (又叫目标点)。 控制摄像机位置 设置摄像机位置 将下面的代码输入到项目文件中,即可获取当前摄像机 camera 的 position 和 target 属性,就可以得到 3D 场景中摄像机的位置信息,也可以将其打印在控制台中。 // 加载

  • Cameras are the devices that capture and display the world to the player. By customizing and manipulating cameras, you can make the presentation of your game truly unique. You can have an unlimited nu