使用MediaCodec和VirtualDisplay的Android流媒体,客户端断开连接

时间:2017-02-22 19:52:17

标签: android video-streaming screen mediacodec

我正在开发一款应用程序,用于记录我的Android设备的屏幕并将其通过rtsp传输到另一个客户端。我正在使用VirtualDisplay和MediaCodec。

我有一个我不知道如何解决的问题。当我开始流式传输时,客户端在屏幕更改之前不会收到任何内容。我想这是有道理的,缓冲区什么都没有,所以没有任何东西发送给客户端。代码是这样的:

MediaCodec buildMediaCodec() throws IOException {
    MediaFormat format = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, VIDEO_WIDTH, VIDEO_HEIGHT);

    // Set some required properties. The media codec may fail if these aren't defined.
   format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
   format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
   format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
   format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 1 seconds between I-frames

   // Create a MediaCodec encoder and configure it. Get a Surface we can use for recording into.
   MediaCodec mediaCodec = MediaCodec.createEncoderByType(VIDEO_MIME_TYPE);
   mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
   return mediaCodec;
}

// This is passed to buildVirtualDisplay(), and I get it from calling buildMediaCodec()
Surface mediaCodecSurface = mMediaCodec.createInputSurface();

VirtualDisplay buildVirtualDisplay(MediaProjection mediaProjection, Surface mediaCodecSurface, DisplayMetrics displayMetrics) {
   if (mediaProjection == null || mediaCodecSurface == null || displayMetrics == null) {
      throw new InvalidParameterException("MediaProjection, Surface and DisplayMetrics are mandatory");
   }
   return mediaProjection.createVirtualDisplay("Recording Display", VIDEO_WIDTH, VIDEO_HEIGHT, SCREEN_DPI, 0 /* flags */, mediaCodecSurface, null /* callback */, null /* handler */);
}

...

mIndex = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 500000);
if (mIndex >= 0) {
    mBuffer = mMediaCodec.getOutputBuffer(mIndex);
    if (mBuffer == null) {
       throw new RuntimeException("couldn't fetch buffer at index " + mIndex);
    }
    mBuffer.position(0);
    break;
 } else if (mIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
    mMediaFormat = mMediaCodec.getOutputFormat();
    Log.i(TAG, mMediaFormat.toString());
 } else if (mIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
    Log.v(TAG, "No buffer available...");
 } else {
     Log.e(TAG, "Message: " + mIndex);
 }

在日志中,我可以看到无缓冲区......一个接一个。在屏幕改变的那一刻它停止。

问题是当我停止与手机交互时。屏幕没有刷新,因为没有任何变化,所以我不断获得MediaCodec.INFO_TRY_AGAIN_LATER。大约10秒钟后,客户端断开连接。我猜它没有收到任何东西所以它只是关闭连接。

我还观察到,我在开始时等待的时间越长,服务器和客户端设备之间的延迟就越大。

如果我放一个进度条,一切正常,似乎屏幕重新渲染,因此缓冲区包含要发送的数据。

我已经找到了有关此问题的信息。有什么建议我可以做些什么来防止这种情况发生?我应该在MediaCodec和VirtualDisplay之间使用另一个Surface并尝试“强制”渲染吗?

感谢。

1 个答案:

答案 0 :(得分:1)

我发现客户端在未接收数据至少10秒后断开连接。我从MediaFormat尝试KEY_REPEAT_PREVIOUS_FRAME_AFTER来防止这种情况,但到目前为止还没有运气。