В Android, как передать предопределенную поверхность в MediaCodec для кодирования?

У меня есть приложение, которое управляет своим собственным GLSurfaceView, и теперь я хочу использовать новую функцию Android 4.3 MediaCodec, которая принимает поверхность в качестве входных данных.

Во всех примерах, которые я видел, поверхность создается с помощью MediaCodec.createInputSurface(), затем для этой поверхности создается контекст GL. Это кажется монолитным и невероятно разрушительным для модернизации уже стабильной кодовой базы.

Можно ли вместо этого использовать MediaCodec.configure(format, a_predefined_Surface, null, MediaCodec.CONFIGURE_FLAG_ENCODE)? Это позволяет мне использовать MediaCodec в режиме plug-and-play и по требованию. Тот факт, что MediaCodec.configure() принимает параметр Surface, указывает на то, что это должно быть возможно. Однако в API указано, что «укажите поверхность, на которой будет отображаться вывод этого декодера» http://developer.android.com/reference/android/media/MediaCodec.html#configure(android.media.MediaFormat, android.view.Surface, android.media .MediaCrypto, int) означает ли это, что это предназначено только для декодирования, а не для кодирования? Если да, то есть ли способ заставить MediaCodec использовать предопределенную поверхность для кодирования?

Поверхность, которую я передаю, уже создана с EGL_RECORDABLE_ANDROID, для которого установлено значение true, а возвращенный контекст GL проверен на наличие требуемого атрибута EGL_RECORDABLE_ANDROID. Несмотря на это, MediaCodec.configure() завершается сбоем с бесполезным исключением «native_window_api_connect возвращает ошибку: неверный аргумент (-22)»:

I/ACodec(32383):  Now uninitialized
I/OMXClient(32383): Using client-side OMX mux.
I/ACodec(32383): [OMX.qcom.video.encoder.avc] Now Loaded
E/MediaCodec(32383): native_window_api_connect returned an error: Invalid argument (-22)
W/System.err(32383): java.lang.IllegalStateException
W/System.err(32383):    at android.media.MediaCodec.native_configure(Native Method)
W/System.err(32383):    at android.media.MediaCodec.configure(MediaCodec.java:259)
[...]
W/System.err(32383):    at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1520)
W/System.err(32383):    at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)

Это от Samsung Galaxy S4 с Android 4.3.


person Vin Kemp    schedule 07.01.2014    source источник


Ответы (2)


Нет, это так не работает. Входная поверхность должна быть создана с помощью createInputSurface().

Имейте в виду, что «поверхность» — это не буфер данных, это очередь буферов, для которых конечные точки производителя и потребителя часто находятся в разных процессах. Есть много движущихся частей, которые нужно настроить. Также обратите внимание, что Surface и EGLSurface — это две разные вещи, которые, хотя часто используются вместе, не имеют тесной связи.

API кажется неуклюжим и странным, потому что... так оно и есть. Реализация Surface сильно изменилась за прошедшие годы — раньше основы были гораздо менее общими, поэтому большинство API для изменения конечных точек не раскрываются. (Недоуказанный) MediaCodec API все еще развивается.

В Grafika есть пример представления одного и того же контента (предварительный просмотр камеры) для GLSurfaceView и MediaCodec. Похоже, вы пытаетесь сделать что-то подобное. (Если нет, обновите свой вопрос, и я обновлю ответ.)

person fadden    schedule 07.01.2014
comment
Могу ли я записывать видео, помещая растровое изображение в Surface MediaCodec, как с MediaRecorder? см. это stackoverflow.com/questions/51332386/ - person user25; 14.07.2018

Кажется, в API 23+ есть API с именем setInputSurface(Surface):

API 23+ с setInputSurface(Surface)

person ytliu    schedule 04.11.2015
comment
Обратите внимание, что он использует постоянную поверхность ввода, созданную вызовом MediaCodec createPersistentInputSurface(). Таким образом, API более гибкий, но вам все равно придется использовать поверхность, созданную MediaCodec. - person fadden; 09.03.2016