Bear with my noobness, I am learning web-flux. I had this simple application that takes a video and extract the audio using FFprobe and FFmpeg, so I thought of redoing it reactively, but I am failing miserably...
Controller:
@PostMapping("/upload")
public String upload(@RequestPart("file") Mono<FilePart> filePartMono, final Model model) {
Flux<String> filenameList = mediaComponent.extractAudio(filePartMono);
model.addAttribute("filenameList", new ReactiveDataDriverContextVariable(filenameList));
return "download";
}
Function to get audio streams out of the video:
public Mono<FFprobeResult> getAudioStreams(InputStream inputStream) {
try {
return Mono.just(FFprobe.atPath(FFprobePath)
.setShowStreams(true)
.setSelectStreams(StreamType.AUDIO)
.setLogLevel(LogLevel.INFO)
.setInput(inputStream)
.execute());
} catch (JaffreeException e) {
log.error(e.getMessage(), e);
return Mono.error(new MediaException("Audio formats could not be identified."));
}
}
Attempt 1:
public Flux<String> extractAudio(Mono<FilePart> filePartMono) {
filePartMono.flatMapMany(Part::content)
.map(dataBuffer -> dataBuffer.asInputStream(true))
.flatMap(this::getAudioStreams)
.subscribe(System.out::println);
...
}
Attempt 2:
public Flux<String> extractAudio(Mono<FilePart> filePartMono) {
filePartMono.flatMapMany(Part::content)
.reduce(InputStream.nullInputStream(), (inputStream, dataBuffer) -> new SequenceInputStream(
inputStream, dataBuffer.asInputStream()
))
.flatMap(this::getAudioStreams)
.subscribe(System.out::println);
...
}
Attempt 3:
public Flux<String> extractAudio(Mono<FilePart> filePartMono) {
DataBufferUtils.write(filePartMono.flatMapMany(Part::content), OutputStream.nullOutputStream())
.map(dataBuffer -> dataBuffer.asInputStream(true))
.flatMap(this::getAudioStreams)
.subscribe(System.out::println);
...
}
Attempt 1 and 3 seems to be the same in the end, FFprobe complains as follows:
2022-10-30 11:24:30.292 WARN 79049 --- [ StdErr] c.g.k.jaffree.process.BaseStdReader : [mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f9162702340] [warning] STSZ atom truncated
2022-10-30 11:24:30.292 ERROR 79049 --- [ StdErr] c.g.k.jaffree.process.BaseStdReader : [mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f9162702340] [error] stream 0, contradictionary STSC and STCO
2022-10-30 11:24:30.292 ERROR 79049 --- [ StdErr] c.g.k.jaffree.process.BaseStdReader : [mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f9162702340] [error] error reading header
2022-10-30 11:24:30.294 ERROR 79049 --- [ StdErr] c.g.k.jaffree.process.BaseStdReader : [error] tcp://127.0.0.1:51532: Invalid data found when processing input
2022-10-30 11:24:30.295 INFO 79049 --- [oundedElastic-3] c.g.k.jaffree.process.ProcessHandler : Process has finished with status: 1
2022-10-30 11:24:30.409 ERROR 79049 --- [oundedElastic-3] c.e.s.application.MediaComponent : Process execution has ended with non-zero status: 1. Check logs for detailed error message.
Attempt 2 produces multiple of these:
Exception in thread "Runnable-0" java.lang.StackOverflowError
at java.base/java.io.SequenceInputStream.read(SequenceInputStream.java:198)
Now, after some more research, I had another fourth attempt:
public Flux<String> extractAudio(Mono<FilePart> filePartMono) {
try {
FFprobeResult FFprobeResult = getAudioStreams(getInputStreamFromFluxDataBuffer(filePartMono.flatMapMany(Part::content))).subscribe(System.out::println);
return Flux.just("file ", "file2").delayElements(Duration.ofMinutes(1));
} catch (IOException e) {
log.error(e.getMessage(), e);
return Flux.error(new MediaException("Audio extraction failed"));
}
}
public InputStream getInputStreamFromFluxDataBuffer(Flux<DataBuffer> dataBuffer) throws IOException {
PipedOutputStream pipedOutputStream = new PipedOutputStream();
PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);
DataBufferUtils.write(dataBuffer, pipedOutputStream)
.subscribeOn(Schedulers.boundedElastic())
.doOnComplete(() -> {
try {
pipedOutputStream.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
})
.subscribe(DataBufferUtils.releaseConsumer());
return pipedInputStream;
}
However, this time FFprobe starts and never ends, as if the InputStream was endless..
Could anybody point me in the right direction? What am I doing wrong? By the way, I am outputting to console just to see a result, but in the end I need to take all the outputted streams and pass them as arguments to another function that will finally extract the audio, so I need to figure out that as well.
Thank you in advance.