- Кодеки воспроизведения мультимедиа для Android
- MX Player кодек (ARMv7)
- MX Player кодек (ARMv7 NEON)
- MX Player кодек (x86)
- DDB2 Codec Pack
- AC3 Codec
- MediaCodec или понимаем как хотим
- Что такое MediaCodec?
- Зачем нужен MediaCodec?
- Как кодировать?
- Подготовка
- Цикл кодирования
- Освобождение ресурсов
- Что дальше?
- Как декодировать?
- Конфигурация
- Декодирование сэмпла
- Цикл декодирования
- Android Camera2 API от чайника, часть 3. Media Codec и стрим видео по UDP
- Что нам для этого нужно?
- И закончим прицеплением Media Codec
- Теперь пойдём искать нужный адрес на компьютере
- Как же так?
Кодеки воспроизведения мультимедиа для Android
MX Player кодек (ARMv7)
Специфический кодек по ряду причин. Типология ARMv7 на сегодня представляет собой предпоследнее поколение процессоров, однако внутри процессоры такой архитектуры различаются по ряду признаков – например, набору инструкций и типу ядер. От этого и зависит выбор кодека для проигрывателя.
Собственно, указанный кодек предназначен в первую очередь для устройств с процессором NVIDIA Tegra 2 (например, смартфонов Motorola Atrix 4G или планшета Samsung GT-P7500 Galaxy Tab 10.1). Этот процессор печально известен своими проблемами воспроизведения HD-видео, и указанный кодек для MX Player поможет их решить. Естественно, понадобится установить сам MX Player из Google Play Маркета. В редких случаях кодек может быть несовместим с устройством, так что имейте этот нюанс в виду.
MX Player кодек (ARMv7 NEON)
По сути, содержит в себе вышеуказанное ПО для декодирования видео плюс компоненты, которые поддерживают инструкции NEON, более производительные и энергоэффективные. Как правило, для устройств с поддержкой NEON установка дополнительных кодеков не требуется.
Версии ЭмИкс Плеера, которые установлены не из Google Play Маркета, часто не обладают таким функционалом – в этом случае компоненты приходится качать и устанавливать отдельно. Некоторые устройства на редких процессорах (например, Broadcom или TI OMAP) требуют ручной установки кодеков. Но повторимся – для большинства устройств этого не требуется.
MX Player кодек (x86)
Большинство современных мобильных девайсов изготовлены на базе процессоров с архитектурой ARM, однако некоторые производители экспериментируют с преимущественно настольной архитектурой x86. Единственным производителем таких процессоров является компания Intel, чьи продукты долгое время устанавливались в смартфоны и планшеты ASUS.
Соответственно, этот кодек и предназначен в основном для таких устройств. Не вдаваясь в подробности, отметим, что работа Android на таких ЦП очень специфична, и пользователь будет вынужден установить соответствующий компонент проигрывателя, чтобы тот смог корректно воспроизводить видеоролики. Иногда может потребоваться ручная настройка кодека, но это уже тема для отдельной статьи.
DDB2 Codec Pack
В отличие от вышеописанных, этот набор инструкций кодирования и декодирования предназначен для аудиоплеера DDB2 и включает в себя компоненты для работы с такими форматами, как APE, ALAC и ряда малораспространенных звуковых форматов, в том числе и сетевого вещания.
Отличается этот пак кодеков и причинами своего отсутствия в основном приложении – их нет в ДДБ2 ради удовлетворения требований лицензии GPL, по которой и распространяются приложения в Google Play Маркете. Однако воспроизведение некоторых тяжелых форматов даже при наличии этого компонента все равно не гарантируется.
AC3 Codec
И плеер, и кодек, способные проигрывать аудиофайлы и звуковые дорожки фильмов в формате AC3. Само приложение может функционировать как проигрыватель видео, причем благодаря идущим в комплекте декодирующим компонентам отличается «всеядностью» форматов.
Как видеоплеер приложение представляет собой решение из разряда «ничего лишнего», и может быть интересным только как замена обычно малофункциональным стоковым проигрывателям. Как правило, с большинством устройств работает корректно, однако на некоторых девайсах могут наблюдаться проблемы – в первую очередь это касается машинок на специфических процессорах. Отсутствует в Плей Маркете, доступно на сторонних сервисах.
Android во много отличается от Windows в плане работы с мультимедиа — большинство форматов будет читаться, как говорится, «из коробки». Необходимость в кодеках появляется только в случае нестандартного «железа» или версии проигрывателя.
Помимо этой статьи, на сайте еще 12474 инструкций.
Добавьте сайт Lumpics.ru в закладки (CTRL+D) и мы точно еще пригодимся вам.
Отблагодарите автора, поделитесь статьей в социальных сетях.
Источник
MediaCodec или понимаем как хотим
С выходом Android 4.3 (API 18), Google привнесла долгожданный компонент под названием MediaCodec. Класс был открыт публике с выходом API 16, но для нормального использования и поддержки в Android системе требуется минимальный уровень API 18.
Материал рассчитан на опытного Android разработчика. Я попробую объяснить и показать примеры кодирования видео на лету с использованием Surface как входа и выхода потока данных. Если интересно, прошу под кат.
Что такое MediaCodec?
MediaCodec class can be used to access low-level media codec, i.e. encoder/decoder components.
MediaCodec класс может быть использован для доступа к низко-уровневому медиа кодеку, т.е. кодеру/декодеру
В принципе это кодер или декодер который манипулирует буферами данных. Если мы будем смотреть на формат H264, он же video/avc, то по сути буфер будет хранить NAL кадры и т.д.
Зачем нужен MediaCodec?
В большинстве случаев Android разработчики будут использовать VideoView, MediaPlayer с SurfaceView и этого вполне достаточно. Но как только речь зайдет о создании видео потока для дальнейшей передачи куда-либо, у нас не так много вариантов. Тут нам поможет MediaCodec.
Как кодировать?
MediaCodec дает возможность создать Surface объект для принятия данных для кодера. Я разделил логику кодирвоания на три этапа: подготовка, цикл кодирования, освобождение ресурсов.
Так как процесс кодирования по сути простой цикл обработки буферов данных, нам потребуется создать отдельный поток, который будет представлять непосредственно видео кодер.
Подготовка
Прежде чем приступить к кодированию нам потребуется описать формат и конфигурацию видео на выходе, создать сам кодер и получить Surface объект для ввода данных кодеру.
Цикл кодирования
mBufferInfo и data хранят данные о кадре(ах) который по сути может быть передан по сети или записаны в файл и др. Эти же данные могут быть декодированы h264 кодеком, чтобы получить изображение.
Важно заметить, что BufferInfo класс имеет поле flags. По сути может содержать три флага: BUFFER_FLAG_CODEC_CONFIG, BUFFER_FLAG_END_OF_STREAM и BUFFER_FLAG_SYNC_FRAME.
Давайте рассмотрим каждый из флагов:
- BUFFER_FLAG_CODEC_CONFIG флаг сигнализирует о том, что буфер данных содержит конфигурацию кодека. Первый доступный буфер кодера должен содержать данный флаг. К примеру для нашего H264 это может быть csd-0, который может быть использован во время декодирования при создании видео формата кодека.
- BUFFER_FLAG_END_OF_STREAM флаг сигнализирует о том, что достигнут конец потока данных. Я не уверен на счет использования данного флага во время кодирования, т.к. мы контролируем поток данных.
- BUFFER_FLAG_SYNC_FRAME флаг сигнализирует о том, что кадр является I-Frame. Важно использовать при передачи в файл или по сети, к примеру по протоколу RTP.
Освобождение ресурсов
Тут все просто, останавливаем кодер и освобождаем системные ресурсы.
Что дальше?
Имея Surface возможны как минимум три пути ввода данных: MediaPlayer (Camera?), OpenGL, Canvas. По примеру использования рендера в SurfaceView возможно создать подобный цикл на основе нашего Surface:
Вариантов использования может быть несколько. Еще интересный момент, Surface является Parcelable, что дает возможность передачи через Binder в другие процессы, таким образом ваш кодер может находиться в одном процессе, когда рендер в другом.
Как декодировать?
Процесс декодирования схожий на процесс кодирования. Мы так же манипулируем буферами данных. Данный процесс я разделил на четыре части: конфигурация, декодирование сэмпла, цикл декодирования, освобождение ресурсов.
Я опущу детали создания класса потока, архитектура схожа на ту, которую я использовал в процессе кодирования.
Конфигурация
Процесс конфигурации критичен, иначе кодек невозможно создать и использовать для декодирования поступающих данных.
Важно заметить, мы обязаны знать на какой Surface нужно выводить изображение, так же ширину и высоту изображения. csd-0 так же важен на этом этапе, как было описанно ранее в процессе кодирования, первый буфер данных должен иметь флаг BUFFER_FLAG_CODEC_CONFIG, этот буфер и является csd-0 который необходимо передать на этапе конфигурации декодера.
Декодирование сэмпла
Как только кодированные данные доступны их необходимо передавать декодеру. Мы запрашиваем буфер декодера, как только он доступен, передаем наши данные.
Если данные были переданы по сети, к примеру RTP протокол, необходимо учесть, что сэмплы передаются последовательно, иначе возможны артифакты при выводе изображения. На данном этапе, само изображение не готово для вывода на Surface, мы просто передаем известные данные декодеру.
Цикл декодирования
Цикл декодирования включает в себя запрос буфера данных который доступен на выходе, если доступен, можно его необходимо вернуть системе и сообщить если мы желаем рендерить данный кадр на Surface.
Источник
Android Camera2 API от чайника, часть 3. Media Codec и стрим видео по UDP
Итак, со съемками фоточек и записью видео при помощи Camera2 API мы вроде бы, разобрались. Осталось только научиться передавать видеопоток c Android устройства страждущим получателям извне. Конечной целью, как уже неоднократно ранее говорилось, является интеллектуализация роботелеги — ставим на неё смартфон и так сказать, превращаем обезьяну в человека. В этом нам поможет Media Codec. И конечно, новое Camera2 API.
Кому интересно, прошу под кат.
Детали о проекте с роботележкой можно найти здесь, а мы пока займемся непосредственно стримингом видео с неё (вернее с прицепленного к ней Android смартфона) на персональную электронно-вычислительную машину.
Что нам для этого нужно?
Для того чтобы передать видео поток с экрана смартфона куда-либо ещё, как известно, его (поток) сначала необходимо преобразовать в подходящий ужатый формат (передавать покадрово выйдет слишком толсто), поставить time-stamps (временные метки) и отправить в бинарном виде получателю. Который произведёт обратную операцию декодирования.
Как раз этими низкоуровневыми чёрными делами и занимается класс Media Codec с 2013 года, с даты выхода Аndroid 4.3.
Другое дело, что раньше подступиться к кодированию видео, в отличие от сегодняшнего дня было не так-то просто. Чтобы вытащить картинку с камеры надо было использовать тонны загадочного кода в котором, как в заклинаниях якутских шаманов, единственная неточность могла привести к полному краху приложения. Добавьте к этому ещё предыдущее Camera API, где вместо готовых коллбэков приходилось ручками самостоятельно писать разные synchronized, а это занятие, скажем так, не для слабых духом.
И главное, издалека смотришь на рабочий код, вроде бы в общих чертах всё ясно. Начинаешь переносить по частям в свой проект — сыпется непонятно почему. А скорректировать не получается, потому что в деталях уже разобраться тяжело.
Да и от сплошных deprecated как-то не по себе. Короче говоря, непорядок
К счастью, для непонятливых гуглостроители ввели волшебную концепцию поверхности Surface, работая с которой, можно избежать низкоуровневых деталей. Какой ценой и что при этом теряет разработчик, мне как неспециалисту понять сложно, но зато теперь мы чуть ли не буквально можем сказать: «Android, возьми эту Surface на которую отображается видео с камеры и ничего там не меняя, ну вот как есть, закодируй и отправь дальше». И самое удивительное, что это работает. А с новым Camera2 API программа и сама знает, когда данные отправлять, коллбэки ж новые появились!
Так что теперь закодировать видео — раз плюнуть. Чем мы сейчас и займёмся.
Берём код из первой статьи и как обычно выкидываем из него всё кроме кнопочек и инициализации камеры.
И закончим прицеплением Media Codec
В прошлом посте мы выводили на Surface изображение с камеры и с него же писали видео при помощи MediaRecorder. Для этого мы просто указывали оба компонента в списке Surface.
Здесь то же самое, только вместо mMediaRecorder указываем:
Получается, что-то типа:
Что такое mEncoderSurface? А это та самая Surface, с которой будет работать Media Codec. Только для начала надо их обоих инициализировать примерно таким образом.
Теперь остается прописать единственный коллбэк. Когда Media Codec вдруг ощутит, что очередные данные для дальнейшей трансляции готовы, он нас об этом известит именно через него:
Байтовый массив outDate — это настоящее сокровище. В нём уже готовые кусочки закодированного в формате H264 видеопотока, с которым мы теперь можем делать всё, что захотим.
Некоторые кусочки может быть великоваты для передачи по сети, ну да ничего, система, если надо их порубит ещё сама и отправит дальше получателю.
Но если сильно страшно, то покромсать можно самому, впихнув такой фрагмент
Но нам пока надо убедиться воочию, что данные в буфере это действительно видеопоток в формате H264. Поэтому, давайте мы их отправим в файл:
Пропишем в сетапе:
А в коллбэке где буфер:
Открываем приложение, жмем кнопку: «ВКЛЮЧИТЬ КАМЕРУ И СТРИМ». Начинается автоматически запись. Ждем немного и давим кнопку остановки.
Сохраненный файл штатно скорее всего не проиграется, поскольку формат не MP4, но если открыть его VLC плеером или сконвертить онлайн каким нибудь ONLINE CONVERT, то мы убедимся, что находимся на правильном пути. Правда изображение лежит на боку, но это поправимо.
Вообще, для каждого события записи, фотографирования или стрима, лучше, конечно, открывать каждый раз новую сессию, а старую закрывать. То есть, сначала мы включаем камеру и запускаем голое превью. Потом, если надо сделать снимок, превью закрываем и открываем превью, но уже с пристегнутым Image Reader. Если переходим на запись видео, то закрываем текущую сессию и запускаем сессию с превью и прицепленным к нему Media Recorder. Я этого не делал, чтобы не страдала наглядность кода, а вам решать, как удобнее самим.
А вот и сам код целиком.
И не забудьте про разрешения в манифесте.
Итак, мы убедились, что Media Codec работает. Но использовать его для записи видео в файл как-то бездуховно. С такой задачей гораздо лучше справится Media Recorder, да ещё и звук добавит. Поэтому файловую часть мы снова выкинем и добавим блок кода для стриминга видео в сеть по udp протоколу. Это тоже очень просто.
Сначала инициализируем UDP практически сервер.
А в том же коллбэке, где мы отправляли данные по готовности в поток для файла, отправим их теперь в виде дэйтаграмм в нашу домашнюю сеть (надеюсь она есть у всех?)
Казалось бы, но нет. Приложение при запуске скрашится. Видите-ли, системе не нравится, что в главном потоке мы отправляем всякие дэйтаграмм пакеты. Но для паники нет оснований. Во-первых мы хоть и в главном потоке, но работаем все равно асинхронно, то есть по срабатыванию коллбэка. Во-вторых отправка udp пакетов, такой же асинхронный процесс. Мы только говорим операционной системе, что неплохо было бы отправить пакетик, но, что мы всецело в этом деле полагаемся на неё. Поэтому, чтобы Android не бунтовал, то в начале программы добавим две строчки:
В общем и целом, получится следующая маленькая элегантная демонстрационная программка:
Не знаю, как у других, но на моем Red Note 7 даже видно, как скачут килобайты по нужному адресу
И таких udp сокетов можно наплодить множество, на сколько хватит пропускной способности сети. Главное, чтобы были адреса куда. Будет у вас широкоадресная рассылка.
Теперь пойдём искать нужный адрес на компьютере
Надо сказать, что не каждая компьютерная программа способна всосать и переварить видео поток формата H264 по единственному udp каналу без какой-либо дополнительной информации. Но некоторые могут. Это например крайне широко известный медиаплеер VLC. Это настолько крутая штука, что если начать описывать её возможности, то из статьи получится целая книга. Наверняка у вас она есть. Если нет, поставьте.
И судя по описанию команд для него, udp пакеты переварить этот плеер может.
Причём все эти source address и bind address, по идее и не нужны. Нужен только прослушиваемый порт.
И ещё, конечно, нужно не забыть про разрешение этот порт слушать (малварь же)
А вы знали, что Винда не дает сделать принтскрин с монитора ресурсов?
Или можно вообще брандмауэр отключить (не рекомендую)
Итак, преодолев эти тернии, запускаем VLC плеер с нашим адресом и наслаждаемся пустым экраном. Видео нет.
Как же так?
А вот так. У вас, наверно, стоит последняя версия VLC 3.08 Vetinari? Вот как раз, в этой версии udp объявлен deprecated и мало того выпилен нахрен.
Так-то логика разработчиков плеера понятна. Мало кому нужно использовать голый udp канал в наше время потому-что:
- Нормально работает только в домашней неперегруженной сети. Стоит вам выйти во внешний мир и ненумерованные дэйтаграммы начнут теряться и приходить не в том порядке, в котором их послали. А для видео декодера это очень неприятно.
- Незашифрован и легко компрометируется
Поэтому нормальные люди, конечно, используют протоколы более высокого уровня RTP и другие. То есть на пальцах — вы пишете сервер, который всё равно на низком уровне использует udp (для скорости), но параллельно обменивается управляющей информацией с клиентом кому он стримит видео. Какая там у него пропускная способность, не надо ли увеличить-уменьшить кэш для данных, какая детализация изображения оптимальна сейчас и так далее и тому подобное. Опять же звук тоже иногда нужен. А ему требуется, сами понимаете, синхронизация с видео.
Вон ребятам из Одноклассников даже пришлось свой протокол запилить для стриминга. Но у них задачи-то, конечно, гораздо более важные — рассылать видео с котиками десяткам миллионов домохозяек по всему миру. Там одним udp каналом не обойдёшься.
Но нам-то писать свой RTP сервер на андроиде как-то грустно. Наверное, можно найти даже готовый и даже бесплатный, но попробуем пока не усложнять сущностей. Просто возьмем версию VLC плеера, где udp стриминг ещё работал.
Устанавливаем вместо или рядом со старым (то есть новым VLC), как вам заблагорассудится.
Запускаем и снова видим пустой экран.
А все это потому, что мы явно не настроили использование кодека H264. Так-то VLC смог бы выбрать кодек автоматически, если бы имел дело с файлом (в настройках изначально, как раз и указан автоматический выбор). Но ему-то кидают байтовый поток по единственному каналу, а кодеков, которые VLC поддерживает десятки. Как ему разобраться, какой применить?
Поэтому устанавливаем кодек силой.
И вот теперь наслаждаемся трансляцией «живого» видео. Единственное, оно зачем-то лежит на боку, но это уже легко поправить в настройках видеоплеера.
А ещё можно просто запускать плеер из командной строки по такому ключу:
Источник