2015-07-20 3 views
3

Я пишу приложение для Android, и в нем у меня есть VirtualDisplay, чтобы отразить то, что на экране, и затем отправлю кадры с экрана на экземпляр MediaCodec. Он работает, но, Я хочу добавить способ указания FPS закодированного видео, но я не уверен, как это сделать.Управление частотой кадров в VirtualDisplay

Из того, что я читал и экспериментировал, отбрасывание закодированных кадров (в зависимости от времени представления) не очень хорошо работает, поскольку оно заканчивается видеоизображением с блочным/артефактом, а не гладким видео с меньшей частотой кадров. Другое чтение предполагает, что единственный способ сделать то, что я хочу (ограничить FPS) будет ограничивать входящий FPS на MediaCodec, но VirtualDisplay просто получает Surface, который строится из MediaCodec ниже

mSurface = <instance of MediaCodec>.createInputSurface(); 
mVirtualDisplay = mMediaProjection.createVirtualDisplay(
    "MyDisplay", 
    screenWidth, 
    screenHeight, 
    screenDensity, 
    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, 
    mSurface, 
    null, 
    null); 

Я также пробовал подклассификацию Surface и ограничил рамки, которые подаются на MediaCodec через unlockCanvasAndPost(Canvas canvas), но функция никогда не кажется вызванной на моем экземпляре, поэтому может возникнуть какая-то странность в том, как я расширил Surface и взаимодействие с Parcel как writeToParcel функция вызвала мой экземпляр, но это это единственная функция, которая вызывается в моем экземпляре (что я могу сказать).

Другие чтения показывают, что я могу перейти от кодировщика -> декодер -> кодер и ограничить скорость, в которой второй кодер будет передаваться кадрами, но это много дополнительных вычислений, которые я бы предпочел не делать, если я могу избежать Это.

Кто-нибудь с успехом ограничил курс, по которому VirtualDisplay4 передает свои Surface? Любая помощь будет принята с благодарностью!

ответ

6

Начиная с того, что вы не можете сделать ...

Вы не можете оставить содержимое из кодированного потока. Большинство кадров в закодированном потоке по существу «отличает» от других кадров. Не зная, как взаимодействуют фреймы, вы не можете безопасно удалить контент, и в итоге получится искаженный макроблочный вид.

Вы не можете указать частоту кадров для кодировщика MediaCodec. Это может быть что-то в метаданных где-то, но единственное, что действительно имеет значение для кодека, это кадры, которые вы загружаете в него, и метки времени представления, связанные с каждым фреймом. Кодер не будет отбрасывать фреймы.

Вы не можете ничего сделать, используя подклассы Surface. Операции Canvas используются только для рендеринга программного обеспечения, которое не связано с подачей кадров с камеры или виртуального дисплея.

Что вы do отправляет кадры на промежуточную поверхность, а затем выбирает, следует ли пересылать их на поверхность ввода MediaCodec. Один из подходов заключался бы в создании SurfaceTexture, построении Surface от него и передаче этого виртуального дисплея. Когда срабатывает обратный вызов рамки SurfaceTexture, вы либо игнорируете его, либо визуализируете текстуру на входной поверхности MediaCodec с помощью GLES.

Различные примеры приведены в Grafika и bigflake, но ни один из них не является точным, но все необходимые классы EGL и GLES имеются.

+0

Благодарим вас за вход fadden! Звучит неплохо (почему я не подумал об этом?). Я инженер по графике, поэтому я должен быть хорошо настроен с помощью OpenGL-запросов на построение текстуры и т. Д. И т. Д. Я дам этот снимок и отчитаюсь. – EncodedNybble

+0

Итак, я заметил, что SurfaceTexture обрабатывает свои обратные вызовы на фрейме, получая сообщение либо в текущем петлере, либо в петлевом потоке пользовательского интерфейса, либо в нет. Что ... интересно. Хотелось бы указать способ обработчика или петлителя. Поскольку я выполняю всю эту работу в HandlerThread, это потребует некоторой работы. – EncodedNybble

+0

Просто отправьте сообщение. Типичная реализация 'onFrameAvailable()' выглядит следующим образом: https://github.com/google/grafika/blob/master/src/com/android/grafika/TextureFromCameraActivity.java#L668 – fadden

0

Вы можете ссылаться на образец кода из saki4510t's ScreenRecordingSample или RyanRQ's ScreenRecoder, все они используют дополнительную текстуру EGL между виртуальным дисплеем и медиакодером, а первая может содержать не менее 15 кадров в секунду для выходного видео. Вы можете найти ключевое слово createVirtualDisplay со своей базой кода для более подробной информации.

Смежные вопросы