简体   繁体   English

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

[英]MediaCodec - Missing codec specific data

Our project records videos using the device's microphone as audio input, and openGL scene as video - the openGL scene is a visualisation of the audio (spectrograph etc).我们的项目使用设备的麦克风作为音频输入录制视频,并将 openGL 场景作为视频 - openGL 场景是音频的可视化(光谱仪等)。 It worked perfectly on devices until Android 11 update, but now the output videos on updated devices have no sound.在 Android 11 更新之前,它在设备上运行良好,但现在更新设备上的 output 视频没有声音。 The issue is not specific to any manufacturer, eg Google Pixel 3/4 and Samsung Galaxy S20 are both impacted.该问题并非特定于任何制造商,例如 Google Pixel 3/4 和三星 Galaxy S20 都受到影响。 There are no runtime errors, or crashes and it doesn't matter what device is used to play back the file - it definitely has no sound.没有运行时错误或崩溃,使用什么设备播放文件都没有关系 - 它肯定没有声音。 The audio visualisation in the video is fine, so the microphone/input is not the issue.视频中的音频可视化很好,所以麦克风/输入不是问题。 We use MediaMuxer and MediaCodec to output the recording to an mp4 file.我们使用 MediaMuxer 和 MediaCodec 将 output 录制到 mp4 文件中。

Is anybody else experiencing this issue with the latest Android 11 update to devices?是否有其他人在设备的最新 Android 11 更新中遇到此问题? Does anybody have any suggestions on how we could debug?有人对我们如何调试有任何建议吗?

This is how we configure our video and audio codecs:这是我们配置视频和音频编解码器的方式:

//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, 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, null, null,MediaCodec.CONFIGURE_FLAG_ENCODE);
audioEncoder.start();

//Initiate Muxer
mMuxer = new MediaMuxer(outputFile, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
mMuxer.setOrientationHint(orientationHint);

We start muxing when we receive the first frame当我们收到第一帧时我们开始混合

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

Inpsecting the log verbose on an impacted device, I was able to find the following lines of interest after tapping the "stop recording" button:检查受影响设备上的详细日志,在点击“停止录制”按钮后,我能够找到以下感兴趣的行:

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()

The following error helped me solve this problem:以下错误帮助我解决了这个问题:

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

More information about codec specific data and what it is.有关编解码器特定数据及其内容的更多信息。

I still don't know why this only started after the Android 11 push, but I do know the cause and how to fix it.我仍然不知道为什么这只是在 Android 11 推送之后才开始,但我知道原因以及如何解决它。 Originally, I would pull the MediaFormat from my audio and video encoders in the video thread after receiving the first frame of video and then call MediaMuxer.start() .最初,我会在接收到第一帧视频后从视频线程中的音频和视频编码器中提取MediaFormat ,然后调用MediaMuxer.start() Up until Android 11, this approach worked fine.在 Android 11 之前,这种方法运行良好。 However, after the update, my audio format had content specific data attached which needed to be provided to the muxer.但是,更新后,我的音频格式附加了内容特定的数据,这些数据需要提供给复用器。 Unfortunately, this data is only available from the audio encoder after receiving the first frame of sound (not first frame of video).不幸的是,只有在接收到第一帧声音(不是第一帧视频)后,音频编码器才能获得此数据。 So, my previous approach wouldn't work as I wasn't passing audio frames until the first frame of video was received, and I was starting my muxer before receiving the codec specific data from my audio encoder.因此,我以前的方法不起作用,因为在接收到第一帧视频之前我没有传递音频帧,并且我在从我的音频编码器接收编解码器特定数据之前启动了我的复用器。

The Solution解决方案

Wait to receive the first frame of sound and call MediaCodec.getMediaFormat() in your audio thread.等待接收第一帧声音并在音频线程中调用MediaCodec.getMediaFormat() Do the same for video in your video thread.对视频线程中的视频执行相同操作。 Include logic to check that both the audio and video formats have been received first, and then initiate the muxer in your video thread.包含逻辑以检查是否已首先接收到音频和视频格式,然后在视频线程中启动多路复用器。 All my output files now have video and audio.我所有的 output 文件现在都有视频和音频。

I faced the same issue while been working on some muxing stuff.我在处理一些混合的东西时遇到了同样的问题。 The bad thing about your solution is the fact that you'll lose all videoframes which was provided to mediamuxer by camera until you'll receive first audioframe.您的解决方案的坏处在于,您将丢失所有由摄像头提供给 mediamuxer 的视频帧,直到您收到第一个音频帧。 i guess it could be better to provide some dummy audioframe at the start of encoding?我想在编码开始时提供一些虚拟音频帧会更好吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM