Created a Java w/ Maven project structure; added a simple directory creation and executes an FFMPEG command to transcode videos

This commit is contained in:
Gregory Ballantine 2022-04-30 20:12:32 -04:00
parent fd31df7d56
commit 898d1467c0
7 changed files with 258 additions and 24 deletions

28
.gitignore vendored
View File

@ -1,23 +1,5 @@
# ---> Go
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
.classpath
.project
.settings/
target/
.idea/

View File

@ -1,4 +1,4 @@
Copyright (c) <year> <owner>
Copyright (c) 2022, Bit Goblin
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

86
pom.xml Normal file
View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>tech.bitgoblin</groupId>
<artifactId>Dragoon</artifactId>
<version>0.1.0</version>
<name>Dragoon</name>
<url>https://www.bitgoblin.tech</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<!-- DO NOT include log4j.properties file in your Jar -->
<excludes>
<exclude>**/log4j.properties</exclude>
</excludes>
<archive>
<manifest>
<!-- Jar file entry point -->
<mainClass>tech.bitgoblin.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -0,0 +1,17 @@
package tech.bitgoblin;
import tech.bitgoblin.video.Transcoder;
/**
* The Bit Goblin video transcoder service.
*
*/
public class App {
public static void main(String[] args) {
// create new Transcoder object and start the service
Transcoder t = new Transcoder("~/dragoon");
t.transcode();
}
}

View File

@ -0,0 +1,27 @@
package tech.bitgoblin.io;
import java.io.File;
public class IOUtils {
public static void createDirectory(String path) {
File f = new File(path);
boolean res = f.mkdir();
if (res) {
System.out.println(path + " was created.");
}
}
public static String resolveTilda(String path) {
if (path.startsWith("~" + File.separator)) {
path = System.getProperty("user.home") + path.substring(1);
} else if (path.startsWith("~")) {
// here you can implement reading homedir of other users if you care
throw new UnsupportedOperationException("Home dir expansion not implemented for explicit usernames");
}
return path;
}
}

View File

@ -0,0 +1,102 @@
package tech.bitgoblin.video;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.lang.InterruptedException;
import java.lang.Process;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Consumer;
import java.util.concurrent.Executors;
import tech.bitgoblin.io.IOUtils;
public class Transcoder {
private String repo_dir;
private String ffmpeg_path = "/usr/bin/ffmpeg";
// only define the working directory; use default FFMPEG path
public Transcoder(String repo_dir) {
this.repo_dir = IOUtils.resolveTilda(repo_dir);
this.initDirectory();
}
// define a custom FFMPEG binary path
public Transcoder(String repo_dir, String ffmpeg_path) {
this.repo_dir = IOUtils.resolveTilda(repo_dir);
this.ffmpeg_path = ffmpeg_path;
this.initDirectory();
}
// transcode files in the working directory
public void transcode() {
// search for files
System.out.println("Searching for files to transcode in " + this.repo_dir);
File repo = new File(Paths.get(this.repo_dir, "ingest").toString());
File[] sourceFiles = repo.listFiles();
// transcode
System.out.println("Transcoding files in " + this.repo_dir + "/ingest...");
for (File f : sourceFiles) {
String filePath = f.toString().substring(0, f.toString().lastIndexOf("."));
String filename = Paths.get(filePath).getFileName().toString();
String outputPath = Paths.get(this.repo_dir, "output", String.format("%s.mov", filename)).toString();
String cmd = String.format("%s -i %s -c:v %s -vf \"%s\" -profile:v %s -c:a %s %s",
this.ffmpeg_path, // FFMPEG binary path
f.toString(), // input file
"dnxhd", // video codec
"scale=1920x1080,fps=60,format=yuv422p", // video format
"dnxhr_hq", // video profile
"pcm_s16le", // audio codec
outputPath // output file path
);
ProcessBuilder pb = new ProcessBuilder(cmd.split("\\s+"));
pb.redirectErrorStream(true);
pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
try {
Process process = pb.start();
int ret = process.waitFor();
System.out.printf("Program exited with code: %d", ret);
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
}
// end output
System.out.println("------------ End of transcoding ------------");
System.out.println();
}
// ensures the transcoder's working directory is available
private void initDirectory() {
// create transcoder directory
IOUtils.createDirectory(this.repo_dir);
// create the sub-directories
IOUtils.createDirectory(Paths.get(this.repo_dir, "ingest").toString());
IOUtils.createDirectory(Paths.get(this.repo_dir, "archive").toString());
IOUtils.createDirectory(Paths.get(this.repo_dir, "output").toString());
}
// Stream handler class for the Transcoder
private static class StreamGobbler implements Runnable {
private InputStream inputStream;
private Consumer<String> consumer;
public StreamGobbler(InputStream inputStream, Consumer<String> consumer) {
this.inputStream = inputStream;
this.consumer = consumer;
}
@Override
public void run() {
new BufferedReader(new InputStreamReader(inputStream)).lines().forEach(consumer);
}
}
}

View File

@ -0,0 +1,20 @@
package tech.bitgoblin;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}