В этом уроке разберем код приложения, которое записывает видео с экрана устройства со звуком. До Андроид 5.0 приложение для записи видео с экрана мобильных устройств требовало рут-доступ и не гарантировало нормальную работу на устройствах разных производителей. Все изменилось в API 21 версии. Здесь появился класс MediaProjection, который предоставляет доступ для записи видео с экрана или звука с аудио системы.
Давайте рассмотрим код приложения для записи видео с экрана устройства.

Макет экрана содержит одну кнопку для старта и остановки записи.

Перейдем к коду. В главном пакете видим три класса- класс RecordApplication, класс MainActivity и класс RecordService.

Рассмотрим класс RecordApplication. Его вызов происходит в манифесте в секции application в строке android:name=.

Класс RecordApplication унаследован от класса Application. Согласно документации, класс Application или его наследник инициализируется перед любым другим классом, когда создается процесс приложения.

Здесь вызывается метод startService, который запускает сервис RecordService при старте приложения.

Класс RecordService унаследован от класса Service. О том, что такое сервисы, подробно можно узнать из видеоуроков на нашем канале, начиная с урока 92.
Если в двух словах, сервис – это некая задача, которая работает в фоне и не использует UI. Поскольку нам нужно записывать все, что происходит на экране, независимо от того, какое приложение запущено, поэтому мы и будем использовать сервис.

Здесь объявлены переменные классов:

MediaProjection — это токен, предоставляющий приложению возможность захватить содержимое экрана и/или записывать аудио системы.
MediaRecorder — класс, который используется для записи аудио и видео.
VirtualDisplay Представляет собой виртуальный экран, содержимое которого рендерится в Surface, который мы передаем методу createVirtualDisplay.

О том, что такое Surface, мы говорим в уроке 132.
В двух словах — это компонент, на который выводится изображение.
Объявляем еще несколько переменных: логическую running, которой будем присваивать true в процессе записи.

Далее параметры виртуального экрана, разрешение установим, а плотность пока не указываем.

Далее идет метод IBinder onBind, который позволяет приложению подключиться к сервису и взаимодействовать с ним через возвращаемый объект RecordBinder. Подробнее в уроке 97

Теперь методы жизненного цикла сервиса.

Метод onStartCommand срабатывает при старте сервиса методом startService, который вызывается в классе RecordApplication. Он возвращает флаг START_STICKY – это значит, сервис будет перезапущен, если будет убит системой.

В методе onCreate? который вызывается в начале работы сервиса, создаем отдельный поток serviceThread с использованием класса HandlerThread. Это вспомогательный класс для запуска нового потока, который имеет лупер, который может использоваться для создания обработчиков классов. На вход передаем произвольное имя потока и флаг THREAD_PRIORITY_BACKGROUND — Стандартный приоритет фоновых потоков.

Далее стартуем поток, сбрасываем значение переменной running и создаем mediaRecorder.

В методе onDestroy, который вызывается при остановке сервиса, просто вызываем метод суперкласса.

Метод setMediaProject будет вызываться в MainActivity и передавать объект mediaProjection.

Далее геттер для переменной running.

Метод setConfig устанавливает параметры виртуального экрана.

В методе startRecord проверяем, если объект mediaProjection не существует и переменная running имеет значение true, возвращаем false.
Вызываем здесь методы initRecorder и createVirtualDisplay, которые рассмотрим позже, стартуем запись вызовом mediaRecorder.start(); присваиваем переменной running = true; и возвращаем true.

Метод stopRecord выполняет обратные операции, останавливает запись и перезапускает mediaRecorder в состояние ожидания. Освобождаем virtualDisplay и останавливаем mediaProjection.

Теперь метод createVirtualDisplay, который вызывается выше в методе startRecord. Здесь выполняется создание виртуального экрана через метод mediaProjection.createVirtualDisplay, которому передается произвольное имя дисплея, его параметры, флаг VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, который позволяет отразить содержимое приватного дисплея, если его содержимое не отображается, и Surface.

Теперь в методе initRecorder, который вызывается выше в методе startRecord работаем с объектом mediaRecorder.
Метод setAudioSource устанавливает источник звука, используемый для записи.
setVideoSource задает источник видео, который будет использоваться для записи.
setOutputFormat устанавливает формат получаемого файла записи.
setOutputFile устанавливает целевое местоположение и имя файла записи.
setVideoSize устанавливает размер видео.
setVideoEncoder определяет кодировщик видео.
setAudioEncoder определяет кодировщик аудио.
setVideoEncodingBitRate устанавливает битрейт файла записи, здесь жестко прописано постоянное значение, равное 5 Мбит.
setVideoFrameRate задает частоту кадров, здесь 30 кадров в секунду.
Метод prepare() подготавливает mediaRecorder для записи и кодирования данных. Выполняем его в блоке try…catch с перехватом ошибки IOException.

Далее в методе getsaveDirectory задаем путь для сохранения файла записи и показываем тост об этом пользователю.

Ниже здесь создаем внутренний класс RecordBinder, это биндер для связи и взаимодействия с сервисом в приложении.

В классе MainActivity.java объявлены константы _REQUEST_CODE с произвольными значениями. Эти константы используются в интентах и запросах разрешений, чтобы отличать друг от друга пришедшие результаты. Подробнее об этом смотрите урок 30

Далее объявляем переменные классов MediaProjectionManager — Управляет получением определенных типов токенов MediaProjection.

MediaProjection вы уже знаете — это токен, предоставляющий приложению возможность захватить содержимое экрана и/или записывать аудио системы.

Также объявляем экземпляр нашего сервиса RecordService и обычную кнопку.

В методе onCreate получаем экземпляр MediaProjectionManager для управления сессиями отображения медиа-данных.

Создаем кнопку, по умолчанию неактивную, и слушатель для нее.
В методе onClick по нажатию кнопки будем вызывать метод recordService.stopRecord, в случае,если запись идет. Иначе создаем интент с projectionManager.createScreenCaptureIntent() и отправляем его методом startActivityForResult.

Далее идут запросы разрешений на запись в память устройства и на запись аудио.

Еще здесь мы создаем еще один интент для запуска сервиса и передаем его методу bindService, который выполняет привязку сервиса к приложению, а если сервис не работает, то стартует его предварительно.

В методе onDestroy отвязываем сервис.

Метод onActivityResult получает результат вызова метода startActivityForResult, где мы отправляем captureIntent и RECORD_REQUEST_CODE.
Если запрос прошел успешно, создадим объект MediaProjection, полученный от успешного запроса захвата экрана. Он будет иметь значение NULL, если результат от startActivityForResult() будет не RESULT_OK.

Вызываем метод recordService.startRecord(); и меняем текст кнопки на «Остановить запись»

Метод onRequestPermissionsResult — это обратный вызов для результата запроса разрешений. Этот метод вызывается для каждого вызова метода requestPermissions. Вполне возможно, что процесс запроса разрешений с пользователем был прерван. В этом случае вы получите пустые разрешения и массивы, которые должны рассматриваться как отмена.

Далее создается экземпляр интерфейса ServiceConnection с реализацией его методов onServiceConnected и onServiceDisconnected. Интерфейс служит для мониторинга состояния сервиса.
Второй метод оставляем пустым, а в первом методе onServiceConnected, который вызывается в случае подключения приложения к сервису через биндер, создаем объект класса DisplayMetrics, который служит для определения реальных параметров экрана устройства — разрешения и плотности.

Получаем экземпляр recordService и через его метод setConfig устанавливаем параметры виртуального экрана, передавая полученные значения.
Здесь же делаем кнопку активной и меняем текст на ней.

Запускаем приложение и наслаждаемся его работой.

Как создать приложение для записи экрана андроид-смартфона обновлено: Январь 1, 2017 автором: admin

  1. Не могу понять:
    HandlerThread serviceThread = new HandlerThread("service_thread",
    android.os.Process.THREAD_PRIORITY_BACKGROUND);
    serviceThread.start();

    Зачем? Можете объяснить?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*
*
Website