Выберите профиль H264 при кодировании с помощью MediaCodec и MTK Codec

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

На Lenovo Yoga 10 кодеком является OMX.MTK.VIDEO.ENCODER.AVC. Это кодирует видео как High Profile, что создает проблему для приемного устройства.

Я использую MediaCodec. Кажется, нет никакого способа установить профиль, который будет использоваться.

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

3 ответа

Что вы можете попробовать, это добавить ключ profile на ваш MediaFormat, со значением 1 (OMX_VIDEO_AVCProfileBaseline). Если вы сделаете это, вам, вероятно, также необходимо добавить ключ level со значением уровня, соответствующим вашему разрешению (со значением констант уровня OMX AVC).

Я не уверен, что этот кодек действительно выполняет запрошенное значение, но стоит попробовать.

Увидеть setupAVCEncoderParameters Функция в https://android.googlesource.com/platform/frameworks/av/+/6ade04174/media/libstagefright/ACodec.cpp для примера процедуры установки. Это выглядит для profile введите входные параметры (которые копируются из предоставленного вами MediaFormat), но если он присутствует, вам также необходимо указать level параметр, и какой уровень использовать зависит от вашего разрешения. См. https://android.googlesource.com/platform/frameworks/native/+/cde4b13a/include/media/openmax/OMX_Video.h для постоянных значений, которые можно использовать для параметров.

Но после проверки параметров профиля и уровня он также переопределяет профиль на базовый, независимо от того, что было установлено. Таким образом, либо эти строки были удалены с вашего устройства, либо кодировщик игнорирует h264type.eProfile поле в целом.

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

В качестве примера того, как выбрать подходящий уровень для вашего разрешения, взгляните на x264_validate_levels в http://git.videolan.org/?p=x264.git;a=blob;f=encoder/set.c;h=1a40b71284 (но уровень, передаваемый MediaFormat, должен быть выражен с помощью OMX_VIDEO_AVCLEVELTYPE константы).

Не уверен, поможет ли что-нибудь из этого, но стоит попробовать.

Вот фрагмент того, что я сделал в своем приложении:

mediaFormat.setInteger("profile", 8); // Profile HIGH
mediaFormat.setInteger("level", 0x200); // Level 3.1

А вот значения профиля, которые вы можете выбрать:

OMX_VIDEO_AVCProfileBaseline = 0x01,   /**< Baseline profile */
OMX_VIDEO_AVCProfileMain     = 0x02,   /**< Main profile */
OMX_VIDEO_AVCProfileExtended = 0x04,   /**< Extended profile */
OMX_VIDEO_AVCProfileHigh     = 0x08,   /**< High profile */
OMX_VIDEO_AVCProfileHigh10   = 0x10,   /**< High 10 profile */
OMX_VIDEO_AVCProfileHigh422  = 0x20,   /**< High 4:2:2 profile */
OMX_VIDEO_AVCProfileHigh444  = 0x40,   /**< High 4:4:4 profile */
OMX_VIDEO_AVCProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
OMX_VIDEO_AVCProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
OMX_VIDEO_AVCProfileMax      = 0x7FFFFFFF  

И уровни:

OMX_VIDEO_AVCLevel1   = 0x01,     /**< Level 1 */
OMX_VIDEO_AVCLevel1b  = 0x02,     /**< Level 1b */
OMX_VIDEO_AVCLevel11  = 0x04,     /**< Level 1.1 */
OMX_VIDEO_AVCLevel12  = 0x08,     /**< Level 1.2 */
OMX_VIDEO_AVCLevel13  = 0x10,     /**< Level 1.3 */
OMX_VIDEO_AVCLevel2   = 0x20,     /**< Level 2 */
OMX_VIDEO_AVCLevel21  = 0x40,     /**< Level 2.1 */
OMX_VIDEO_AVCLevel22  = 0x80,     /**< Level 2.2 */
OMX_VIDEO_AVCLevel3   = 0x100,    /**< Level 3 */
OMX_VIDEO_AVCLevel31  = 0x200,    /**< Level 3.1 */
OMX_VIDEO_AVCLevel32  = 0x400,    /**< Level 3.2 */
OMX_VIDEO_AVCLevel4   = 0x800,    /**< Level 4 */
OMX_VIDEO_AVCLevel41  = 0x1000,   /**< Level 4.1 */
OMX_VIDEO_AVCLevel42  = 0x2000,   /**< Level 4.2 */
OMX_VIDEO_AVCLevel5   = 0x4000,   /**< Level 5 */
OMX_VIDEO_AVCLevel51  = 0x8000,   /**< Level 5.1 */
OMX_VIDEO_AVCLevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
OMX_VIDEO_AVCLevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
OMX_VIDEO_AVCLevelMax = 0x7FFFFFFF  

Важно установить оба.

Я пробовал это на Nexus 9 с Nvidia HW Encoder. Единственное, что мне подходит, это выбрать кодировщик по имени. Я могу установить профиль на выбранное значение для уровня датчика всегда установлен на 13.

Обратите внимание, что если вы выбираете кодировщик по типу, он выбирает кодировщик Google и, как упоминалось выше, переводит профиль в базовый уровень.

Другие вопросы по тегам