在最新的Android版本上(AndroidO)为了降低播放4K60FPS片源对整机性能的过度消耗,Android出现了一种新的视频播放模式Tunnel Mode。
下面是关键的几步适配Tunnel Mode的方式:
1.需要Audio SessionID,这个是由Audio Manager生成的
audioSessionId = ((AudioManager)ctx.getSystemService(Context.AUDIO_SERVICE)).generateAudioSessionId();
2.配置docoder尾tunnel mode模式
format.setFeatureEnabled(MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback, true);
3.通过audio sessionid来配置video decoder
format.setInteger(android.media.MediaFormat.KEY_AUDIO_SESSION_ID, audioSessionId);
4.通过SessionId创建Auditrack,同时设置FLAG_HW_AV_SYNC flag让底层知道需要硬件同步
AudioAttributes attr = new AudioAttributes.Builder()
.setLegacyStreamType(AudioManager.STREAM_MUSIC)
.setFlags(AudioAttributes.FLAG_HW_AV_SYNC)
.build();
AudioFormat fmt = new AudioFormat.Builder()
.setEncoding(targetEncoding)
.setSampleRate(sampleRate)
.setChannelMask(channelConfig)
.build();
AudioTrack audioTrack = new android.media.AudioTrack(attr, fmt, bufferSize, 575 android.media.AudioTrack.MODE_STREAM, audioSessionId);
5.video decoder不需要调用dequeueOutputBuffer和releaseOutPutBuffer
6.需要在音频写入audiotrack的时候在头部插入一个16 byte的avsync header
private ByteBuffer avSyncHeader = null;
avSyncHeader = ByteBuffer.allocate(16);
avSyncHeader.order(ByteOrder.BIG_ENDIAN);
avSyncHeader.position(0);
avSyncHeader.order(ByteOrder.BIG_ENDIAN);
avSyncHeader.putInt(AVSYNC_START_CODE);
avSyncHeader.putInt(bufferBytesRemaining);
avSyncHeader.putLong(presentationTimeUs * 1000 );
avSyncHeader.position(0);
这个header包含一个起始码,pts(nano sec),和数据的size。再写入audio数据前先写入这个header data。
具体调试中还会有一些坑,这个得调试的过程中才能一一分析解决。