Программно получить профиль видеопотока MPEG-4 на Android

Есть ли способ получить код профиля видеофайлов MPEG-4, используя стандартный Android API ?

Примеры кодов профилей: baseline, main, high и так далее.

Я не хочу включать двоичный файл ffmpeg в приложение для Android только для того, чтобы получить эту информацию.

Я нашел ссылку на список профилей в классе MediaCodecInfo.CodecProfileLevel. Может ли кто-нибудь подтвердить, что это тот, который я должен использовать?

Вот пример снимка экрана с информацией о видео, полученной из приложения MX Player Пример данных с профилем видео


  • ОБНОВЛЕНИЕ № 1: я посмотрел в приложении MX Player, похоже, что они используют двоичный файл ffmpeg, поэтому я могу с уверенностью сказать, что они используют его для извлечения profile-code.
  • ОБНОВЛЕНИЕ № 2: я также изучил API ExoPlayer v1, у них также нет конкретного API. чтобы получить эту информацию.

person Hossain Khan    schedule 11.01.2017    source источник


Ответы (1)


Код профиля можно узнать с помощью MediaExtractor

На основании документации по API кажется, что кодировка profile-code доступен только для уровня API 24 (Nougat) и выше.

Вот метод, который я написал для извлечения кода профиля, не стесняйтесь изменять его в соответствии с вашими потребностями.

/**
 * Get video profile-code from video file.
 *
 * @param videoFilePath Path of the video file.
 * @return One of predefined AVC profiles from {@link MediaCodecInfo.CodecProfileLevel} when found, or {@code -1} if
 * Android API level does not support extracting profile data.
 */
@TargetApi(21)
public int getVideoEncodingProfile(final String videoFilePath) {
    int videoProfileCode = -1;

    File inputFile = new File(videoFilePath);
    if (!inputFile.canRead()) {
        throw new RuntimeException("Unable to read " + inputFile);
    }

    MediaExtractor mediaExtractor = new MediaExtractor();
    // Initialize MediaExtractor and configure/extract video information
    try {
        mediaExtractor.setDataSource(inputFile.toString());
    } catch (IOException e) {
        Log.e(TAG, "Unable to set MediaExtractor source.", e);
        throw new RuntimeException("Unable to set source.");
    }

    MediaFormat videoMediaFormat = findVideoMediaFormat(mediaExtractor);
    // MediaCodecInfo.CodecProfileLevel of the video track
    if (videoMediaFormat != null && videoMediaFormat.containsKey(MediaFormat.KEY_PROFILE)) {
        videoProfileCode = videoMediaFormat.getInteger(MediaFormat.KEY_PROFILE);
    } else {
        // Current API level does not support encoding profile information.
        Log.w(TAG, "Video profile code is not supported by current API level.");
    }

    mediaExtractor.release();
    mediaExtractor = null;

    return videoProfileCode;
}

/**
 * Find video MediaFormat from MediaExtractor.
 *
 * @param mediaExtractor The MediaExtractor which is used to find video track.
 * @return MediaFormat for video track, or {@code null} when video track is not found.
 */
private MediaFormat findVideoMediaFormat(final MediaExtractor mediaExtractor) {
    MediaFormat videoTrackMediaFormat = null;
    int totalTracks = mediaExtractor.getTrackCount();
    for (int i = 0; i < totalTracks; i++) {
        MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
        if ((trackFormat.containsKey(MediaFormat.KEY_MIME)
                && trackFormat.getString(MediaFormat.KEY_MIME).contains("video"))
                || (trackFormat.containsKey(MediaFormat.KEY_WIDTH) && trackFormat.containsKey(MediaFormat.KEY_HEIGHT))
                ) {
            videoTrackMediaFormat = trackFormat;
            break;
        }
    }
    return videoTrackMediaFormat;
}

И вот пример кода о том, как его использовать.

String TAG = "DEBUG"; // Define your tag
int profileCode = getVideoEncodingProfile(videoInfo.getLocalVideoPath());

switch (profileCode) {
    case MediaCodecInfo.CodecProfileLevel.AVCProfileBaseline:
        Log.d(TAG, "getVideoEncodingProfile() returned AVCProfileBaseline");
        break;
    case MediaCodecInfo.CodecProfileLevel.AVCProfileMain:
        Log.d(TAG, "getVideoEncodingProfile() returned AVCProfileMain");
        break;
    case MediaCodecInfo.CodecProfileLevel.AVCProfileExtended:
        Log.d(TAG, "getVideoEncodingProfile() returned AVCProfileExtended");
        break;
    case MediaCodecInfo.CodecProfileLevel.AVCProfileHigh:
        Log.d(TAG, "getVideoEncodingProfile() returned AVCProfileHigh");
        break;
    case MediaCodecInfo.CodecProfileLevel.AVCProfileHigh10:
        Log.d(TAG, "getVideoEncodingProfile() returned AVCProfileHigh10");
        break;
    case MediaCodecInfo.CodecProfileLevel.AVCProfileHigh422:
        Log.d(TAG, "getVideoEncodingProfile() returned AVCProfileHigh422");
        break;
    case MediaCodecInfo.CodecProfileLevel.AVCProfileHigh444:
        Log.d(TAG, "getVideoEncodingProfile() returned AVCProfileHigh444");
        break;
    default:
        Log.d(TAG, "getVideoEncodingProfile() returned unsupported profile code or code not found.");

}

Надеюсь, поможет. Если у вас есть другой способ, который поддерживает как минимум Jelly Bean уровень API 16, дайте мне знать.


Для справки, вот снимок MediaFormat видеодорожки, снятой с устройства Nougat 7.1.1. (ПРИМЕЧАНИЕ: API более низкого уровня будет возвращать меньше атрибутов)

Хэш-карта MediaFormat – моментальный снимок

Другие ссылки:

person Hossain Khan    schedule 13.01.2017