我正在尝试使用MediaCodec
API在Android中实现媒体播放器。
我创建了三个主题
线程1:对输入缓冲区进行解除队列以获取空闲索引,然后在相应编解码器的输入缓冲区中对audio
和video
帧进行排队
线程2:对audio
编解码器的输出缓冲区进行解除队列并使用AudioTrack
类'写入方法对其进行渲染
线程3:对video
编解码器的输出缓冲区进行解除队列并使用releaseBuffer
方法对其进行渲染
我在实现audio
和video
帧之间的同步时面临很多问题。我从不丢弃audio
帧,在渲染video
帧之前,我检查解码后的帧是否延迟超过3个,如果它们是我丢帧,如果它们提前超过10毫秒我不渲染框架。
要查找audio
和video
之间的差异,请使用以下逻辑
public long calculateLateByUs(long timeUs) {
long nowUs = 0;
if (hasAudio && audioTrack != null) {
synchronized (audioTrack) {
if(first_audio_sample && startTimeUs >=0){
System.out.println("First video after audio Time Us: " + timeUs );
startTimeUs = -1;
first_audio_sample = false;
}
nowUs = (audioTrack.getPlaybackHeadPosition() * 1000000L) /
audioCodec.format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
}
} else if(!hasAudio){
nowUs = System.currentTimeMillis() * 1000;
startTimeUs = 0;
}else{
nowUs = System.currentTimeMillis() * 1000;
}
if (startTimeUs == -1) {
startTimeUs = nowUs - timeUs;
}
if(syslog){
System.out.println("Timing Statistics:");
System.out.println("Key Sample Rate :"+ audioCodec.format.getInteger(MediaFormat.KEY_SAMPLE_RATE) + " nowUs: " + nowUs + " startTimeUs: "+startTimeUs + " timeUs: "+timeUs + " return value :"+(nowUs - (startTimeUs + timeUs)));
}
return (nowUs - (startTimeUs + timeUs));
}
timeUs
是视频帧的微秒级的呈现时间。 nowUs
应该包含audio
已播放的持续时间(以微秒为单位)。 startTimeUs
是audio
和video
帧之间的初始差异,必须始终保持这种差异。
第一个if块检查,是否确实存在audio
轨道并且已经初始化,并通过从nowUs
计算audiotrack
来设置audio
的值
如果否 nowUs
(第一个)SystemTime
设置为startTimeUs
且初始间隔设置为零。 audio
在main函数中初始化为零。
在使用同步块中的if块的情况下,要渲染的第一帧是audio
并且first_audio_sample
帧稍后加入。 {{1}}标志最初设置为true。
如果有任何不清楚的地方,请告诉我。
此外,如果您知道使用视频编解码器实现了a-v文件的媒体播放器的任何开源链接,那就太棒了。
答案 0 :(得分:0)
如果您正在处理Android
的最新版本之一,则可以考虑直接从audioTimeStamp
检索AudioTrack
。有关详细信息,请参阅此documentation。同样,您也可以考虑通过getSampleRate
检索sampling rate
。
如果您希望继续使用算法,可以考虑在此本机示例中使用相对类似的实现。 SimplePlayer
使用MediaCodec
实现了播放器引擎,并且还具有 a-v sync 部分。请参阅执行同步的section of code。我认为这应该有助于作为一个很好的参考。