MediaCodec
APIを使用してAndroidにメディアプレーヤーを実装しようとしています。
私は 3 つのスレッドを作成しましaudio
たvideo
。
スレッド 2 :audio
コーデックの出力バッファをデキューし、AudioTrack
クラスの書き込みメソッドを使用してレンダリングする
スレッド 3 :video
コーデックの出力バッファをデキューし、releaseBuffer
メソッドを使用してレンダリングするには
フレーム間audio
の同期を達成する際に多くの問題に直面しています。video
フレームをドロップすることはなくaudio
、フレームをレンダリングする前にvideo
、デコードされたフレームが 3 ミリ秒以上遅れているかどうかをチェックします。
との違いを見つけるには、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
トラックが実際に存在し、それが初期化されているかどうかをチェックし、存在しない
場合(first else)が設定され、初期ギャップがゼロに設定されてnowUs
いることから計算しての値を設定します。メイン関数でゼロに初期化されます。audiotrack
audio
nowUs
SystemTime
startTimeUs
同期ブロックの if ブロックは、最初にレンダリングされるフレームが でaudio
、audio
フレームが後で結合する場合に使用されます。first_audio_sample
flag は最初は true に設定されています。
不明な点があればお知らせください。
また、ビデオ コーデックを使用して av ファイルのメディア プレーヤーが実装されているオープン ソース リンクを知っていれば、それは素晴らしいことです。