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:
parent
9be4c07049
commit
8855591f0f
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue