Android视频添加滤镜时报Failed to add the track to the muxer错误如何解决
Android视频滤镜处理
Failed to add the track to the muxer问题排查与修复方案 问题根因共性分析
该错误本质是MediaMuxer添加音轨时格式不匹配、时序错误或者资源冲突导致的,仅带音轨的视频处理出错,说明问题完全出在音频轨道的配置、采集、写入时序环节。
排查步骤
- 核对音频输出格式与
MediaMuxer要求的一致性
检查音频编码器输出的MediaFormat是否符合以下要求:- 必须设置
KEY_MIME为audio/mp4a-latm - 必须正确设置
KEY_SAMPLE_RATE、KEY_CHANNEL_COUNT、KEY_BIT_RATE,和原视频提取的音频参数完全匹配,不要硬编码固定值 - 音频编码器输出的
csd-0、csd-1参数是否正确传递给了addTrack的MediaFormat,滤镜处理环节很容易丢失这两个配置参数
- 必须设置
- 检查音轨添加的时序逻辑
必须严格遵循
MediaMuxer的调用时序:先调用addTrack添加所有轨道(视频+音频),再调用start(),之后才能写帧数据,绝对不允许start之后再调用addTrack
常见时序错误场景:
视频轨道配置完成就提前调用了muxer.start(),后面音频编码器配置完成再调用addTrack就会直接抛错,偶发崩溃是因为音频编码速度有时候比视频慢,偶尔视频先准备好提前触发了start,有时候音频先准备好就正常,完全匹配你描述的故障现象 - 检查音频帧写入的格式匹配
确认写入muxer的音频帧的bufferInfo.presentationTimeUs是严格递增的,不要出现时间戳回退,同时不要把音频编码的原始PCM帧直接写入,必须是编码器输出的编码后AAC数据才可以传给muxer - 检查资源释放逻辑
确认没有重复调用muxer的addTrack、start、stop、release方法,多线程操作muxer时必须加锁,避免不同线程同时操作muxer触发状态异常
针对性修复方案
1. 轨道就绪等待逻辑优化
在Mp4ComposerEngine里添加轨道就绪计数,只有视频轨道、音频轨道(如果原视频有音轨)都准备完成后,才统一调用muxer.addTrack和muxer.start(),示例逻辑如下:
// 新增成员变量 private AtomicInteger readyTrackCount = new AtomicInteger(0); private final int REQUIRED_TRACK_COUNT; // 初始化时赋值:有音频为2,无音频为1 private final Object muxerLock = new Object(); private AtomicBoolean isMuxerStarted = new AtomicBoolean(false); // 每个轨道配置完成时调用 private void onTrackReady(MediaFormat format, boolean isVideo) { synchronized (muxerLock) { if (isVideo) { videoTrackIndex = muxer.addTrack(format); } else { audioTrackIndex = muxer.addTrack(format); } if (readyTrackCount.incrementAndGet() == REQUIRED_TRACK_COUNT) { muxer.start(); isMuxerStarted.set(true); // 唤醒等待写帧的线程 muxerLock.notifyAll(); } } } // 写帧前先判断muxer是否已经启动,没启动就等待 private void writeSampleData(boolean isVideo, ByteBuffer buffer, MediaCodec.BufferInfo info) { synchronized (muxerLock) { while (!isMuxerStarted.get()) { try { muxerLock.wait(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } int trackIndex = isVideo ? videoTrackIndex : audioTrackIndex; muxer.writeSampleData(trackIndex, buffer, info); } }
2. 音频参数适配优化
不要硬编码音频输出参数,完全从原视频的音频轨道提取参数传给音频编码器:
// 提取原音频参数示例 MediaFormat audioFormat = extractor.getTrackFormat(audioTrackIndex); int sampleRate = audioFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE); int channelCount = audioFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT); int bitRate = audioFormat.containsKey(MediaFormat.KEY_BIT_RATE) ? audioFormat.getInteger(MediaFormat.KEY_BIT_RATE) : 128000; // 配置音频编码器 MediaCodec audioEncoder = MediaCodec.createEncoderByType("audio/mp4a-latm"); MediaFormat outputAudioFormat = MediaFormat.createAudioFormat("audio/mp4a-latm", sampleRate, channelCount); outputAudioFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate); outputAudioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); audioEncoder.configure(outputAudioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
3. 多线程操作加锁
所有对MediaMuxer的操作(addTrack、start、writeSampleData、stop、release)都必须加同一把锁,避免多线程并发操作导致状态异常。
内容的提问来源于stack exchange,提问作者S_i_l_e_n_t C_o_d_e_r
相关产品推荐
相关产品推荐

