androidandroid-mediaplayermpeg-4mediaextractorandroid-mediacodec

Get MPEG-4 video stream's profile programmatically on Android


Is there any way to get MPEG-4 video fils's profile-code using standard Android API?

Sample profile-codes are: baseline, main, high and so on.

I don't want to include ffmpeg binary in the android app just to get this information.

I found reference of list of profiles in MediaCodecInfo.CodecProfileLevel class. Can any body confirm if this is the one I should be using?

Here is an example screenshot of video info taken from MX Player app Sample data with video profile



Solution

  • Profile code can be found using MediaExtractor

    Based on API documentation it seems that the encoding profile-code is only available from API level 24 (Nougat) and up.

    Here is method I wrote to extract the profile code, feel free to modify to meet your need.

    /**
     * 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;
    }
    

    And here is sample code on how to use it.

    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.");
    
    }
    

    Hope it helps. If you have other way which supports at least Jelly Bean API level 16 let me know.


    For reference, here is a snapshot of MediaFormat of a video track taken from Nougat 7.1.1 device. (NOTE: Lower level API will return less attributes)

    MediaFormat Hash Map - Snapshot

    Other references: