Skip to content
This repository has been archived by the owner on Feb 9, 2018. It is now read-only.

Commit

Permalink
Make FFmpeg display external subtitles.
Browse files Browse the repository at this point in the history
(Requires FFmpeg version 1.1 or higher)
  • Loading branch information
Raptor399 committed Feb 10, 2013
1 parent 5e9a3e6 commit 453d4c3
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/main/java/net/pms/encoders/FFMpegAudio.java
Expand Up @@ -51,6 +51,7 @@ public class FFMpegAudio extends FFMpegVideo {
JCheckBox noresample; JCheckBox noresample;


public FFMpegAudio(PmsConfiguration configuration) { public FFMpegAudio(PmsConfiguration configuration) {
super(configuration);
this.configuration = configuration; this.configuration = configuration;
} }


Expand Down
4 changes: 4 additions & 0 deletions src/main/java/net/pms/encoders/FFMpegAviSynthVideo.java
Expand Up @@ -44,6 +44,10 @@ public class FFMpegAviSynthVideo extends FFMpegVideo {
private static final Logger logger = LoggerFactory.getLogger(FFMpegAviSynthVideo.class); private static final Logger logger = LoggerFactory.getLogger(FFMpegAviSynthVideo.class);
public static final String ID = "avsffmpeg"; public static final String ID = "avsffmpeg";


FFMpegAviSynthVideo() {
super(PMS.getConfiguration());
}

@Override @Override
public String id() { public String id() {
return ID; return ID;
Expand Down
97 changes: 83 additions & 14 deletions src/main/java/net/pms/encoders/FFMpegVideo.java
Expand Up @@ -22,6 +22,7 @@
import java.awt.Font; import java.awt.Font;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
Expand All @@ -32,6 +33,7 @@


import net.pms.Messages; import net.pms.Messages;
import net.pms.PMS; import net.pms.PMS;
import net.pms.configuration.PmsConfiguration;
import net.pms.configuration.RendererConfiguration; import net.pms.configuration.RendererConfiguration;
import net.pms.dlna.DLNAMediaInfo; import net.pms.dlna.DLNAMediaInfo;
import net.pms.dlna.DLNAMediaSubtitle; import net.pms.dlna.DLNAMediaSubtitle;
Expand All @@ -41,6 +43,8 @@
import net.pms.io.ProcessWrapper; import net.pms.io.ProcessWrapper;
import net.pms.io.ProcessWrapperImpl; import net.pms.io.ProcessWrapperImpl;
import net.pms.network.HTTPResource; import net.pms.network.HTTPResource;
import net.pms.util.FileUtil;
import net.pms.util.ProcessUtil;


import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
Expand All @@ -67,12 +71,30 @@
public class FFMpegVideo extends Player { public class FFMpegVideo extends Player {
private static final Logger LOGGER = LoggerFactory.getLogger(FFMpegVideo.class); private static final Logger LOGGER = LoggerFactory.getLogger(FFMpegVideo.class);
private JTextField ffmpeg; private JTextField ffmpeg;
private final PmsConfiguration configuration;
private static final String DEFAULT_QSCALE = "3"; private static final String DEFAULT_QSCALE = "3";


// FIXME we have an id() accessor for this; no need for the field to be public // FIXME we have an id() accessor for this; no need for the field to be public
@Deprecated @Deprecated
public static final String ID = "ffmpegvideo"; public static final String ID = "ffmpegvideo";


/**
* This constructor is not used in the codebase.
*/
@Deprecated
public FFMpegVideo() {
this(PMS.getConfiguration());
}

/**
* Default constructor.
*
* @param configuration The PMS configuration options object
*/
public FFMpegVideo(PmsConfiguration configuration) {
this.configuration = configuration;
}

/** /**
* Returns a list of strings representing the rescale options for this transcode i.e. the ffmpeg -vf * Returns a list of strings representing the rescale options for this transcode i.e. the ffmpeg -vf
* options used to resize a video that's too wide and/or high for the specified renderer. * options used to resize a video that's too wide and/or high for the specified renderer.
Expand Down Expand Up @@ -266,6 +288,47 @@ private List<String> getCustomArgs() {
return customOptions; return customOptions;
} }


/**
* Returns subtitle options based on the provided media and output parameters.
*
* @param renderer The renderer configuration settings
* @param media The media information
* @param params The output parameter settings
* @return The list of subtitle options
*/
private List<String> getSubtitleOptions(RendererConfiguration renderer,
DLNAMediaInfo media, OutputParams params) {

List<String> subtitleOptions = new ArrayList<String>();
String externalSubtitlesFileName = null;

if (params.sid != null) {
if (params.sid.isExternal()) {
// External subtitle file
if (params.sid.isExternalFileUtf16()) {
try {
// Convert UTF-16 -> UTF-8
File convertedSubtitles = new File(configuration.getTempFolder(), "utf8_" + params.sid.getExternalFile().getName());
FileUtil.convertFileFromUtf16ToUtf8(params.sid.getExternalFile(), convertedSubtitles);
externalSubtitlesFileName = ProcessUtil.getShortFileNameIfWideChars(convertedSubtitles.getAbsolutePath());
} catch (IOException e) {
LOGGER.debug("Error converting file from UTF-16 to UTF-8", e);
externalSubtitlesFileName = ProcessUtil.getShortFileNameIfWideChars(params.sid.getExternalFile().getAbsolutePath());
}
} else {
externalSubtitlesFileName = ProcessUtil.getShortFileNameIfWideChars(params.sid.getExternalFile().getAbsolutePath());
}

// Burn in subtitles with the subtitles filter (available since ffmpeg 1.1)
subtitleOptions.add("-vf");
subtitleOptions.add("subtitles=" + externalSubtitlesFileName);
}
// TODO: Handle embedded subtitles
}

return subtitleOptions;
}

// XXX hardwired to false and not referenced anywhere else in the codebase // XXX hardwired to false and not referenced anywhere else in the codebase
@Deprecated @Deprecated
public boolean mplayer() { public boolean mplayer() {
Expand All @@ -288,23 +351,13 @@ public ProcessWrapper launchTranscode(
DLNAResource dlna, DLNAResource dlna,
DLNAMediaInfo media, DLNAMediaInfo media,
OutputParams params OutputParams params
) throws IOException {
return getFFMpegTranscode(fileName, dlna, media, params, null);
}

// XXX pointless redirection of launchTranscode
// TODO remove this method and move its body into launchTranscode
// TODO call setAudioAndSubs to populate params with audio track/subtitles metadata
@Deprecated
protected ProcessWrapperImpl getFFMpegTranscode(
String fileName,
DLNAResource dlna,
DLNAMediaInfo media,
OutputParams params,
String args[]
) throws IOException { ) throws IOException {
int nThreads = PMS.getConfiguration().getNumberOfCpuCores(); int nThreads = PMS.getConfiguration().getNumberOfCpuCores();
List<String> cmdList = new ArrayList<String>(); List<String> cmdList = new ArrayList<String>();

// Populate params with audio track and subtitles metadata
setAudioAndSubs(fileName, media, params, configuration);

RendererConfiguration renderer = params.mediaRenderer; RendererConfiguration renderer = params.mediaRenderer;


cmdList.add(executable()); cmdList.add(executable());
Expand Down Expand Up @@ -342,6 +395,9 @@ protected ProcessWrapperImpl getFFMpegTranscode(
// if the source is too large for the renderer, resize it // if the source is too large for the renderer, resize it
cmdList.addAll(getRescaleOptions(renderer, media)); cmdList.addAll(getRescaleOptions(renderer, media));


// Add subtitle options
cmdList.addAll(getSubtitleOptions(renderer, media, params));

// add custom args // add custom args
cmdList.addAll(getCustomArgs()); cmdList.addAll(getCustomArgs());


Expand All @@ -367,6 +423,19 @@ protected ProcessWrapperImpl getFFMpegTranscode(
return pw; return pw;
} }


// XXX pointless redirection of launchTranscode
// TODO remove this method and move its body into launchTranscode
@Deprecated
protected ProcessWrapperImpl getFFMpegTranscode(
String fileName,
DLNAResource dlna,
DLNAMediaInfo media,
OutputParams params,
String args[]
) throws IOException {
return (ProcessWrapperImpl) launchTranscode(fileName, dlna, media, params);
}

@Override @Override
public JComponent config() { public JComponent config() {
return config("FFMpegVideo.1"); return config("FFMpegVideo.1");
Expand Down
1 change: 1 addition & 0 deletions src/main/java/net/pms/encoders/FFMpegWebVideo.java
Expand Up @@ -67,6 +67,7 @@ public boolean isTimeSeekable() {
} }


public FFMpegWebVideo(PmsConfiguration configuration) { public FFMpegWebVideo(PmsConfiguration configuration) {
super(configuration);
this.configuration = configuration; this.configuration = configuration;
} }


Expand Down
2 changes: 1 addition & 1 deletion src/main/java/net/pms/encoders/PlayerFactory.java
Expand Up @@ -131,7 +131,7 @@ private static void registerPlayers(final PmsConfiguration configuration) {
registerPlayer(new MEncoderAviSynth(configuration)); registerPlayer(new MEncoderAviSynth(configuration));
} }


registerPlayer(new FFMpegVideo()); registerPlayer(new FFMpegVideo(configuration));
registerPlayer(new MPlayerAudio(configuration)); registerPlayer(new MPlayerAudio(configuration));
registerPlayer(new FFMpegWebVideo(configuration)); registerPlayer(new FFMpegWebVideo(configuration));
registerPlayer(new MEncoderWebVideo(configuration)); registerPlayer(new MEncoderWebVideo(configuration));
Expand Down

0 comments on commit 453d4c3

Please sign in to comment.