MediaCodec - 缺少编解码器特定数据

问题描述

我们的项目使用设备的麦克风作为音频输入录制视频,使用 openGL 场景作为视频 - openGL 场景是音频(光谱图等)的可视化。在 Android 11 更新之前,它在设备上运行良好,但现在更新设备上的输出视频没有声音。该问题并非特定于任何制造商,例如Google Pixel 3/4 和三星 galaxy S20 都受到影响。没有运行时错误或崩溃,使用什么设备播放文件并不重要 - 它肯定没有声音。视频中的音频可视化很好,因此麦克风/输入不是问题。我们使用 Mediamuxer 和 MediaCodec 将录音输出为 mp4 文件

是否还有其他人在对设备进行最新的 Android 11 更新时遇到此问题?有人对我们如何调试有任何建议吗?

这是我们配置视频和音频编解码器的方式:

//VIDEO OUTPUT (MP4)
public static final String VIDEO_MIME_TYPE = MediaFormat.MIMETYPE_VIDEO_AVC;
public static final int VIDEO_FRAME_RATE = 30; 
public static final int VIDEO_IFRAME_INTERVAL = 5;
public static final String AUdio_MIME_TYPE = MediaFormat.MIMETYPE_AUdio_AAC;Video Coding

//AUdio INPUT (MIC)
public static final int RECORDER_SAMPLE_RATE = 44100;
public static final int RECORDER_CHANNELS = 1;
public static final int RECORDER_AUdio_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

//AUdio OUTPUT (MP4)
public static final String ENCODER_AUdio_FORMAT = MediaFormat.MIMETYPE_AUdio_AAC;
public static final int ENCODER_AAC_PROFILE = MediaCodecInfo.CodecProfileLevel.AACObjectLC;
public static final int AUdio_BIT_RATE = 128000; 
public static final int AUdio_SAMPLE_RATE = 44100;
public static final int AUdio_SAMPLES_PER_FRAME = 1024;
public static final int AUdio_FRAMES_PER_BUFFER = 25;
public static final int AUdio_BYTES_PER_ELEMENT = 2;
public static final int AUdio_NUMBER_OF_SPECTRUM_BINS = 20;

//...

//Initialise Video Encoder
MediaFormat format = MediaFormat.createVideoFormat(Config.VIDEO_MIME_TYPE,width,height);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
format.setInteger(MediaFormat.KEY_BIT_RATE,bitRate);
format.setInteger(MediaFormat.KEY_FRAME_RATE,Config.VIDEO_FRAME_RATE);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,Config.VIDEO_IFRAME_INTERVAL);
videoEncoder = MediaCodec.createEncoderByType(Config.VIDEO_MIME_TYPE);
videoEncoder.configure(format,null,MediaCodec.CONfigURE_FLAG_ENCODE);
mInputSurface = videoEncoder.createInputSurface();
videoEncoder.start();

//Initialise Audio Encoder
audioEncoder = MediaCodec.createEncoderByType(Config.AUdio_MIME_TYPE);
MediaFormat audioFormat = MediaFormat.createAudioFormat(Config.ENCODER_AUdio_FORMAT,Config.AUdio_SAMPLE_RATE,Config.RECORDER_CHANNELS);
audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE,Config.ENCODER_AAC_PROFILE);
audioFormat.setInteger(MediaFormat.KEY_BIT_RATE,Config.AUdio_BIT_RATE);
audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT,Config.RECORDER_CHANNELS);
audioEncoder.configure(audioFormat,MediaCodec.CONfigURE_FLAG_ENCODE);
audioEncoder.start();

//Initiate muxer
mmuxer = new Mediamuxer(outputFile,Mediamuxer.OutputFormat.muxer_OUTPUT_MPEG_4);
mmuxer.setorientationHint(orientationHint);

当我们收到第一帧时,我们开始混合

//...
else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
    MediaFormat videoFormat = videoEncoder.getoutputFormat();
    MediaFormat audioFormat = audioEncoder.getoutputFormat();
    videoTrackIndex = mmuxer.addTrack(videoFormat);
    audioTrackIndex = mmuxer.addTrack(audioFormat);
    mmuxer.start();
}

在受影响的设备上检查详细日志,点击“停止记录”按钮后,我能够找到以下感兴趣的行:

2021-03-08 14:52:12.658 20015-20241/com.xx.xx V/Audio:VideoEncoderCore: Sending EOS to encoder!
2021-03-08 14:52:12.670 20015-20241/com.xx.xx D/MPEG4Writer: reset()
**2021-03-08 14:52:12.670 20015-20259/com.xx.xx E/MPEG4Writer: Missing codec specific data**
2021-03-08 14:52:12.670 20015-20259/com.xx.xx E/MPEG4Writer: 0 frames to dump timeStamps in Audio track 
**2021-03-08 14:52:12.670 20015-20258/com.xx.xx V/MediaWriter: Track event err/info msg:101,trackId:1,type:1000,val:-1011 **
2021-03-08 14:52:12.670 20015-20258/com.xx.xx I/MPEG4Writer: Received total/0-length (69/0) buffers and encoded 69 frames. - Video
2021-03-08 14:52:12.670 20015-20241/com.xx.xx D/MPEG4Writer: Video track stopping. Stop source
2021-03-08 14:52:12.670 20015-20241/com.xx.xx D/MPEG4Writer: Video track source stopping
2021-03-08 14:52:12.670 20015-20241/com.xx.xx D/MPEG4Writer: Video track source stopped
2021-03-08 14:52:12.670 20015-20241/com.xx.xx D/MPEG4Writer: Video track stopped. Status:0. Stop source
2021-03-08 14:52:12.670 20015-20241/com.xx.xx D/MPEG4Writer: Audio track stopping. Stop source
2021-03-08 14:52:12.670 20015-20241/com.xx.xx D/MPEG4Writer: Audio track source stopping
2021-03-08 14:52:12.670 20015-20241/com.xx.xx D/MPEG4Writer: Audio track source stopped
2021-03-08 14:52:12.670 20015-20259/com.xx.xx V/MediaWriter: Track event err/info msg:100,trackId:2,type:100,val:-1007
2021-03-08 14:52:12.670 20015-20259/com.xx.xx I/MPEG4Writer: Received total/0-length (87/0) buffers and encoded 87 frames. - Audio
2021-03-08 14:52:12.670 20015-20259/com.xx.xx I/MPEG4Writer: Audio track drift time: 0 us
2021-03-08 14:52:12.670 20015-20262/com.xx.xx I/hw-BpHwBinder: onLastStrongRef automatically unlinking death recipients
**2021-03-08 14:52:12.671 20015-20241/com.xx.xx D/MPEG4Writer: Audio track stopped. Status:-1007. Stop source **
**2021-03-08 14:52:12.671 20015-20241/com.xx.xx W/MPEG4Writer: Condition trackErr == OK Failed Audio track stopped with an error **
2021-03-08 14:52:12.671 20015-20241/com.xx.xx D/MPEG4Writer: Duration from tracks range is [2050653,2293393] us
2021-03-08 14:52:12.671 20015-20256/com.xx.xx D/MPEG4Writer: 0 chunks are written in the last batch
2021-03-08 14:52:12.671 20015-20241/com.xx.xx D/MPEG4Writer: WriterThread stopped. Status:0
2021-03-08 14:52:12.671 20015-20241/com.xx.xx I/MPEG4Writer: Adjust the moov start time from 0 us -> 0 us
2021-03-08 14:52:12.671 20015-20241/com.xx.xx I/MPEG4Writer: MOOV atom was written to the file
2021-03-08 14:52:12.671 20015-20241/com.xx.xx D/MPEG4Writer: release()

解决方法

以下错误帮助我解决了这个问题:

2021-03-08 14:52:12.670 20015-20259/com.xx.xx E/MPEG4Writer: Missing codec specific data

有关 codec specific data 及其含义的更多信息。

我仍然不知道为什么这只是在 Android 11 推送后才开始,但我知道原因以及如何解决它。最初,我会在收到第一帧视频后从视频线程中的音频和视频编码器中提取 MediaFormat,然后调用 MediaMuxer.start()。在 Android 11 之前,这种方法运行良好。但是,更新后,我的音频格式附加了需要提供给多路复用器的内容特定数据。不幸的是,只有在接收到第一帧声音(不是视频的第一帧)后,才能从音频编码器中获得这些数据。因此,我之前的方法不起作用,因为在接收到第一帧视频之前我没有传递音频帧,并且我在从音频编码器接收编解码器特定数据之前启动了我的复用器。

解决方案

等待接收第一帧声音并在您的音频线程中调用 MediaCodec.getMediaFormat()。对视频线程中的视频执行相同操作。包括检查音频和视频格式是否已首先接收的逻辑,然后在您的视频线程中启动多路复用器。我所有的输出文件现在都有视频和音频。

,

我在处理一些多路复用的事情时遇到了同样的问题。您的解决方案的坏处是,您将丢失由相机提供给 mediamuxer 的所有视频帧,直到您收到第一个音频帧。我想在编码开始时提供一些虚拟音频帧会更好吗?

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...