use of net.pms.io.PipeProcess in project UniversalMediaServer by UniversalMediaServer.
the class VideoLanVideoStreaming method launchTranscode.
@Override
public ProcessWrapper launchTranscode(DLNAResource dlna, DLNAMediaInfo media, OutputParams params) throws IOException {
// Use device-specific pms conf
PmsConfiguration prev = configuration;
configuration = (DeviceConfiguration) params.mediaRenderer;
boolean isWindows = Platform.isWindows();
final String filename = dlna.getFileName();
PipeProcess tsPipe = new PipeProcess("VLC" + System.currentTimeMillis() + "." + getMux());
ProcessWrapper pipe_process = tsPipe.getPipeProcess();
// XXX it can take a long time for Windows to create a named pipe
// (and mkfifo can be slow if /tmp isn't memory-mapped), so start this as early as possible
pipe_process.runInNewThread();
tsPipe.deleteLater();
params.input_pipes[0] = tsPipe;
params.minBufferSize = params.minFileSize;
params.secondread_minsize = 100000;
List<String> cmdList = new ArrayList<>();
cmdList.add(executable());
cmdList.add("-I");
cmdList.add("dummy");
// TODO: either
// 1) add this automatically if enabled (probe)
// 2) add a GUI option to "enable GPU acceleration"
// 3) document it as an option the user can enable themselves in the vlc GUI (saved to a config file used by cvlc)
// XXX: it's still experimental (i.e. unstable), causing (consistent) segfaults on Windows and Linux,
// so don't even document it for now
// cmdList.add("--ffmpeg-hw");
String transcodeSpec = String.format("#transcode{%s}:standard{access=file,mux=%s,dst=\"%s%s\"}", getEncodingArgs(), getMux(), (isWindows ? "\\\\" : ""), tsPipe.getInputPipe());
if (isWindows) {
cmdList.add("--dummy-quiet");
}
if (isWindows || Platform.isMac()) {
cmdList.add("--sout=" + transcodeSpec);
} else {
cmdList.add("--sout");
cmdList.add(transcodeSpec);
}
// via: https://code.google.com/p/ps3mediaserver/issues/detail?id=711
if (Platform.isMac()) {
cmdList.add("");
}
cmdList.add(filename);
cmdList.add("vlc://quit");
String[] cmdArray = new String[cmdList.size()];
cmdList.toArray(cmdArray);
cmdArray = finalizeTranscoderArgs(filename, dlna, media, params, cmdArray);
ProcessWrapperImpl pw = new ProcessWrapperImpl(cmdArray, params);
pw.attachProcess(pipe_process);
try {
Thread.sleep(150);
} catch (InterruptedException e) {
}
pw.runInNewThread();
configuration = prev;
return pw;
}
use of net.pms.io.PipeProcess in project UniversalMediaServer by UniversalMediaServer.
the class modAwareHashMap method launchTranscode.
@Override
public ProcessWrapper launchTranscode(DLNAResource dlna, DLNAMediaInfo media, OutputParams params) throws IOException {
params.minBufferSize = params.minFileSize;
params.secondread_minsize = 100000;
// Use device-specific pms conf
PmsConfiguration prev = configuration;
configuration = (DeviceConfiguration) params.mediaRenderer;
RendererConfiguration renderer = params.mediaRenderer;
String filename = dlna.getFileName();
setAudioAndSubs(filename, media, params);
// XXX work around an ffmpeg bug: http://ffmpeg.org/trac/ffmpeg/ticket/998
if (filename.startsWith("mms:")) {
filename = "mmsh:" + filename.substring(4);
}
// check if we have modifier for this url
String r = replacements.match(filename);
if (r != null) {
filename = filename.replaceAll(r, replacements.get(r));
LOGGER.debug("modified url: " + filename);
}
FFmpegOptions customOptions = new FFmpegOptions();
// Gather custom options from various sources in ascending priority:
// - automatic options
String match = autoOptions.match(filename);
if (match != null) {
List<String> opts = autoOptions.get(match);
if (opts != null) {
customOptions.addAll(opts);
}
}
// - (http) header options
if (params.header != null && params.header.length > 0) {
String hdr = new String(params.header);
customOptions.addAll(parseOptions(hdr));
}
// - attached options
String attached = (String) dlna.getAttachment(ID);
if (attached != null) {
customOptions.addAll(parseOptions(attached));
}
// - renderer options
String ffmpegOptions = renderer.getCustomFFmpegOptions();
if (StringUtils.isNotEmpty(ffmpegOptions)) {
customOptions.addAll(parseOptions(ffmpegOptions));
}
// Build the command line
List<String> cmdList = new ArrayList<>();
if (!dlna.isURLResolved()) {
URLResult r1 = ExternalFactory.resolveURL(filename);
if (r1 != null) {
if (r1.precoder != null) {
filename = "-";
if (Platform.isWindows()) {
cmdList.add("cmd.exe");
cmdList.add("/C");
}
cmdList.addAll(r1.precoder);
cmdList.add("|");
} else {
if (StringUtils.isNotEmpty(r1.url)) {
filename = r1.url;
}
}
if (r1.args != null && r1.args.size() > 0) {
customOptions.addAll(r1.args);
}
}
}
cmdList.add(executable());
// XXX squashed bug - without this, ffmpeg hangs waiting for a confirmation
// that it can write to a file that already exists i.e. the named pipe
cmdList.add("-y");
cmdList.add("-loglevel");
if (LOGGER.isTraceEnabled()) {
// Set -loglevel in accordance with LOGGER setting
// Could be changed to "verbose" or "debug" if "info" level is not enough
cmdList.add("info");
} else {
cmdList.add("warning");
}
/*
* FFmpeg uses multithreading by default, so provided that the
* user has not disabled FFmpeg multithreading and has not
* chosen to use more or less threads than are available, do not
* specify how many cores to use.
*/
int nThreads = 1;
if (configuration.isFfmpegMultithreading()) {
if (Runtime.getRuntime().availableProcessors() == configuration.getNumberOfCpuCores()) {
nThreads = 0;
} else {
nThreads = configuration.getNumberOfCpuCores();
}
}
// Decoder threads
if (nThreads > 0) {
cmdList.add("-threads");
cmdList.add("" + nThreads);
}
// Add global and input-file custom options, if any
if (!customOptions.isEmpty()) {
customOptions.transferGlobals(cmdList);
customOptions.transferInputFileOptions(cmdList);
}
if (params.timeseek > 0) {
cmdList.add("-ss");
cmdList.add("" + (int) params.timeseek);
}
cmdList.add("-i");
cmdList.add(filename);
cmdList.addAll(getVideoFilterOptions(dlna, media, params));
// Encoder threads
if (nThreads > 0) {
cmdList.add("-threads");
cmdList.add("" + nThreads);
}
// Add the output options (-f, -c:a, -c:v, etc.)
// Now that inputs and filtering are complete, see if we should
// give the renderer the final say on the command
boolean override = false;
if (renderer instanceof RendererConfiguration.OutputOverride) {
override = ((RendererConfiguration.OutputOverride) renderer).getOutputOptions(cmdList, dlna, this, params);
}
if (!override) {
cmdList.addAll(getVideoTranscodeOptions(dlna, media, params));
// Add video bitrate options
cmdList.addAll(getVideoBitrateOptions(dlna, media, params));
// Add audio bitrate options
cmdList.addAll(getAudioBitrateOptions(dlna, media, params));
// Add any remaining custom options
if (!customOptions.isEmpty()) {
customOptions.transferAll(cmdList);
}
}
// Set up the process
// basename of the named pipe:
String fifoName = String.format("ffmpegwebvideo_%d_%d", Thread.currentThread().getId(), System.currentTimeMillis());
// This process wraps the command that creates the named pipe
PipeProcess pipe = new PipeProcess(fifoName);
// delete the named pipe later; harmless if it isn't created
pipe.deleteLater();
ProcessWrapper mkfifo_process = pipe.getPipeProcess();
/**
* It can take a long time for Windows to create a named pipe (and
* mkfifo can be slow if /tmp isn't memory-mapped), so run this in
* the current thread.
*/
mkfifo_process.runInSameThread();
params.input_pipes[0] = pipe;
// Output file
cmdList.add(pipe.getInputPipe());
// Convert the command list to an array
String[] cmdArray = new String[cmdList.size()];
cmdList.toArray(cmdArray);
// Hook to allow plugins to customize this command line
cmdArray = finalizeTranscoderArgs(filename, dlna, media, params, cmdArray);
// Now launch FFmpeg
ProcessWrapperImpl pw = new ProcessWrapperImpl(cmdArray, params);
// Better late than never
parseMediaInfo(filename, dlna, pw);
// Clean up the mkfifo process when the transcode ends
pw.attachProcess(mkfifo_process);
// Give the mkfifo process a little time
try {
Thread.sleep(300);
} catch (InterruptedException e) {
LOGGER.error("Thread interrupted while waiting for named pipe to be created", e);
}
// Launch the transcode command...
pw.runInNewThread();
// ...and wait briefly to allow it to start
try {
Thread.sleep(200);
} catch (InterruptedException e) {
LOGGER.error("Thread interrupted while waiting for transcode to start", e);
}
configuration = prev;
return pw;
}
use of net.pms.io.PipeProcess in project UniversalMediaServer by UniversalMediaServer.
the class MEncoderWebVideo method launchTranscode.
@Override
public ProcessWrapper launchTranscode(DLNAResource dlna, DLNAMediaInfo media, OutputParams params) throws IOException {
// Use device-specific pms conf
PmsConfiguration prev = configuration;
configuration = (DeviceConfiguration) params.mediaRenderer;
params.minBufferSize = params.minFileSize;
params.secondread_minsize = 100000;
PipeProcess pipe = new PipeProcess("mencoder" + System.currentTimeMillis());
params.input_pipes[0] = pipe;
String[] cmdArray = new String[args().length + 4];
cmdArray[0] = executable();
final String filename = dlna.getFileName();
cmdArray[1] = filename;
System.arraycopy(args(), 0, cmdArray, 2, args().length);
cmdArray[cmdArray.length - 2] = "-o";
cmdArray[cmdArray.length - 1] = pipe.getInputPipe();
ProcessWrapper mkfifo_process = pipe.getPipeProcess();
cmdArray = finalizeTranscoderArgs(filename, dlna, media, params, cmdArray);
ProcessWrapperImpl pw = new ProcessWrapperImpl(cmdArray, params);
pw.attachProcess(mkfifo_process);
/**
* It can take a long time for Windows to create a named pipe (and
* mkfifo can be slow if /tmp isn't memory-mapped), so run this in
* the current thread.
*/
mkfifo_process.runInSameThread();
pipe.deleteLater();
pw.runInNewThread();
// Not sure what good this 50ms wait will do for the calling method.
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
configuration = prev;
return pw;
}
Aggregations