Skip to content

Instantly share code, notes, and snippets.

@aelqsimi
Last active January 3, 2024 07:31
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aelqsimi/f773d63fd5f234df7892276e3b05e5f8 to your computer and use it in GitHub Desktop.
Save aelqsimi/f773d63fd5f234df7892276e3b05e5f8 to your computer and use it in GitHub Desktop.
Fetch mediacodec infos and get capabilities and supported features. The output is writed to the log and a file at the same time
package com.example.nativemediacodectest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.ektacom.nativemediacodectest.Activities.LogActivity;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback;
import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_IntraRefresh;
import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_SecurePlayback;
import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback;
public class TestMediaCodecInfoAsyncTask extends AsyncTask<String, String, String> {
private String TAG = TestMediaCodecInfoAsyncTask.class.getName();
private WeakReference<ProgressBar> progressBarRef;
private WeakReference<Activity> activityRef;
public TestMediaCodecInfoAsyncTask(ProgressBar progressBar, Activity activity){
this.progressBarRef = new WeakReference<>(progressBar);
this.activityRef = new WeakReference<>(activity);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
ProgressBar progressBar = progressBarRef.get();
progressBar.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(String path) {
super.onPostExecute(path);
ProgressBar progressBar = progressBarRef.get();
progressBar.setVisibility(View.INVISIBLE);
Activity mActivity = activityRef.get();
Intent intent = new Intent(mActivity, LogActivity.class);
intent.putExtra("path",path);
mActivity.startActivity(intent);
}
/**
* Override this method to perform a computation on a background thread. The
* specified parameters are the parameters passed to {@link #execute}
* by the caller of this task.
* <p>
* This method can call {@link #publishProgress} to publish updates
* on the UI thread.
*
* @param args The parameters of the task.
* @return A result, defined by the subclass of this task.
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
@Override
protected String doInBackground(String... args) {
String name = args[0];
String path = "";
if(name.length()>0) {
path = Utils.codecsPath +name+".txt";
MediaCodecList list = new MediaCodecList(MediaCodecList.ALL_CODECS);
MediaCodecInfo[] codecInfos = list.getCodecInfos();
try (FileOutputStream stream = new FileOutputStream(path)) {
for (MediaCodecInfo info : codecInfos) {
if (name.equalsIgnoreCase(info.getName())) {
publishProgress("=== " + info.getName() + " ===\n");
stream.write(("=== " + info.getName() + " ===\n").getBytes());
boolean isEncoder = info.isEncoder();
publishProgress("is Encoder = " + isEncoder);
stream.write(("is Encoder = " + isEncoder + "\n").getBytes());
// list codec support media types
String[] types = info.getSupportedTypes();
for (String type : types) {
publishProgress("Supported types = " + type);
stream.write(("Supported types = " + type + "\n").getBytes());
// max instances
/* TODO API >= 23 */
int max = -1;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
max = info.getCapabilitiesForType(type).getMaxSupportedInstances();
publishProgress("Max instances for " + type + " = " + max);
stream.write(("Max instances for " + type + " = " + max + "\n").getBytes());
stream.write(("---\n\n").getBytes());
}
publishProgress("Supported colors for " + type + " :");
stream.write(("Supported colors for " + type + " :\n").getBytes());
// colors
Class<MediaCodecInfo.CodecCapabilities> c = MediaCodecInfo.CodecCapabilities.class;
int colors[] = info.getCapabilitiesForType(type).colorFormats;
for (int color : colors) {
for (Field f : c.getDeclaredFields()) {
int mod = f.getModifiers();
if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
if (String.valueOf(color).equalsIgnoreCase(String.valueOf(f.get(null)))) {
publishProgress(" Support color number " + color + " aka " + f.getName());
stream.write((" Support color number " + color + " aka " + f.getName() + "\n").getBytes());
stream.write(("\n").getBytes());
}
}
}
}
stream.write(("---\n\n").getBytes());
// get capabilities of the given media type of the current codec
MediaCodecInfo.CodecCapabilities capabilitiesForType = info.getCapabilitiesForType(type);
publishProgress("Default format = " + capabilitiesForType.getDefaultFormat().toString());
stream.write(("Default format = " + capabilitiesForType.getDefaultFormat().toString() + "\n").getBytes());
stream.write(("---\n\n").getBytes());
/* TODO API >= 24 */
publishProgress("Features :");
stream.write(("Features :\n").getBytes());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
publishProgress(" IntraRefresh support = " + capabilitiesForType.isFeatureSupported(FEATURE_IntraRefresh));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
stream.write((" IntraRefresh support = " + capabilitiesForType.isFeatureSupported(FEATURE_IntraRefresh) + "\n").getBytes());
stream.write(("---\n\n").getBytes());
}
MediaCodecInfo.VideoCapabilities videoCapabilities = capabilitiesForType.getVideoCapabilities();
if (videoCapabilities != null) {
// get video capabilities
publishProgress("Video capabilities :");
stream.write(("Video capabilities :\n").getBytes());
if(isEncoder) {
publishProgress(" BitrateRange = " + videoCapabilities.getBitrateRange());
stream.write((" BitrateRange = " + videoCapabilities.getBitrateRange() + "\n").getBytes());
}
publishProgress(" SupportedHeights = " + videoCapabilities.getSupportedHeights());
stream.write((" Supported Heights = " + videoCapabilities.getSupportedHeights() + "\n").getBytes());
publishProgress(" SupportedWidths = " + videoCapabilities.getSupportedWidths());
stream.write((" Supported Widths = " + videoCapabilities.getSupportedWidths() + "\n").getBytes());
publishProgress(" HeightAlignment = " + videoCapabilities.getHeightAlignment());
stream.write((" Height Alignment = " + videoCapabilities.getHeightAlignment() + "\n").getBytes());
publishProgress(" Width Alignment = " + videoCapabilities.getWidthAlignment());
stream.write((" Width Alignment = " + videoCapabilities.getWidthAlignment() + "\n").getBytes());
stream.write(("---\n\n").getBytes());
// get profile & level capabilities
publishProgress("Video capabilities profile levels:");
stream.write(("Video capabilities profile levels:\n").getBytes());
String s1 = info.getName().substring(info.getName().indexOf(".", info.getName().indexOf(".") + 1) + 1);
String codecName = s1.substring(0, s1.indexOf("."));
Class<MediaCodecInfo.CodecProfileLevel> cc = MediaCodecInfo.CodecProfileLevel.class;
for (int k = 0; k < capabilitiesForType.profileLevels.length; k++) {
for (Field f : cc.getDeclaredFields()) {
int mod = f.getModifiers();
if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
if ((f.getName().toLowerCase().contains(codecName) || f.getName().toLowerCase().contains(type.substring(type.indexOf("/") + 1, type.length()))) && f.getName().toLowerCase().contains("profile")) {
if (String.valueOf(capabilitiesForType.profileLevels[k].profile).equalsIgnoreCase(f.get(null) + "")) {
publishProgress(" profile = " + capabilitiesForType.profileLevels[k].profile + " aka " + f.getName());
stream.write((" profile = " + capabilitiesForType.profileLevels[k].profile + " aka " + f.getName() + "\n").getBytes());
for (Field f2 : cc.getDeclaredFields()) {
int mod2 = f2.getModifiers();
if (Modifier.isStatic(mod2) && Modifier.isPublic(mod2) && Modifier.isFinal(mod2)) {
if ((f2.getName().toLowerCase().contains(codecName) || f2.getName().toLowerCase().contains(type.substring(type.indexOf("/") + 1, type.length()))) && !f2.getName().toLowerCase().contains("profile")) {
if (String.valueOf(capabilitiesForType.profileLevels[k].level).equalsIgnoreCase(f2.get(null) + "")) {
publishProgress(" level = " + capabilitiesForType.profileLevels[k].level + " aka " + f2.getName());
stream.write((" level = " + capabilitiesForType.profileLevels[k].level + " aka " + f2.getName() + "\n").getBytes());
}
}
}
}
}
}
}
}
}
}
if(!isEncoder) {
//Valid features
publishProgress("Features :");
stream.write(("Features :\n").getBytes());
publishProgress(" Adaptive playback support = " + capabilitiesForType.isFeatureSupported(FEATURE_AdaptivePlayback));
stream.write((" Adaptive playback support = " + capabilitiesForType.isFeatureSupported(FEATURE_AdaptivePlayback) + "\n").getBytes());
publishProgress(" Secure playback support = " + capabilitiesForType.isFeatureSupported(FEATURE_SecurePlayback));
stream.write((" Secure playback support = " + capabilitiesForType.isFeatureSupported(FEATURE_SecurePlayback) + "\n").getBytes());
publishProgress(" Tunneled playback support = " + capabilitiesForType.isFeatureSupported(FEATURE_TunneledPlayback));
stream.write((" Tunneled playback support = " + capabilitiesForType.isFeatureSupported(FEATURE_TunneledPlayback) + "\n").getBytes());
}
}
publishProgress(
"=============\n");
}
}
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return path;
}
protected void onProgressUpdate(String... log) {
Log.i(TAG, log[0]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment