Android 如何检测是否支持MediaRecorder.AudioEncoder.HE_AAC?

Android 如何检测是否支持MediaRecorder.AudioEncoder.HE_AAC?,android,Android,我希望尽可能使用MediaRecorder.AudioEncoder.HE_AAC 但是,以下代码无法在某些设备中生成有效的音频文件,除非我使用MediaRecorder.AudioEncoder.AAC private void startMediaRecorder() { mediaRecorder = new MediaRecorder(); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); m

我希望尽可能使用MediaRecorder.AudioEncoder.HE_AAC

但是,以下代码无法在某些设备中生成有效的音频文件,除非我使用
MediaRecorder.AudioEncoder.AAC

private void startMediaRecorder() {
    mediaRecorder = new MediaRecorder();
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mediaRecorder.setAudioChannels(1);
    mediaRecorder.setAudioSamplingRate(8000);
    mediaRecorder.setAudioEncodingBitRate(32000);
    /*
    mediaRecorder.setAudioChannels(1);
    mediaRecorder.setAudioSamplingRate(44100);
    mediaRecorder.setAudioEncodingBitRate(96000);
     */
    mediaRecorder.setMaxDuration(RECORDING_MEDIA_RECORDER_MAX_DURATION);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
    } else {
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    }
    mediaRecorder.setOutputFile(getMicFilepath());

    mediaRecorder.setOnInfoListener((mediaRecorder, what, i1) -> {
        if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
            dismiss();
        }
    });

    try {
        mediaRecorder.prepare();
    } catch (IOException e) {
        Log.e(TAG, "", e);
    }

    mediaRecorder.start();
}

对于不支持HE_AAC的设备,不会发生崩溃,也不会引发异常。但是,您可以看到以下错误日志

E/MediaProfiles:找不到给定的音频编码器4


我尝试了一下MediaCodeList.getCodecInfoAt,看看它是否能给我一些有用的信息,关于所选设备是否支持MediaRecorder.AudioEncoder.HE_AAC

    int numCodecs = 0;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
        numCodecs = MediaCodecList.getCodecCount();

        for (int i = 0; i < numCodecs; i++) {
            MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);

            if (!codecInfo.isEncoder()) {
                continue;
            }

            for (String s : codecInfo.getSupportedTypes())
                android.util.Log.i("CHEOK", "getSupportedTypes = " + s);
            android.util.Log.i("CHEOK", "name = " + codecInfo.getName());
        }
    }

支持HE_AAC的设备的输出
基于上述输出,我很难将
MediaCodeList.getCodecInfoAt
返回的信息与是否支持
MediaRecorder.AudioEncoder.HE_AAC
相关联

有没有关于什么是可靠的方法的建议


更新的解决方案 这就是解决方案,假设可以使用profile
mediacodeinfo.CodecProfileLevel.AACObjectHE
mediacodeinfo.CodecProfileLevel.AACObjectHE

我是否错过了其他个人资料

private static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";

private boolean isHeAacEncoderSupported() {
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
        int numCodecs = MediaCodecList.getCodecCount();

        for (int i = 0; i < numCodecs; i++) {
            MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);

            if (!codecInfo.isEncoder()) {
                continue;
            }

            for (String supportedType : codecInfo.getSupportedTypes()) {
                if (supportedType.equalsIgnoreCase(MIMETYPE_AUDIO_AAC)) {
                    MediaCodecInfo.CodecCapabilities cap = codecInfo.getCapabilitiesForType(MIMETYPE_AUDIO_AAC);
                    MediaCodecInfo.CodecProfileLevel[] profileLevels = cap.profileLevels;
                    for (MediaCodecInfo.CodecProfileLevel profileLevel : profileLevels) {
                        int profile = profileLevel.profile;
                        if (profile == MediaCodecInfo.CodecProfileLevel.AACObjectHE || profile == MediaCodecInfo.CodecProfileLevel.AACObjectHE_PS) {
                            return true;
                        }
                    }
                }
            }
        }
    }

    return false;
}
private static final String MIMETYPE\u AUDIO\u AAC=“AUDIO/mp4a latm”;
私有布尔值isHeAacEncoderSupported(){
if(android.os.Build.VERSION.SDK\u INT>=android.os.Build.VERSION\u code.JELLY\u BEAN){
int numCodecs=mediacodelist.getCodecCount();
对于(int i=0;i
所有AAC编解码器共享相同的MIME类型,但您应该能够通过区分它们并与之进行比较。

fwiw-如果您必须有一个边缘大小写编码器,您可以使用NDK在应用程序中包含/构建它,以便编码器适用于所有设备。有关使用OPUS的git示例,请参阅-谢谢。我会试试看。目前,为了首先确定编解码器是否来自aac系列,我们使用codecinfo名称与“OMX.google.aac.encoder”进行比较。但是,这足够现实吗?如果aac编解码器是由其他供应商提供的呢?感谢您的指导,我已经更新了我的问题和解决方案。在stackoverflow上,最好实际发布解决方案(回答您自己的问题)并接受它,而不是更新您的问题。
getSupportedTypes = audio/mp4a-latm
name = OMX.google.aac.encoder
getSupportedTypes = audio/3gpp
name = OMX.google.amrnb.encoder
getSupportedTypes = audio/amr-wb
name = OMX.google.amrwb.encoder
getSupportedTypes = audio/flac
name = OMX.google.flac.encoder
getSupportedTypes = video/avc
name = OMX.qcom.video.encoder.avc
getSupportedTypes = video/avc
name = OMX.google.h264.encoder
getSupportedTypes = video/3gpp
name = OMX.qcom.video.encoder.h263
getSupportedTypes = video/3gpp
name = OMX.google.h263.encoder
getSupportedTypes = video/hevc
name = OMX.qcom.video.encoder.hevc
getSupportedTypes = video/mp4v-es
name = OMX.qcom.video.encoder.mpeg4
getSupportedTypes = video/mp4v-es
name = OMX.google.mpeg4.encoder
getSupportedTypes = video/x-vnd.on2.vp8
name = OMX.qcom.video.encoder.vp8
getSupportedTypes = video/x-vnd.on2.vp8
name = OMX.google.vp8.encoder
getSupportedTypes = video/x-vnd.on2.vp9
name = OMX.google.vp9.encoder
private static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";

private boolean isHeAacEncoderSupported() {
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
        int numCodecs = MediaCodecList.getCodecCount();

        for (int i = 0; i < numCodecs; i++) {
            MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);

            if (!codecInfo.isEncoder()) {
                continue;
            }

            for (String supportedType : codecInfo.getSupportedTypes()) {
                if (supportedType.equalsIgnoreCase(MIMETYPE_AUDIO_AAC)) {
                    MediaCodecInfo.CodecCapabilities cap = codecInfo.getCapabilitiesForType(MIMETYPE_AUDIO_AAC);
                    MediaCodecInfo.CodecProfileLevel[] profileLevels = cap.profileLevels;
                    for (MediaCodecInfo.CodecProfileLevel profileLevel : profileLevels) {
                        int profile = profileLevel.profile;
                        if (profile == MediaCodecInfo.CodecProfileLevel.AACObjectHE || profile == MediaCodecInfo.CodecProfileLevel.AACObjectHE_PS) {
                            return true;
                        }
                    }
                }
            }
        }
    }

    return false;
}