ADD MetadataService to track inital metadata

This commit is contained in:
2025-05-20 13:56:00 +02:00
parent b09577fc81
commit a639cfbb0e
5 changed files with 136 additions and 7 deletions

View File

@@ -15,15 +15,17 @@ public class Job {
private File outputFile; private File outputFile;
// configs // configs
private VideoMetadata videoMetadata; private VideoMetadata inputVideoMetadata;
private VideoMetadata outputVideoMetadata;
// job status // job status
private JobStatus status = JobStatus.NOT_READY; private JobStatus status = JobStatus.NOT_READY;
private Float progress = 0.0f; private Float progress = 0.0f;
public Job(String uuid, File inputFile, File outputFile) { public Job(String uuid, File inputFile, File outputFile, VideoMetadata inputVideoMetadata) {
this.uuid = uuid; this.uuid = uuid;
this.inputFile = inputFile; this.inputFile = inputFile;
this.outputFile = outputFile; this.outputFile = outputFile;
this.inputVideoMetadata = inputVideoMetadata;
} }
} }

View File

@@ -109,12 +109,12 @@ public class CompressionService {
public void run(Job job) throws IOException, InterruptedException { public void run(Job job) throws IOException, InterruptedException {
logger.info("FFMPEG starting..."); logger.info("FFMPEG starting...");
ProcessBuilder pb = buildCommand(job.getInputFile(), job.getOutputFile(), job.getVideoMetadata()); ProcessBuilder pb = buildCommand(job.getInputFile(), job.getOutputFile(), job.getOutputVideoMetadata());
Process process = pb.start(); Process process = pb.start();
job.setStatus(JobStatus.RUNNING); job.setStatus(JobStatus.RUNNING);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
float length = job.getVideoMetadata().getEndPoint() - job.getVideoMetadata().getStartPoint(); float length = job.getOutputVideoMetadata().getEndPoint() - job.getOutputVideoMetadata().getStartPoint();
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {

View File

@@ -16,7 +16,7 @@ public class EditService {
public void edit(String uuid, VideoMetadata videoMetadata) { public void edit(String uuid, VideoMetadata videoMetadata) {
Job job = jobService.getJob(uuid); Job job = jobService.getJob(uuid);
validateClipConfig(videoMetadata); validateClipConfig(videoMetadata);
job.setVideoMetadata(videoMetadata); job.setOutputVideoMetadata(videoMetadata);
} }
public void process(String uuid) { public void process(String uuid) {

View File

@@ -0,0 +1,123 @@
package com.ddf.vodsystem.services;
import com.ddf.vodsystem.entities.VideoMetadata;
import com.ddf.vodsystem.exceptions.FFMPEGException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
@Service
public class MetadataService {
private static Logger logger = LoggerFactory.getLogger(MetadataService.class);
public VideoMetadata getVideoMetadata(File file) {
ProcessBuilder pb = new ProcessBuilder("ffprobe",
"-v", "quiet",
"-print_format", "json",
"-show_format", "-select_streams",
"v:0", "-show_entries", "stream=duration,width,height,r_frame_rate:format=size,duration",
"-i", file.getAbsolutePath());
Process process;
try {
process = pb.start();
handleFfprobeError(process);
return parseVideoMetadata(readStandardOutput(process));
} catch (IOException | InterruptedException e) {
Thread.currentThread().interrupt();
throw new FFMPEGException(e.getMessage());
}
}
private JsonNode readStandardOutput(Process process) throws IOException{
// Read the standard output (JSON metadata)
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder jsonOutput = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
jsonOutput.append(line);
}
// Parse the JSON output
ObjectMapper mapper = new ObjectMapper();
return mapper.readTree(jsonOutput.toString());
}
private void handleFfprobeError(Process process) throws IOException, InterruptedException {
int exitCode = process.waitFor();
if (exitCode != 0) {
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
StringBuilder errorOutput = new StringBuilder();
String line;
while ((line = errorReader.readLine()) != null) {
errorOutput.append(line).append("\n");
}
throw new FFMPEGException("ffprobe exited with code " + exitCode + ". Error: " + errorOutput);
}
}
private VideoMetadata parseVideoMetadata(JsonNode node) {
VideoMetadata metadata = new VideoMetadata();
metadata.setStartPoint(0f);
JsonNode streamNode = node.path("streams").get(0);
// if stream doesn't exist
if (streamNode == null || streamNode.isMissingNode()) {
throw new FFMPEGException("ffprobe streams missing");
}
if (streamNode.has("duration")) {
metadata.setEndPoint(Float.valueOf(streamNode.get("duration").asText()));
}
if (streamNode.has("width")) {
metadata.setWidth(streamNode.get("width").asInt());
}
if (streamNode.has("height")) {
metadata.setHeight(streamNode.get("height").asInt());
}
if (streamNode.has("r_frame_rate")) {
String fpsFraction = streamNode.get("r_frame_rate").asText();
if (fpsFraction.contains("/")) {
String[] parts = fpsFraction.split("/");
double numerator = Float.parseFloat(parts[0]);
double denominator = Float.parseFloat(parts[1]);
if (denominator != 0) {
metadata.setFps((float) (numerator / denominator));
}
} else {
metadata.setFps(Float.valueOf(fpsFraction)); // Handle cases like "25" directly
}
}
// Extract from the 'format' section
JsonNode formatNode = node.path("format");
if (formatNode != null && !formatNode.isMissingNode()) {
if (formatNode.has("size")) {
metadata.setFileSize(Float.parseFloat(formatNode.get("size").asText()));
}
// Use format duration as a fallback or primary source if stream duration is absent/zero
if (formatNode.has("duration") && metadata.getEndPoint() == null) {
metadata.setEndPoint(Float.parseFloat(formatNode.get("duration").asText()));
}
}
return metadata;
}
}

View File

@@ -1,6 +1,7 @@
package com.ddf.vodsystem.services; package com.ddf.vodsystem.services;
import com.ddf.vodsystem.entities.Job; import com.ddf.vodsystem.entities.Job;
import com.ddf.vodsystem.entities.VideoMetadata;
import com.vaadin.flow.server.auth.AnonymousAllowed; import com.vaadin.flow.server.auth.AnonymousAllowed;
import com.vaadin.hilla.Endpoint; import com.vaadin.hilla.Endpoint;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
@@ -34,10 +35,12 @@ public class UploadService {
private String outputDir; private String outputDir;
private final JobService jobService; private final JobService jobService;
private final MetadataService metadataService;
@Autowired @Autowired
public UploadService(JobService jobService) { public UploadService(JobService jobService, MetadataService metadataService) {
this.jobService = jobService; this.jobService = jobService;
this.metadataService = metadataService;
} }
public String upload(MultipartFile file) { public String upload(MultipartFile file) {
@@ -55,7 +58,8 @@ public class UploadService {
moveToFile(file, inputFile); moveToFile(file, inputFile);
// add job // add job
Job job = new Job(uuid, inputFile, outputFile); VideoMetadata videoMetadata = metadataService.getVideoMetadata(inputFile);
Job job = new Job(uuid, inputFile, outputFile, videoMetadata);
jobService.add(job); jobService.add(job);
return uuid; return uuid;