forked from j62/ctbrec
1
0
Fork 0

Fix race condition in code for streaming segments to FFmpeg

This caused stuttering and jumps mostly in the beginning of a recording
This commit is contained in:
0xb00bface 2021-01-23 16:24:24 +01:00
parent 9be4c07049
commit 8855591f0f
2 changed files with 29 additions and 20 deletions

View File

@ -13,6 +13,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;
import org.slf4j.Logger;
@ -40,6 +42,7 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload {
private transient Process ffmpegProcess;
private transient OutputStream ffmpegStdIn;
private transient BlockingQueue<Future<SegmentDownload>> queue = new LinkedBlockingQueue<>();
private transient Lock ffmpegStreamLock = new ReentrantLock();
public MergedFfmpegHlsDownload(HttpClient client) {
super(client);
@ -78,30 +81,31 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload {
}
private void streamSegmentDataToFfmpeg() {
while (!queue.isEmpty() && !Thread.currentThread().isInterrupted()) {
downloadExecutor.submit(() -> {
ffmpegStreamLock.lock();
try {
Future<SegmentDownload> future = queue.peek();
if (running && future.isDone()) {
queue.take();
SegmentDownload segmentDownload = future.get();
downloadExecutor.submit(() -> {
ByteArrayOutputStream downloadData = (ByteArrayOutputStream) segmentDownload.getOutputStream();
try {
ffmpegStdIn.write(downloadData.toByteArray());
} catch (IOException e) {
LOG.error("Couldn't stream segment data to FFmpeg", e);
while (!queue.isEmpty() && !Thread.currentThread().isInterrupted()) {
try {
Future<SegmentDownload> future = queue.peek();
if (running && future.isDone()) {
queue.take();
SegmentDownload segmentDownload = future.get();
ByteArrayOutputStream downloadData = (ByteArrayOutputStream) segmentDownload.getOutputStream();
downloadData.writeTo(ffmpegStdIn);
} else {
// first download in queue not finished, let's continue with other stuff
break;
}
});
} else {
// first download in queue not finished, let's continue with other stuff
break;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
LOG.error("Segment download failed for model {}", model, e);
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
LOG.error("Segment download failed for model {}", model, e);
} finally {
ffmpegStreamLock.unlock();
}
}
});
}
@Override

View File

@ -81,6 +81,7 @@ public class SegmentDownload implements Callable<SegmentDownload> {
out.write(b, 0, length);
BandwidthMeter.add(length);
}
out.flush();
return true;
} else {
throw new HttpException(response.code(), response.message());
@ -96,4 +97,8 @@ public class SegmentDownload implements Callable<SegmentDownload> {
public OutputStream getOutputStream() {
return out;
}
public URL getUrl() {
return url;
}
}