在 Android 上以编程方式获取 MPEG-4 视频流的配置文件
Get MPEG-4 video stream's profile programmatically on Android
有什么方法可以使用标准 Android API 获取 MPEG-4 视频文件的 profile-code?
样本配置文件代码为:baseline
、main
、high
等等。
我不想为了获取此信息而在 android 应用程序中包含 ffmpeg
二进制文件。
我在 MediaCodecInfo.CodecProfileLevel class 中找到了配置文件列表的参考。任何人都可以确认这是否是我应该使用的吗?
这是从 MX Player 应用中截取的视频信息示例屏幕截图
- 更新 #1:我查看了 MX Player 应用程序,看起来他们使用
ffmpeg
二进制文件,所以我可以肯定地说他们使用它来提取 profile-code
。
- 更新 #2:我还调查了 ExoPlayer v1 API,他们似乎也没有特定的 API 来获取此信息。
可以使用 MediaExtractor
找到配置文件代码
根据 API documentation 看来编码 profile-code 仅适用于 API 24 级(牛轧糖)及以上。
这是我写的提取配置文件代码的方法,您可以随意修改以满足您的需要。
/**
* 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 将 return 更少的属性)
其他参考资料:
- 从桌面应用程序获取视频文件信息 - How to get h264 video info?
有什么方法可以使用标准 Android API 获取 MPEG-4 视频文件的 profile-code?
样本配置文件代码为:baseline
、main
、high
等等。
我不想为了获取此信息而在 android 应用程序中包含 ffmpeg
二进制文件。
我在 MediaCodecInfo.CodecProfileLevel class 中找到了配置文件列表的参考。任何人都可以确认这是否是我应该使用的吗?
这是从 MX Player 应用中截取的视频信息示例屏幕截图
- 更新 #1:我查看了 MX Player 应用程序,看起来他们使用
ffmpeg
二进制文件,所以我可以肯定地说他们使用它来提取profile-code
。 - 更新 #2:我还调查了 ExoPlayer v1 API,他们似乎也没有特定的 API 来获取此信息。
可以使用 MediaExtractor
根据 API documentation 看来编码 profile-code 仅适用于 API 24 级(牛轧糖)及以上。
这是我写的提取配置文件代码的方法,您可以随意修改以满足您的需要。
/**
* 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 将 return 更少的属性)
其他参考资料:
- 从桌面应用程序获取视频文件信息 - How to get h264 video info?