Android Asychrounous MediaCodec-解码器和渲染在单独的线程上

时间:2019-03-22 00:03:35

标签: android multithreading opengl-es-2.0 mediacodec android-mediacodec

我正在尝试在管道中开发以下模块:

[Receive data on Socket] 
         |
      buffer1
         |
         v
[Async Decode Frame]
         |
      buffer2
         |
         v
[Async Render to FBO-Texture-pair]
         |
      buffer3
         |
         v
[Display_on_screen]

*图例:[]表示模块,缓冲区*表示中间缓冲区

  • 每个模块都在单独的线程上运行。
  • 并非缓冲区1中接收的所有数据(或帧)都将被解码并发送到缓冲区2
  • 并非缓冲区2中的所有解码输出帧都将呈现为 (FBO-Texture)s
  • 缓冲区3中并非所有渲染的FBO纹理都将是 显示在屏幕上。

我知道这是一种特殊的用例,但是我使用内存池概念来管理不同缓冲区中的缓冲区对象,以避免内存分配并提高性能。

为实现[异步解码帧],我研究了Android MediaCodec Asynchronous Decoder examples,下面我指的是一个带有问题(Q1)内联注释的问题。

假设以下代码段是[异步解码帧]线程的一部分:

MediaCodec codec = MediaCodec.createByCodecName(name);
 MediaFormat mOutputFormat; // member variable
 codec.setCallback(new MediaCodec.Callback() {
  @Override
  void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {
    ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
    // fill inputBuffer with valid data
    …
    codec.queueInputBuffer(inputBufferId, …);
  }

  @Override
  void onOutputBufferAvailable(MediaCodec mc, int outputBufferId, …) {
    ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
    MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
    // bufferFormat is equivalent to mOutputFormat
    // outputBuffer is ready to be processed or rendered.

    // Q1. Will this logic work and efficient?
    // send outputBuffer to [Async-Render to FBO-Texture-pair] handler
    //     when done, send message to DecoderThreadHandler/[Async Decode Frame] to release outputBufferId


  }

  @Override
  void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {
    // Subsequent data will conform to new format.
    // Can ignore if using getOutputFormat(outputBufferId)
    mOutputFormat = format; // option B
  }

  @Override
  void onError(…) {
    …
  }
 });
 codec.configure(format, …);
 mOutputFormat = codec.getOutputFormat(); // option B
 codec.start();
 // wait for processing to complete
 codec.stop();
 codec.release();

问题

  1. 将问题(内联发布)渲染为独立线程中的(与FBO纹理对)是有效的还是有更好的方法?
  2. 如您所见,我试图通过不在codec.releaseOutputBuffer(outputBufferId, ...)回调中调用onOutputBufferAvailable()来避免渲染到Surface。这样做的主要原因是我可能无法渲染所有解码的帧,因为我可能会丢弃一些解码的帧,并将相应的对象释放回相应的内存池。避免渲染到Surface的另一个原因在in this link中进行了说明,这表明如果解码线程运行得太快,我的渲染线程可能会无意间跳过某些帧。这种方法会行得通吗?
  3. This blog帖子建议将数据从Decoder的outputBufferId复制到临时缓冲区中,但是用例与我的不同,并且我不确定是否应该使用相同的内容。我在这里感到困惑的主要原因是,我不想在智能手机(如果有)中的GPU内存和RAM之间进行不必要的乒乓。

任何建议都值得赞赏。让我知道是否需要进一步澄清。

0 个答案:

没有答案