Используйте MediaCodec и MediaExtractor для декодирования и кодирования видео.

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

Я планирую управлять этим, используя getFrameAtTime и сохраняя его в последовательность изображений. Затем я могу изменить изображения в последовательности и закодировать их обратно в фильм. Но у меня есть две проблемы с этим:

  • Во-первых, как я читал, getFrameAtTime предназначен для создания эскизов и не гарантирует возврата правильного кадра. Из-за этого видео тормозит.
  • Во-вторых, сохранение изображений и их повторное чтение занимает много времени.

Я читал, что правильный способ декодирования — с помощью MediaExtractor, это нормально, но у меня есть только примеры для рендеринга непосредственно в surfaceView. Есть ли способ преобразовать outputBuffer в растровое изображение?

Мне нужно, чтобы он работал с уровнем API 16 и выше.


person G.T.    schedule 09.12.2013    source источник


Ответы (2)


Вы можете найти коллекцию полезных примеров на сайте bigflake.

В частности, ExtractMpegFramesTest демонстрирует, как декодировать файл .mp4 в Bitmap, а DecodeEditEncodeTest декодирует и повторно кодирует поток H.264, изменяя кадры с помощью шейдера GLES.

Во многих примерах используются функции, введенные в API 18, такие как ввод Surface в MediaCodec (что позволяет избежать ряда проблем с цветовым форматом) и MediaMuxer (что позволяет преобразовывать необработанный элементарный поток H.264, выходящий из MediaCodec, в файл .mp4). Некоторые устройства позволяют извлекать видео в данные YUV в ByteBuffer, изменять их и перекодировать, но другие устройства извлекают в проприетарные цветовые форматы YUV, которые могут быть отклонены API 16 версии MediaCodec.

Я бы рекомендовал кодировать для API 18 (Android 4.3 "Jellybean" MR2) или более поздней версии.

person fadden    schedule 09.12.2013
comment
Ну, проблема в том, что я уже видел этот сайт, но, к сожалению, я должен сделать это для API lvl 16. И хотя он говорит, что ExtractMpegFramesTest.java требует API 16, когда я пытаюсь его построить, он требует как минимум 17... Так что это не вариант. - person G.T.; 10.12.2013
comment
Тогда вам предстоит тяжелая битва. Должен ли он работать в целом или он просто создается для конкретного устройства? (Я проверю в ExtractMpegFramesTest — я не думал, что ему нужно что-то от 17+.) - person fadden; 10.12.2013
comment
Что ж, проблема в том, что он должен быть универсальным и API уровня 16+ ... Я получил решение getFrameAtTime для работы без сохранения в png и ускорения его, как это довольно много раз, но все же у меня может быть проблема, что он извлечет некоторые кадров два раза, из-за чего видео будет тормозить, и я до сих пор понятия не имею, как добавить к нему звук. Поэтому любое предложение по разделению видео на растровые изображения и созданию нового видеофайла со звуком будет оценено по достоинству, но оно должно работать с 16+. - person G.T.; 11.12.2013
comment
Пример ExtractMpegFramesTest был изменен для работы с API 16 (требуется EGL 1.0, а не EGL 1.4 — см. заголовок stackoverflow.com/questions/20495863/ ). Невозможно создать файл .mp4 (только видео или видео+аудио), пока API 18 не представил класс MediaMuxer, поэтому, если вам это нужно, вы можете исследовать внешние библиотеки (возможно, ffmpeg). - person fadden; 11.12.2013
comment
@fadden привет, я пытаюсь заставить работать пример ExtractMpegFramesTest, но вызов SurfaceTexture onFrameAvailable() никогда не выполняется или выполняется слишком поздно. Я добавил вопрос здесь - stackoverflow .com/questions/22457623/ - person manixrock; 17.03.2014
comment
В конце концов я сделал это с ffmpeg, работает как шарм. - person G.T.; 02.02.2015

Многие говорят, что метод onFrameAvailable() никогда не вызывается. Что ж, прослушиватель должен находиться в другом потоке, отличном от основного потока. Чтобы установить прослушиватель, сделайте следующее: (где это прослушиватель класса, который реализует SurfaceTexture.IOnFrameAvailableListener):

mSurfaceTexture.SetOnFrameAvailableListener(this);
person Gabriel Bursztyn    schedule 12.01.2016