package org.jcodec.samples.splitter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Splits H264 bitstream into slices having n IDR sequences each
*
* @author The JCodec project
*
*/
public class H264SplitterMain extends H264SplitterBase {
private String fnPattern;
private String slicePath;
private String[] exec;
private boolean verbose;
private int maxIdr;
public static void main(String[] args) throws Exception {
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption(OptionBuilder.withLongOpt("num-idr").withDescription(
"Maximum number of IDR sequences to be written into one slice. Default is 1.").hasArg().withArgName(
"number").create("n"));
options.addOption(OptionBuilder.withLongOpt("pattern").withDescription(
"File name pattern for output slices."
+ " Use '{index}' as a placeholder for slice index."
+ " Default is 'output{index}.264'.").hasArg().withArgName(
"pattern").create("p"));
options.addOption("v", "verbose", false, "Generate verbose output.");
options.addOption(OptionBuilder.withLongOpt("exec").withDescription(
"A command to execute after a new slice is created."
+ " A full path to the new slice file is"
+ " passed as a first parameter to the command."
+ " This should be a full path to executable module."
+ " Use shell to execute a script.").hasArg().withArgName(
"command").create("e"));
options.addOption("h", "help", false, "Print this message.");
try {
CommandLine line = parser.parse(options, args);
String[] files = line.getArgs();
if (line.hasOption("help") || files.length == 0) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("split264", options);
System.exit(0);
}
String filePattern = "output{index}.264";
if (line.hasOption("p")) {
filePattern = line.getOptionValue("p");
}
File file = new File(produceFilePath(filePattern, 0));
if (!file.isAbsolute()) {
String fileName = files[0];
filePattern = new File(new File(fileName).getParentFile(),
filePattern).getAbsolutePath();
}
int numIDR = 1;
if (line.hasOption("n")) {
numIDR = Integer.parseInt(line.getOptionValue("n"));
}
String execute = null;
if (line.hasOption("e")) {
execute = line.getOptionValue("e");
}
boolean verbose = false;
if (line.hasOption("v")) {
verbose = true;
}
new H264SplitterMain().doTheJob(filePattern, numIDR, execute,
verbose, files[0]);
} catch (ParseException exp) {
System.out.println("Unexpected exception:" + exp.getMessage());
}
}
private void doTheJob(String filePattern, int numIDR, String execute,
boolean verbose2, String fileName) throws Exception {
fnPattern = filePattern;
maxIdr = numIDR;
if (execute != null) {
exec = execute.split("\\s");
}
verbose = verbose2;
InputStream io = null;
try {
String inFileName = fileName;
if ("-".equals(inFileName)) {
io = new BufferedInputStream(System.in);
} else {
io = new BufferedInputStream(new FileInputStream(inFileName));
}
split(io);
} finally {
io.close();
}
}
@Override
protected void startNewSlice() throws FileNotFoundException, IOException {
slicePath = produceFilePath(fnPattern, getSliceCount());
String slicePathTmp = slicePath + ".tmp";
setOutputStream(new BufferedOutputStream(new FileOutputStream(
slicePathTmp)));
}
@Override
protected void finishCurrentSlice() {
try {
OutputStream os = getOutputStream();
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (slicePath != null) {
String slicePathTmp = slicePath + ".tmp";
File file = new File(slicePathTmp);
file.renameTo(new File(slicePath));
executeCommand(slicePath);
}
}
private void executeCommand(String slicePath) {
if (exec == null)
return;
try {
String[] newArr = new String[exec.length + 1];
System.arraycopy(exec, 0, newArr, 0, exec.length);
newArr[exec.length] = slicePath;
ProcessWrapper pw = new ProcessWrapper(newArr, null);
int exit = pw.execute();
if (verbose)
System.out.println(new String(pw.getOut()));
byte[] err = pw.getErr();
if (err.length > 0) {
System.err.println(new String(err));
}
if (exit != 0) {
System.err.println("Command '" + join(newArr)
+ "' exited with code: " + exit);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String join(String[] arr) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]);
if (i < arr.length - 1) {
sb.append(" ");
}
}
return sb.toString();
}
private static String produceFilePath(String pattern, int sliceCount) {
return pattern.replace("{index}", String.valueOf(sliceCount));
}
@Override
protected int getMaxIdr() {
return maxIdr;
}
}