Android Asychrounous MediaCodec - декодирование и рендеринг в отдельных потоках - PullRequest
0 голосов
/ 22 марта 2019

Я пытаюсь разработать следующие модули в конвейере:

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

* Обозначения: [] указывают модули, буфер * указывает промежуточные буферы

  • Каждый модуль работает в отдельном потоке.
  • Не все данные (или кадры), принятые в buffer1, будут декодированы и отправлены в buffer2
  • Не все декодированные выходные кадры в буфере 2 будут отображаться в (FBO-текстура) с
  • Не все визуализированные FBO-текстуры в буфере3 будут отображается на экране.

Я знаю, что это своего рода исключительный случай использования, но я управляю объектами буфера в разных буферах, используя понятие пула памяти, чтобы избежать выделения памяти и повысить производительность.

Чтобы реализовать [Async Decode Frame], я изучил примеры асинхронного декодера Android MediaCodec и ниже я имею в виду один из них с вопросом (Q1), встроенными комментариями.

Предположим, что следующий фрагмент кода является частью потока [Async Decode Frame]:

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-Texture-pair) в отдельном потоке будет эффективным или есть лучший подход?
  2. Как видите, я пытаюсь избежать рендеринга в Surface, не вызывая codec.releaseOutputBuffer(outputBufferId, ...) в onOutputBufferAvailable() callback. Основная причина для этого состоит в том, что я могу не рендерить все декодированные кадры, поскольку я могу отбросить некоторые декодированные кадры и освободить соответствующие объекты обратно в соответствующий пул памяти. Другая причина избегать рендеринга в Surface объясняется в этой ссылке , которая предполагает, что мой поток рендеринга может непреднамеренно пропустить определенные кадры, если поток декодирования работает слишком быстро. Будет ли этот подход работать хорошо?
  3. В этом блоге сообщение предлагает скопировать данные из outputBufferId декодера во временный буфер, однако вариант использования отличается от моего, и я не уверен, стоит ли использовать то же самое. Я запутался здесь в основном потому, что не хочу делать ненужный пинг-понг между GPU-памятью в смартфонах (если есть) и оперативной памятью.

Любое предложение высоко ценится. Дайте мне знать, если вам понадобятся дальнейшие разъяснения.

...