Как передать предварительный просмотр камеры на поверхность, созданный MediaCodec.createInputSurface()?

В идеале я бы хотел достичь двух целей:

  • Передайте данные предварительного просмотра Camera в кодер MediaCodec с помощью Surface. Я могу создать Surface с помощью MediaCodec.createInputSurface(), но Camera.setPreviewDisplay() занимает SurfaceHolder, а не Surface.
  • Помимо передачи данных предварительного просмотра Camera в кодировщик, я также хотел бы отобразить предварительный просмотр на экране (так что пользователь может реально увидеть, что они кодируют). Если кодер не был задействован, я использовал бы SurfaceView, но это не работает в этом сценарии, так как SurfaceView создает свой собственный Surface, и я думаю, что мне нужно использовать созданную с помощью MediaCodec.

Я искал в Интернете довольно много для решения и не нашел его. Некоторые примеры на bigflake.com кажутся шагом в правильном направлении, но они используют подход, который добавляет кучу накладных расходов EGL/SurfaceTexture, d хотел бы избежать. Я надеюсь, что есть более простой пример или решение, в котором я могу напрямую разговаривать с Camera и MediaCodec без участия EGL или текстур.

Ответы

Ответ 1

Как и для Android 4.3 (API 18), правильный подход bigflake CameraToMpegTest - правильный путь.

Накладные расходы EGL/SurfaceTexture в настоящее время неизбежны, особенно для того, что вы хотите сделать в цели №2. Идея такова:

  • Настройте камеру для отправки вывода на SurfaceTexture. Это делает выход камеры доступным для GLES как "внешнюю текстуру".
  • Отобразите SurfaceTexture в Surface, возвращенный MediaCodec#createInputSurface(). Это подает видеокодер.
  • Повторно введите SurfaceTexture, a GLSurfaceView. Это выводит его на экран для предварительного просмотра в режиме реального времени.

Единственное копирование данных, которое происходит, выполняется драйвером GLES, поэтому вы выполняете аппаратные ускорения, которые будут быстрыми.

Единственный сложный бит - вы хотите, чтобы внешняя текстура была доступна для двух разных контекстов EGL (одна для MediaCodec, одна для GLSurfaceView). Вы можете увидеть пример создания общего контекста в примере патча "Захват игрового автомата Android" на большой ленте - он дважды воспроизводит игру, один раз на экран, один раз для кодера MediaCodec.

Обновление: Это реализовано в Grafika ( "Показать + камеру захвата" ).

Обновление: Многоконтекстный подход в подходе "показать + захват" несколько испорчен. Активность "непрерывного захвата" использует простой SurfaceView и способна выполнять как рендеринг экрана, так и видеозапись с одним контекстом EGL. Это рекомендуется.