DLNAMediaInfo media,
OutputParams params
) throws IOException {
int nThreads = configuration.getNumberOfCpuCores();
List<String> cmdList = new ArrayList<String>();
RendererConfiguration renderer = params.mediaRenderer;
final String filename = dlna.getSystemName();
setAudioAndSubs(filename, media, params, configuration);
params.waitbeforestart = 2500;
cmdList.add(executable());
cmdList.addAll(getGlobalOptions(logger));
if (params.timeseek > 0) {
cmdList.add("-ss");
cmdList.add("" + params.timeseek);
}
// decoder threads
cmdList.add("-threads");
cmdList.add("" + nThreads);
final boolean isTsMuxeRVideoEngineEnabled = configuration.getEnginesAsList().contains(TsMuxeRVideo.ID);
setAc3Remux(false);
setDtsRemux(false);
setVideoRemux(false);
if (configuration.isAudioRemuxAC3() && params.aid != null && params.aid.isAC3() && renderer.isTranscodeToAC3()) {
// AC-3 remux takes priority
setAc3Remux(true);
} else if (isTsMuxeRVideoEngineEnabled && configuration.isAudioEmbedDtsInPcm() && params.aid != null && params.aid.isDTS() && params.mediaRenderer.isDTSPlayable()) {
// Now check for DTS remux
setDtsRemux(true);
}
String frameRateRatio = media.getValidFps(true);
String frameRateNumber = media.getValidFps(false);
// Input filename
cmdList.add("-i");
cmdList.add(filename);
if (media.getAudioTracksList().size() > 1) {
// Set the video stream
cmdList.add("-map");
cmdList.add("0:v");
// Set the proper audio stream
cmdList.add("-map");
cmdList.add("0:a:" + (media.getAudioTracksList().indexOf(params.aid)));
}
// Encoder threads
cmdList.add("-threads");
cmdList.add("" + nThreads);
if (params.timeend > 0) {
cmdList.add("-t");
cmdList.add("" + params.timeend);
}
// add video bitrate options (-b:a)
// cmdList.addAll(getVideoBitrateOptions(filename, dlna, media, params));
// add audio bitrate options (-b:v)
// cmdList.addAll(getAudioBitrateOptions(filename, dlna, media, params));
// if the source is too large for the renderer, resize it
// and/or add subtitles to video filter
// FFmpeg must be compiled with --enable-libass parameter
cmdList.addAll(getVideoFilterOptions(dlna, media, params));
int defaultMaxBitrates[] = getVideoBitrateConfig(configuration.getMaximumBitrate());
int rendererMaxBitrates[] = new int[2];
if (renderer.getMaxVideoBitrate() != null) {
rendererMaxBitrates = getVideoBitrateConfig(renderer.getMaxVideoBitrate());
}
// Give priority to the renderer's maximum bitrate setting over the user's setting
if (rendererMaxBitrates[0] > 0 && rendererMaxBitrates[0] < defaultMaxBitrates[0]) {
defaultMaxBitrates = rendererMaxBitrates;
}
if (params.mediaRenderer.getCBRVideoBitrate() == 0) {
// Convert value from Mb to Kb
defaultMaxBitrates[0] = 1000 * defaultMaxBitrates[0];
// Halve it since it seems to send up to 1 second of video in advance
defaultMaxBitrates[0] = defaultMaxBitrates[0] / 2;
int bufSize = 1835;
// x264 uses different buffering math than MPEG-2
if (!renderer.isTranscodeToH264TSAC3()) {
if (media.isHDVideo()) {
bufSize = defaultMaxBitrates[0] / 3;
}
if (bufSize > 7000) {
bufSize = 7000;
}
if (defaultMaxBitrates[1] > 0) {
bufSize = defaultMaxBitrates[1];
}
if (params.mediaRenderer.isDefaultVBVSize() && rendererMaxBitrates[1] == 0) {
bufSize = 1835;
}
}
// Make room for audio
if (isDtsRemux()) {
defaultMaxBitrates[0] = defaultMaxBitrates[0] - 1510;
} else {
defaultMaxBitrates[0] = defaultMaxBitrates[0] - configuration.getAudioBitrate();
}
// Round down to the nearest Mb
defaultMaxBitrates[0] = defaultMaxBitrates[0] / 1000 * 1000;
// FFmpeg uses bytes for inputs instead of kbytes like MEncoder
bufSize = bufSize * 1000;
defaultMaxBitrates[0] = defaultMaxBitrates[0] * 1000;
/**
* Level 4.1-limited renderers like the PS3 can stutter when H.264 video exceeds
* this bitrate
*/
if (renderer.isTranscodeToH264TSAC3() || isVideoRemux()) {
if (
params.mediaRenderer.isH264Level41Limited() &&
defaultMaxBitrates[0] > 31250000
) {
defaultMaxBitrates[0] = 31250000;
}
bufSize = defaultMaxBitrates[0];
}
cmdList.add("-bufsize");
cmdList.add("" + bufSize);
cmdList.add("-maxrate");
cmdList.add("" + defaultMaxBitrates[0]);
}
// Set audio bitrate and channel count only when doing audio transcoding
if (!isAc3Remux() && !isDtsRemux() && !(type() == Format.AUDIO)) {
int channels;
if (renderer.isTranscodeToWMV() && !renderer.isXBOX()) {
channels = 2;
} else {
channels = configuration.getAudioChannelCount(); // 5.1 max for AC-3 encoding
}
cmdList.add("-ac");
cmdList.add("" + channels);
cmdList.add("-ab");
cmdList.add(configuration.getAudioBitrate() + "k");
}
if (params.timeseek > 0) {
cmdList.add("-copypriorss");
cmdList.add("0");
cmdList.add("-avoid_negative_ts");
cmdList.add("1");
}
// Add MPEG-2 quality settings
if (!renderer.isTranscodeToH264TSAC3() && !isVideoRemux()) {
String mpeg2Options = configuration.getMPEG2MainSettingsFFmpeg();
String mpeg2OptionsRenderer = params.mediaRenderer.getCustomFFmpegMPEG2Options();
// Renderer settings take priority over user settings
if (isNotBlank(mpeg2OptionsRenderer)) {
mpeg2Options = mpeg2OptionsRenderer;
} else {
if (mpeg2Options.contains("Automatic")) {
mpeg2Options = "-g 5 -q:v 1 -qmin 2 -qmax 3";
// It has been reported that non-PS3 renderers prefer keyint 5 but prefer it for PS3 because it lowers the average bitrate
if (params.mediaRenderer.isPS3()) {
mpeg2Options = "-g 25 -q:v 1 -qmin 2 -qmax 3";
}
if (mpeg2Options.contains("Wireless") || defaultMaxBitrates[0] < 70) {
// Lower quality for 720p+ content
if (media.getWidth() > 1280) {
mpeg2Options = "-g 25 -qmax 7 -qmin 2";
} else if (media.getWidth() > 720) {
mpeg2Options = "-g 25 -qmax 5 -qmin 2";
}
}
}
}
String[] customOptions = StringUtils.split(mpeg2Options);
cmdList.addAll(new ArrayList<String>(Arrays.asList(customOptions)));
}
// Add the output options (-f, -c:a, -c:v, etc.)
cmdList.addAll(getVideoTranscodeOptions(dlna, media, params));
// Add custom options
if (StringUtils.isNotEmpty(renderer.getCustomFFmpegOptions())) {
parseOptions(renderer.getCustomFFmpegOptions(), cmdList);
}
if (!isDtsRemux()) {
cmdList.add("pipe:");
}