mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-19 19:15:08 +00:00
Fix PTS produced by the default opus/flac encoders
The default OPUS and FLAC encoders on Android rewrite the input PTS so that they exactly match the number of samples. As a consequence: - audio clock drift is not compensated - implicit silences (without packets) are ignored To work around this behavior, generate new PTS based on the current time (after encoding) and the packet duration. PR #5870 <https://github.com/Genymobile/scrcpy/pull/5870>
This commit is contained in:
parent
1d25338119
commit
245981281e
1 changed files with 31 additions and 0 deletions
|
@ -55,6 +55,9 @@ public final class AudioEncoder implements AsyncProcessor {
|
|||
private final List<CodecOption> codecOptions;
|
||||
private final String encoderName;
|
||||
|
||||
private boolean recreatePts;
|
||||
private long previousPts;
|
||||
|
||||
// Capacity of 64 is in practice "infinite" (it is limited by the number of available MediaCodec buffers, typically 4).
|
||||
// So many pending tasks would lead to an unacceptable delay anyway.
|
||||
private final BlockingQueue<InputTask> inputTasks = new ArrayBlockingQueue<>(64);
|
||||
|
@ -118,6 +121,9 @@ public final class AudioEncoder implements AsyncProcessor {
|
|||
OutputTask task = outputTasks.take();
|
||||
ByteBuffer buffer = mediaCodec.getOutputBuffer(task.index);
|
||||
try {
|
||||
if (recreatePts) {
|
||||
fixTimestamp(task.bufferInfo);
|
||||
}
|
||||
streamer.writePacket(buffer, task.bufferInfo);
|
||||
} finally {
|
||||
mediaCodec.releaseOutputBuffer(task.index, false);
|
||||
|
@ -125,6 +131,25 @@ public final class AudioEncoder implements AsyncProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private void fixTimestamp(MediaCodec.BufferInfo bufferInfo) {
|
||||
assert recreatePts;
|
||||
|
||||
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
|
||||
// Config packet, nothing to fix
|
||||
return;
|
||||
}
|
||||
|
||||
long pts = bufferInfo.presentationTimeUs;
|
||||
if (previousPts != 0) {
|
||||
long now = System.nanoTime() / 1000;
|
||||
// This specific encoder produces PTS matching the exact number of samples
|
||||
long duration = pts - previousPts;
|
||||
bufferInfo.presentationTimeUs = now - duration;
|
||||
}
|
||||
|
||||
previousPts = pts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(TerminationListener listener) {
|
||||
thread = new Thread(() -> {
|
||||
|
@ -194,6 +219,12 @@ public final class AudioEncoder implements AsyncProcessor {
|
|||
Codec codec = streamer.getCodec();
|
||||
mediaCodec = createMediaCodec(codec, encoderName);
|
||||
|
||||
// The default OPUS and FLAC encoders overwrite the input PTS with a value that matches the number of samples. This is not the behavior
|
||||
// we want: it ignores any audio clock drift and hard silences (packets not produced on silence). To work around this behavior,
|
||||
// regenerate PTS based on the current time and the packet duration.
|
||||
String codecName = mediaCodec.getCanonicalName();
|
||||
recreatePts = "c2.android.opus.encoder".equals(codecName) || "c2.android.flac.encoder".equals(codecName);
|
||||
|
||||
mediaCodecThread = new HandlerThread("media-codec");
|
||||
mediaCodecThread.start();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue