Захват видео в OpenGL приложениях с помощью Intel INDE Media Pack

imageИз прошлых статей вы уже знаете, что такое Intel INDE и его компонент Intel INDE Media Pack, предоставляющий разнообразные возможности работы с видео. В этот раз я хочу поподробнее остановиться на такой возможности Intel INDE Media Pack, как захват видео в приложениях, использующих OpenGL.Начну я не с примеров и рассказа о том, как это все работает, а с ответов на вопросы, которые чаще всего задают разработчики, когда речь заходит о захвате видео в Media Pack: «Зачем мне вообще делать возможность захвата видео в своем приложении?» и «Зачем использовать Media Pack, если в Android 4.4 появилась возможность захвата видео через ADB?»

Зачем это разработчику и пользователям 1. Это модель использования, которая может лечь в основу приложения, такого, как например Toy Story: Story Theater. Пользователь производит действия с объектами на экране, приложение захватывает видео, пишет его в файл, далее дает возможность его просмотреть, сохранить, поделиться в социальных сетях.2. Новая возможность для пользователя — записать и сохранить удачный игровой момент, способ прохождения уровня, которым он также сможет поделиться в социальных сетях. Для разработчика это будет один из способов популяризации приложения.

Захват видео через ADB Основное отличие от данного способа — это отсутствие необходимости подключать мобильное устройство к хосту, захват происходит прямо на устройстве, при этом не требуется «рутовать» устройство, используются стандартные механизмы. На выходе получается MP4 видео, готовое к просмотру или загрузке в сеть.Второе отличие — есть возможность захватывать не только видео, но и аудио со встроенного микрофона, что делает возможным захват звука из приложения, плюс возможность комментирования того, что происходит на экране.

Захват видео в OpenGL приложениях с помощью Media Pack Первым делом необходимо скачать и установить INDE Media Pack, о том как это делается я подробно рассказал в этой статье.Внутри находятся две библиотеки, которые необходимо включить в свое приложение — android-<номер версии>.jar и domain-<номер версии>.jar

image

Всю работу по захвату видео делает класс GLCapture. Принцип его работы прост: он имеет собственную поверхность (Surface), содержимое которой он кодирует в кадры и пишет в видео. Приложение сначала отрисовывает текущий кадр на экран, затем переключает контекст на поверхность GLCapture и рисует сцену еще раз, при восстановлении контекста текущее содержимое поверхности кодируется и пишется в результирующее видео.

Перед началом использования GLCapture его необходимо подготовить, а именно:

Задать параметры видео Аудио (если есть необходимость писать звук) Указать, куда будет сохраняться видео (путь к файлу) Сконфигурировать поверхность // Объявление GLCapture capturer; … // Создание экземпляра capturer = new GLCapture (new AndroidMediaObjectFactory ()); Настройка параметров видео // Создаем и инициализируем видео формат // Формат видео String videoMimeType = «video/avc»;

// Ширина кадра int videoFrameWidth = 640;

// Высота кадра int videoFrameHeight = 480;

// Битрейт в килобайтах int videoBitRate = 5000;

// Частота кадров в секунду int videoFrameRate = 30;

// Частота ключевых кадров int videoIFrameInterval = 1;

VideoFormatAndroid videoFormat = new VideoFormatAndroid (videoMimeType, videoFrameWidth, videoFrameHeight);

videoFormat.setVideoBitRateInKBytes (videoBitRate); videoFormat.setVideoFrameRate (videoFrameRate); videoFormat.setVideoIFrameInterval (videoIFrameInterval);

// Задаем видео формат сapturer.setTargetVideoFormat (videoFormat); Настройка параметров аудио Если нет необходимости писать звук, этот шаг можно пропустить // Создаем и инициализируем аудио формат // Формат Audio String audioMimeType = «audio/mp4a-latm»;

// Частота аудио сэмплов int audioSampleRate = 44100;

// Количество уадио каналов int audioChannelCount = 1;

AudioFormatAndroid audioFormat = new AudioFormatAndroid (audioMimeType, audioSampleRate, audioChannelCount);

// Задаем аудио формат сapturer.setTargetAudioFormat (audioFormat); Путь к результирующему видео String dstPath = »…»; capture.setTargetFile (dstPath); Инициализация поверхности Перед первым использованием необходимо инициализировать поверхность, делается это путем вызова capture.setSurfaceSize (videoFrameWidth, videoFrameHeight) Одно условие — вызов должен быть осуществлен из функции с активным OpenGL контекстом, т.е. где-то в

onSurfaceChanged (GL10 gl, int width, int height)

или

onDrawFrame (GL10 gl) После того, как параметры заданы, поверхность сконфигурирована, можем начинать сохранять кадры в видео.

В простейшем случае можно дважды отрисовать сцену — сначала на экран, затем на поверхность.

Способ первый: двойная отрисовка // Рисуем сцену на экран render ();

// Переключаем контекст capturer.beginCaptureFrame ();

// Рисуем сцену на поверхность GLCapture render ();

// Восстанавливаем контекст capturer.endCaptureFrame (); В некоторых случаях такой подход может сказаться на производительности, например в случае сцен с большим количеством объектов, текстур, пост обработкой кадра. Чтобы избежать двойной отрисовки, можно использовать кадровый буфер (frame buffer).

Способ второй: кадровый буфер В этом случае алгоритм выглядит следующим образом: Создаем кадровый буфер и привязанную к нему текстуру Рисуем сцену на текстуру Рисуем полноэкранную текстуру на экран Переключаем контекст и рисуем текстуру на поверхность GLCapture Дабы сэкономить время разработчикам на реализацию этого метода, мы включили в библиотеку все необходимые компоненты для работы с кадровым буфером.

// Класс-обертка FrameBuffer frameBuffer; // Вспомогательный класс для рисования полноэкранной текстуры FullFrameTexture texture;

// Где-то в функции с активным OpenGL контекстом, например

public void onSurfaceChanged (GL10 gl, int width, int height) {

frameBuffer = new FrameBuffer (EglUtil.getInstance ()); frameBuffer.setResolution (new Resolution (width, height));

texture = new FullFrameTexture (); } Как видите — минимум кода для создания и инициализации. При желание нашу реализацию можно заменить на собственную, никаких ограничений.

// В функции рисования

public void onDrawFrame (GL10 gl) {

// Будем рисовать на текстуру frameBuffer.bind ();

// Рисуем сцену renderScene ();

// Восстанавливаем контекст frameBuffer.unbind ();

// Рисуем текстуру на экран texture.draw (frameBuffer.getTextureId ());

// Переключаем контекст capture.beginCaptureFrame ();

// Рисуем текстуру на поверхность texture.draw (frameBuffer.getTextureId ());

// Восстанавливаем контекст capture.endCaptureFrame (); } С целью упростить пример я исключил часть кода, который вычисляет и устанавливает область просмотра (view port), что является необходимым условием для корректного отображения захвата видео в случаях, когда размер экрана и разрешение результирующего видео не совпадают.

Полную версию примера вы сможете найти в приложении samples, поставляемом в составе Intel INDE Media Pack, класс GameRenderer.

image

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

11–12 Апреля в Москве в Digital October состоится ежегодная конференция Droidcon, на которой компания Intel на своем стенде представит образцы мобильных устройств на базе IA. Помимо этого, мы представим доклад (в пятницу 11-го) и workshop (в субботу 12-го) на тему Intel INDE. Если вы планируете посетить данное мероприятие — не забудьте заглянуть к нам, будет интересно!

© Habrahabr.ru