用于音频的 MediaExtractor,得到意想不到的音频
MediaExtractor for audio, getting unexpected audio
使用 MediaExtractor class,我能够使用以下内容从保存的 mp4 视频中获取编码的音频样本数据:
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 256);
MediaExtractor audioExtractor = new MediaExtractor();
try {
int trackIndex = -1;
audioExtractor.setDataSource(originalMediaItem.getFilePath());
for (int i = 0; i < audioExtractor.getTrackCount(); i++) {
MediaFormat format = audioExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("audio/")) {
trackIndex = i;
break;
}
}
audioExtractor.selectTrack(trackIndex);
mAudioFormatMedia = audioExtractor.getTrackFormat(trackIndex);
mAudioTrackIndex = mMediaMuxer.addTrack(mAudioFormatMedia);
int size = audioExtractor.readSampleData(byteBuffer, 0);
do {
if (audioExtractor.getSampleTrackIndex() == 1) {
long presentationTime = audioExtractor.getSampleTime();
mInputBufferHashMap.put(presentationTime, byteBuffer);
audioExtractor.advance();
size = audioExtractor.readSampleData(byteBuffer, 0);
}
} while (size >= 0);
audioExtractor.release();
audioExtractor = null;
} catch (IOException e) {
e.printStackTrace();
}
我有一个来自 GlSurface 的视频源,然后想使用 MediaMuxer 将此视频与前面提到的音频提取混合。在处理视频时,使用哈希图将音频交织到复用器中。我成功地混合了视频和音频并创建了可播放的 mp4 视频,但是音频听起来不像原始 mp4 的原始音频。
当我写入 muxer 时,我确实看到了预期的 bufferinfo.size 和 bufferInfo.presentationTimeUs:
mMediaMuxer.writeSampleData(mAudioTrackIndex, buffer, mAudioBufferInfo);
Log.d(TAG, String.format("Wrote %d audio bytes at %d", mAudioBufferInfo.size, mAudioBufferInfo.presentationTimeUs));
我试过使用标准的 inputBuffer、outputBuffer 和 MediaCodec,像这样 https://gist.github.com/a-m-s/1991ab18fbcb0fcc2cf9,但这会产生相同的音频,据我了解,MediaExtractor 应该已经编码了音频数据,所以数据应该可以直接通过管道传输。
同样有趣的是,当我在最初提取时检查标志时:
if( (audioExtractor.getSampleFlags() & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
Log.d(TAG, "BUFFER_FLAG_END_OF_STREAM")
以上都没有为原始 mp4 视频打印。我现在正在质疑原始的 mp4 视频以及是否有可能为 mp4 提供不可提取的音轨以及我如何确认这一点。
我相信我已经查看了大多数关于 Whosebug 的 MediaExtractor 问题,以及关于 github 的 MediaExtractor 的许多单例解决方案。有谁知道以另一种方式提取音频的方法,即使用 ExoPlayer(最好不是 ffmpeg,因为它会增加 android 项目的大量开销)。如果我当前的实施有任何错误,任何见解都会有所帮助!
编辑 1: 这就是格式 audioExtractor.getTrackFormat(trackIndex):
{max-bitrate=512000, sample-rate=48000, track-id=2, durationUs=22373187, mime=audio/mp4a-latm, profile=2, channel-count=4, language=```, aac-profile=2, bitrate=512000, max-input-size=1764, csd-0=java.nio.HeapByteBuffer[pos=0 lim=2 cap=2]}
尝试为音频数据创建地图时出现问题。 AudioData 不正确。我能够通过在使用如下方法编写 videoData 时批处理音频样本数据来解决此问题:
private void writeAudioSampleData(
MediaExtractor audioExtractor, MediaMuxer muxer, int filterStart, int filterEnd) {
mFilterStart = filterEnd;
MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();
boolean audioExtractorDone = false;
audioExtractor.seekTo(filterStart, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
synchronized (mAudioLockObject) {
while (!audioExtractorDone) {
try {
audioBufferInfo.size =
audioExtractor.readSampleData(audioInputBuffer, 0);
} catch (Exception e) {
e.printStackTrace();
}
if (DEBUG) {
Log.d(TAG, "audioBufferInfo.size: " + audioBufferInfo.size);
}
if (audioBufferInfo.size < 0) {
audioBufferInfo.size = 0;
audioExtractorDone = true;
} else {
audioBufferInfo.presentationTimeUs = audioExtractor.getSampleTime();
if (audioBufferInfo.presentationTimeUs > filterEnd) {
break; //out of while
}
if (audioBufferInfo.presentationTimeUs >= filterStart &&
audioBufferInfo.presentationTimeUs <= filterEnd) {
audioBufferInfo.presentationTimeUs -= mOriginalMediaItem.mRecordingStartTs;
audioBufferInfo.flags = audioExtractor.getSampleFlags();
try {
muxer.writeSampleData(mAudioTrackIndex, audioInputBuffer,
audioBufferInfo);
if (DEBUG)Log.d(TAG, String.format("Wrote %d audio bytes at %d",
audioBufferInfo.size, audioBufferInfo.presentationTimeUs));
} catch(IllegalArgumentException | IllegalStateException |
NullPointerException ignore) {}
}
audioExtractor.advance();
}
}
}
使用 MediaExtractor class,我能够使用以下内容从保存的 mp4 视频中获取编码的音频样本数据:
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 256);
MediaExtractor audioExtractor = new MediaExtractor();
try {
int trackIndex = -1;
audioExtractor.setDataSource(originalMediaItem.getFilePath());
for (int i = 0; i < audioExtractor.getTrackCount(); i++) {
MediaFormat format = audioExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("audio/")) {
trackIndex = i;
break;
}
}
audioExtractor.selectTrack(trackIndex);
mAudioFormatMedia = audioExtractor.getTrackFormat(trackIndex);
mAudioTrackIndex = mMediaMuxer.addTrack(mAudioFormatMedia);
int size = audioExtractor.readSampleData(byteBuffer, 0);
do {
if (audioExtractor.getSampleTrackIndex() == 1) {
long presentationTime = audioExtractor.getSampleTime();
mInputBufferHashMap.put(presentationTime, byteBuffer);
audioExtractor.advance();
size = audioExtractor.readSampleData(byteBuffer, 0);
}
} while (size >= 0);
audioExtractor.release();
audioExtractor = null;
} catch (IOException e) {
e.printStackTrace();
}
我有一个来自 GlSurface 的视频源,然后想使用 MediaMuxer 将此视频与前面提到的音频提取混合。在处理视频时,使用哈希图将音频交织到复用器中。我成功地混合了视频和音频并创建了可播放的 mp4 视频,但是音频听起来不像原始 mp4 的原始音频。
当我写入 muxer 时,我确实看到了预期的 bufferinfo.size 和 bufferInfo.presentationTimeUs:
mMediaMuxer.writeSampleData(mAudioTrackIndex, buffer, mAudioBufferInfo);
Log.d(TAG, String.format("Wrote %d audio bytes at %d", mAudioBufferInfo.size, mAudioBufferInfo.presentationTimeUs));
我试过使用标准的 inputBuffer、outputBuffer 和 MediaCodec,像这样 https://gist.github.com/a-m-s/1991ab18fbcb0fcc2cf9,但这会产生相同的音频,据我了解,MediaExtractor 应该已经编码了音频数据,所以数据应该可以直接通过管道传输。
同样有趣的是,当我在最初提取时检查标志时:
if( (audioExtractor.getSampleFlags() & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)
Log.d(TAG, "BUFFER_FLAG_END_OF_STREAM")
以上都没有为原始 mp4 视频打印。我现在正在质疑原始的 mp4 视频以及是否有可能为 mp4 提供不可提取的音轨以及我如何确认这一点。
我相信我已经查看了大多数关于 Whosebug 的 MediaExtractor 问题,以及关于 github 的 MediaExtractor 的许多单例解决方案。有谁知道以另一种方式提取音频的方法,即使用 ExoPlayer(最好不是 ffmpeg,因为它会增加 android 项目的大量开销)。如果我当前的实施有任何错误,任何见解都会有所帮助!
编辑 1: 这就是格式 audioExtractor.getTrackFormat(trackIndex):
{max-bitrate=512000, sample-rate=48000, track-id=2, durationUs=22373187, mime=audio/mp4a-latm, profile=2, channel-count=4, language=```, aac-profile=2, bitrate=512000, max-input-size=1764, csd-0=java.nio.HeapByteBuffer[pos=0 lim=2 cap=2]}
尝试为音频数据创建地图时出现问题。 AudioData 不正确。我能够通过在使用如下方法编写 videoData 时批处理音频样本数据来解决此问题:
private void writeAudioSampleData(
MediaExtractor audioExtractor, MediaMuxer muxer, int filterStart, int filterEnd) {
mFilterStart = filterEnd;
MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();
boolean audioExtractorDone = false;
audioExtractor.seekTo(filterStart, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
synchronized (mAudioLockObject) {
while (!audioExtractorDone) {
try {
audioBufferInfo.size =
audioExtractor.readSampleData(audioInputBuffer, 0);
} catch (Exception e) {
e.printStackTrace();
}
if (DEBUG) {
Log.d(TAG, "audioBufferInfo.size: " + audioBufferInfo.size);
}
if (audioBufferInfo.size < 0) {
audioBufferInfo.size = 0;
audioExtractorDone = true;
} else {
audioBufferInfo.presentationTimeUs = audioExtractor.getSampleTime();
if (audioBufferInfo.presentationTimeUs > filterEnd) {
break; //out of while
}
if (audioBufferInfo.presentationTimeUs >= filterStart &&
audioBufferInfo.presentationTimeUs <= filterEnd) {
audioBufferInfo.presentationTimeUs -= mOriginalMediaItem.mRecordingStartTs;
audioBufferInfo.flags = audioExtractor.getSampleFlags();
try {
muxer.writeSampleData(mAudioTrackIndex, audioInputBuffer,
audioBufferInfo);
if (DEBUG)Log.d(TAG, String.format("Wrote %d audio bytes at %d",
audioBufferInfo.size, audioBufferInfo.presentationTimeUs));
} catch(IllegalArgumentException | IllegalStateException |
NullPointerException ignore) {}
}
audioExtractor.advance();
}
}
}