Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

RendererConfiguration

By: a guest on Apr 1st, 2013  |  syntax: None  |  size: 35.18 KB  |  views: 23  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. package net.pms.configuration;
  2.  
  3. import com.sun.jna.Platform;
  4.  
  5. import net.pms.Messages;
  6. import net.pms.PMS;
  7. import net.pms.dlna.DLNAMediaInfo;
  8. import net.pms.dlna.LibMediaInfoParser;
  9. import net.pms.dlna.RootFolder;
  10. import net.pms.formats.Format;
  11. import net.pms.network.HTTPResource;
  12. import net.pms.network.SpeedStats;
  13. import net.pms.util.PropertiesUtil;
  14.  
  15. import org.apache.commons.configuration.ConfigurationException;
  16. import org.apache.commons.configuration.ConversionException;
  17. import org.apache.commons.configuration.PropertiesConfiguration;
  18. import org.apache.commons.lang.StringUtils;
  19.  
  20. import org.slf4j.Logger;
  21. import org.slf4j.LoggerFactory;
  22.  
  23. import java.io.File;
  24. import java.net.InetAddress;
  25. import java.util.ArrayList;
  26. import java.util.HashMap;
  27. import java.util.Map;
  28. import java.util.StringTokenizer;
  29. import java.util.regex.Pattern;
  30.  
  31. public class RendererConfiguration {
  32.         private static final Logger LOGGER = LoggerFactory.getLogger(RendererConfiguration.class);
  33.         private static ArrayList<RendererConfiguration> rendererConfs;
  34.         private static PmsConfiguration pmsConfiguration;
  35.         private static RendererConfiguration defaultConf;
  36.         private static Map<InetAddress, RendererConfiguration> addressAssociation = new HashMap<InetAddress, RendererConfiguration>();
  37.  
  38.         private RootFolder rootFolder;
  39.         private final PropertiesConfiguration configuration;
  40.         private FormatConfiguration formatConfiguration;
  41.         private int rank;
  42.         private final Map<String, String> mimes;
  43.         private final Map<String, String> DLNAPN;
  44.  
  45.         // property values
  46.         private static final String DEPRECATED_MPEGPSAC3 = "MPEGAC3"; // XXX deprecated: old name with missing container
  47.         private static final String EXCLUSIVE = "exclusive";
  48.         private static final String LPCM = "LPCM";
  49.         private static final String MP3 = "MP3";
  50.         private static final String MPEGPSAC3 = "MPEGPSAC3";
  51.         private static final String MPEGTSAC3 = "MPEGTSAC3";
  52.         private static final String WAV = "WAV";
  53.         private static final String WMV = "WMV";
  54.  
  55.         // property names
  56.         private static final String AUDIO = "Audio";
  57.         private static final String AUTO_EXIF_ROTATE = "AutoExifRotate";
  58.         private static final String BYTE_TO_TIMESEEK_REWIND_SECONDS = "ByteToTimeseekRewindSeconds"; // Ditlew
  59.         private static final String CBR_VIDEO_BITRATE = "CBRVideoBitrate"; // Ditlew
  60.         private static final String CHUNKED_TRANSFER = "ChunkedTransfer";
  61.         private static final String CUSTOM_MENCODER_OPTIONS = "CustomMencoderOptions";
  62.         private static final String CUSTOM_MENCODER_QUALITY_SETTINGS = "CustomMencoderQualitySettings";
  63.         private static final String DEFAULT_VBV_BUFSIZE = "DefaultVBVBufSize";
  64.         private static final String DLNA_LOCALIZATION_REQUIRED = "DLNALocalizationRequired";
  65.         private static final String DLNA_ORGPN_USE = "DLNAOrgPN";
  66.         private static final String DLNA_PN_CHANGES = "DLNAProfileChanges";
  67.         private static final String DLNA_TREE_HACK = "CreateDLNATreeFaster";
  68.         private static final String FORCE_JPG_THUMBNAILS = "ForceJPGThumbnails"; // Sony devices require JPG thumbnails
  69.         private static final String H264_L41_LIMITED = "H264Level41Limited";
  70.         private static final String IMAGE = "Image";
  71.         private static final String LONG_FILE_NAME_FORMAT = "LongFileNameFormat";
  72.         private static final String MAX_VIDEO_BITRATE = "MaxVideoBitrateMbps";
  73.         private static final String MAX_VIDEO_HEIGHT = "MaxVideoHeight";
  74.         private static final String MAX_VIDEO_WIDTH = "MaxVideoWidth";
  75.         private static final String MEDIAPARSERV2 = "MediaInfo";
  76.         private static final String MEDIAPARSERV2_THUMB = "MediaParserV2_ThumbnailGeneration";
  77.         private static final String MIME_TYPES_CHANGES = "MimeTypesChanges";
  78.         private static final String MUX_DTS_TO_MPEG = "MuxDTSToMpeg";
  79.         private static final String MUX_H264_WITH_MPEGTS = "MuxH264ToMpegTS";
  80.         private static final String MUX_LPCM_TO_MPEG = "MuxLPCMToMpeg";
  81.         private static final String RENDERER_ICON = "RendererIcon";
  82.         private static final String RENDERER_NAME = "RendererName";
  83.         private static final String SEEK_BY_TIME = "SeekByTime";
  84.         private static final String SHORT_FILE_NAME_FORMAT = "ShortFileNameFormat";
  85.         private static final String SHOW_AUDIO_METADATA = "ShowAudioMetadata";
  86.         private static final String SHOW_DVD_TITLE_DURATION = "ShowDVDTitleDuration"; // Ditlew
  87.         private static final String SHOW_SUB_METADATA = "ShowSubMetadata";
  88.         private static final String STREAM_EXT = "StreamExtensions";
  89.         private static final String SUBTITLE_HTTP_HEADER = "SubtitleHttpHeader";
  90.         private static final String SUPPORTED = "Supported";
  91.         private static final String TRANSCODE_AUDIO_441KHZ = "TranscodeAudioTo441kHz";
  92.         private static final String TRANSCODE_AUDIO = "TranscodeAudio";
  93.         private static final String TRANSCODED_SIZE = "TranscodedVideoFileSize";
  94.         private static final String TRANSCODE_EXT = "TranscodeExtensions";
  95.         private static final String TRANSCODE_FAST_START = "TranscodeFastStart";
  96.         private static final String TRANSCODE_VIDEO = "TranscodeVideo";
  97.         private static final String USER_AGENT_ADDITIONAL_HEADER = "UserAgentAdditionalHeader";
  98.         private static final String USER_AGENT_ADDITIONAL_SEARCH = "UserAgentAdditionalHeaderSearch";
  99.         private static final String USER_AGENT = "UserAgentSearch";
  100.         private static final String USE_SAME_EXTENSION = "UseSameExtension";
  101.         private static final String VIDEO = "Video";
  102.         private static final String WRAP_DTS_INTO_PCM = "WrapDTSIntoPCM";
  103.  
  104.         public static RendererConfiguration getDefaultConf() {
  105.                 return defaultConf;
  106.         }
  107.  
  108.         /**
  109.          * Load all renderer configuration files and set up the default renderer.
  110.          *
  111.          * @param pmsConf
  112.          */
  113.         public static void loadRendererConfigurations(PmsConfiguration pmsConf) {
  114.                 LOGGER.info("now we're inside loadRendererConfigurations method. setting pmsConfiguration");
  115.                 LOGGER.info("pmsConfiguration = pmsConf;");
  116.                 pmsConfiguration = pmsConf;
  117.                
  118.                 LOGGER.info("rendererConfs = new ArrayList<RendererConfiguration>();");
  119.                 rendererConfs = new ArrayList<RendererConfiguration>();
  120.  
  121.                 try {
  122.                         LOGGER.info("defaultConf = new RendererConfiguration();");
  123.                         defaultConf = new RendererConfiguration();
  124.                 } catch (ConfigurationException e) {
  125.                         LOGGER.debug("Caught exception", e);
  126.                 }
  127.  
  128.                 LOGGER.info("File renderersDir = getRenderersDir();");
  129.                 File renderersDir = getRenderersDir();
  130.  
  131.                 LOGGER.info("if (renderersDir != null) {");
  132.                 if (renderersDir != null) {
  133.                        
  134.                         LOGGER.info("Loading renderer configurations from " + renderersDir.getAbsolutePath());
  135.                        
  136.                         LOGGER.info("File[] confs = renderersDir.listFiles();");
  137.                         File[] confs = renderersDir.listFiles();
  138.                         int rank = 1;
  139.                         for (File f : confs) {
  140.                                 if (f.getName().endsWith(".conf")) {
  141.                                         try {
  142.                                                 LOGGER.info("Loading configuration file: " + f.getName());
  143.                                                 RendererConfiguration r = new RendererConfiguration(f);
  144.                                                 r.rank = rank++;
  145.                                                 rendererConfs.add(r);
  146.                                         } catch (ConfigurationException ce) {
  147.                                                 LOGGER.info("Error in loading configuration of: " + f.getAbsolutePath());
  148.                                         }
  149.  
  150.                                 }
  151.                         }
  152.                 }
  153.  
  154.                 if (rendererConfs.size() > 0) {
  155.                         // See if a different default configuration was configured
  156.                         String rendererFallback = pmsConfiguration.getRendererDefault();
  157.  
  158.                         if (StringUtils.isNotBlank(rendererFallback)) {
  159.                                 RendererConfiguration fallbackConf = getRendererConfigurationByName(rendererFallback);
  160.  
  161.                                 if (fallbackConf != null) {
  162.                                         // A valid fallback configuration was set, use it as default.
  163.                                         defaultConf = fallbackConf;
  164.                                 }
  165.                         }
  166.                 }
  167.         }
  168.  
  169.         /**
  170.          * Returns the list of all renderer configurations.
  171.          *
  172.          * @return The list of all configurations.
  173.          */
  174.         public static ArrayList<RendererConfiguration> getAllRendererConfigurations() {
  175.                 return rendererConfs;
  176.         }
  177.  
  178.         protected static File getRenderersDir() {
  179.                 final String[] pathList = PropertiesUtil.getProjectProperties().get("project.renderers.dir").split(",");
  180.  
  181.                 for (String path : pathList) {
  182.                         if (path.trim().length() > 0) {
  183.                                 File file = new File(path.trim());
  184.  
  185.                                 if (file.isDirectory()) {
  186.                                         if (file.canRead()) {
  187.                                                 return file;
  188.                                         } else {
  189.                                                 LOGGER.warn("Can't read directory: {}", file.getAbsolutePath());
  190.                                         }
  191.                                 }
  192.                         }
  193.                 }
  194.  
  195.                 return null;
  196.         }
  197.  
  198.         public static void resetAllRenderers() {
  199.                 for (RendererConfiguration rc : rendererConfs) {
  200.                         rc.rootFolder = null;
  201.                 }
  202.         }
  203.  
  204.         public RootFolder getRootFolder() {
  205.                 if (rootFolder == null) {
  206.                         rootFolder = new RootFolder();
  207.                         rootFolder.discoverChildren();
  208.                 }
  209.  
  210.                 return rootFolder;
  211.         }
  212.  
  213.         /**
  214.          * Associate an IP address with this renderer. The association will
  215.          * persist between requests, allowing the renderer to be recognized
  216.          * by its address in later requests.
  217.          * @param sa The IP address to associate.
  218.          * @see #getRendererConfigurationBySocketAddress(InetAddress)
  219.          */
  220.         public void associateIP(InetAddress sa) {
  221.                 addressAssociation.put(sa, this);
  222.                 SpeedStats.getInstance().getSpeedInMBits(sa, getRendererName());
  223.         }
  224.  
  225.         public static RendererConfiguration getRendererConfigurationBySocketAddress(InetAddress sa) {
  226.                 return addressAssociation.get(sa);
  227.         }
  228.  
  229.         /**
  230.          * Tries to find a matching renderer configuration based on a request
  231.          * header line with a User-Agent header. These matches are made using
  232.          * the "UserAgentSearch" configuration option in a renderer.conf.
  233.          * Returns the matched configuration or <code>null</code> if no match
  234.          * could be found.
  235.          *
  236.          * @param userAgentString The request header line.
  237.          * @return The matching renderer configuration or <code>null</code>.
  238.          */
  239.         public static RendererConfiguration getRendererConfigurationByUA(String userAgentString) {
  240.                 if (pmsConfiguration.isRendererForceDefault()) {
  241.                         // Force default renderer
  242.                         LOGGER.trace("Forcing renderer match to \"" + defaultConf.getRendererName() + "\"");
  243.                         return manageRendererMatch(defaultConf);
  244.                 } else {
  245.                         // Try to find a match
  246.                         for (RendererConfiguration r : rendererConfs) {
  247.                                 if (r.matchUserAgent(userAgentString)) {
  248.                                         return manageRendererMatch(r);
  249.                                 }
  250.                         }
  251.                 }
  252.  
  253.                 return null;
  254.         }
  255.  
  256.         private static RendererConfiguration manageRendererMatch(RendererConfiguration r) {
  257.                 if (addressAssociation.values().contains(r)) {
  258.                         // FIXME: This cannot ever ever happen because of how renderer matching
  259.                         // is implemented in RequestHandler and RequestHandlerV2. The first header
  260.                         // match will associate the IP address with the renderer and from then on
  261.                         // all other requests from the same IP address will be recognized based on
  262.                         // that association. Headers will be ignored and unfortunately they happen
  263.                         // to be the only way to get here.
  264.                         LOGGER.info("Another renderer like " + r.getRendererName() + " was found!");
  265.                 }
  266.  
  267.                 return r;
  268.         }
  269.  
  270.         /**
  271.          * Tries to find a matching renderer configuration based on a request
  272.          * header line with an additional, non-User-Agent header. These matches
  273.          * are made based on the "UserAgentAdditionalHeader" and
  274.          * "UserAgentAdditionalHeaderSearch" configuration options in a
  275.          * renderer.conf. Returns the matched configuration or <code>null</code>
  276.          * if no match could be found.
  277.          *
  278.          * @param header The request header line.
  279.          * @return The matching renderer configuration or <code>null</code>.
  280.          */
  281.         public static RendererConfiguration getRendererConfigurationByUAAHH(String header) {
  282.                 if (pmsConfiguration.isRendererForceDefault()) {
  283.                         // Force default renderer
  284.                         LOGGER.trace("Forcing renderer match to \"" + defaultConf.getRendererName() + "\"");
  285.                         return manageRendererMatch(defaultConf);
  286.                 } else {
  287.                         // Try to find a match
  288.                         for (RendererConfiguration r : rendererConfs) {
  289.                                 if (StringUtils.isNotBlank(r.getUserAgentAdditionalHttpHeader()) && header.startsWith(r.getUserAgentAdditionalHttpHeader())) {
  290.                                         String value = header.substring(header.indexOf(":", r.getUserAgentAdditionalHttpHeader().length()) + 1);
  291.                                         if (r.matchAdditionalUserAgent(value)) {
  292.                                                 return manageRendererMatch(r);
  293.                                         }
  294.                                 }
  295.                         }
  296.                 }
  297.  
  298.                 return null;
  299.         }
  300.  
  301.         /**
  302.          * Tries to find a matching renderer configuration based on the name of
  303.          * the renderer. Returns true if the provided name is equal to or a
  304.          * substring of the renderer name defined in a configuration, where case
  305.          * does not matter.
  306.          *
  307.          * @param name The renderer name to match.
  308.          * @return The matching renderer configuration or <code>null</code>
  309.          *
  310.          * @since 1.50.1
  311.          */
  312.         public static RendererConfiguration getRendererConfigurationByName(String name) {
  313.                 for (RendererConfiguration conf : rendererConfs) {
  314.                         if (conf.getRendererName().toLowerCase().contains(name.toLowerCase())) {
  315.                                 return conf;
  316.                         }
  317.                 }
  318.  
  319.                 return null;
  320.         }
  321.  
  322.         public FormatConfiguration getFormatConfiguration() {
  323.                 return formatConfiguration;
  324.         }
  325.  
  326.         public int getRank() {
  327.                 return rank;
  328.         }
  329.  
  330.         // FIXME These 'is' methods should disappear. Use feature detection instead.
  331.         @Deprecated
  332.         public boolean isXBOX() {
  333.                 return getRendererName().toUpperCase().contains("XBOX");
  334.         }
  335.  
  336.         @Deprecated
  337.         public boolean isXBMC() {
  338.                 return getRendererName().toUpperCase().contains("XBMC");
  339.         }
  340.  
  341.         public boolean isPS3() {
  342.                 return getRendererName().toUpperCase().contains("PLAYSTATION") || getRendererName().toUpperCase().contains("PS3");
  343.         }
  344.  
  345.         public boolean isBRAVIA() {
  346.                 return getRendererName().toUpperCase().contains("BRAVIA");
  347.         }
  348.  
  349.         @Deprecated
  350.         public boolean isFDSSDP() {
  351.                 return getRendererName().toUpperCase().contains("FDSSDP");
  352.         }
  353.  
  354.         // Ditlew
  355.         public int getByteToTimeseekRewindSeconds() {
  356.                 return getInt(BYTE_TO_TIMESEEK_REWIND_SECONDS, 0);
  357.         }
  358.  
  359.         // Ditlew
  360.         public int getCBRVideoBitrate() {
  361.                 return getInt(CBR_VIDEO_BITRATE, 0);
  362.         }
  363.  
  364.         // Ditlew
  365.         public boolean isShowDVDTitleDuration() {
  366.                 return getBoolean(SHOW_DVD_TITLE_DURATION, false);
  367.         }
  368.  
  369.         private RendererConfiguration() throws ConfigurationException {
  370.                 this(null);
  371.         }
  372.  
  373.         public RendererConfiguration(File f) throws ConfigurationException {
  374.                 LOGGER.info("Inside constructor: public RendererConfiguration(File f) throws ConfigurationException {");
  375.                
  376.                 LOGGER.info("configuration = new PropertiesConfiguration();");
  377.                 configuration = new PropertiesConfiguration();
  378.                
  379.                 LOGGER.info("configuration.setListDelimiter((char) 0);");
  380.                 configuration.setListDelimiter((char) 0);
  381.  
  382.                 LOGGER.info("checking if f is null.. F is File f");
  383.                 if (f != null) {
  384.                         LOGGER.info("f is not null, loading configuration");
  385.                         LOGGER.info("configuration.load(f);");
  386.                         configuration.load(f);
  387.                 } else {
  388.                         LOGGER.info("f is null... not going to do configuration.load(f)");
  389.                 }
  390.  
  391.                 LOGGER.info("mimes = new HashMap<String, String>();");
  392.                 mimes = new HashMap<String, String>();
  393.  
  394.                 LOGGER.info("String mimeTypes = getString(MIME_TYPES_CHANGES, null);");
  395.                 String mimeTypes = getString(MIME_TYPES_CHANGES, null);
  396.  
  397.                 LOGGER.info("checking if StringUtils.isNotBlank(mimeTypes)");
  398.                 if (StringUtils.isNotBlank(mimeTypes)) {
  399.                         LOGGER.info("StringUtils.isNotBlank(mimeTypes) == true");
  400.                         LOGGER.info("StringTokenizer st = new StringTokenizer(mimeTypes);");
  401.                         StringTokenizer st = new StringTokenizer(mimeTypes, "|");
  402.  
  403.                         while (st.hasMoreTokens()) {
  404.                                 String mime_change = st.nextToken().trim();
  405.                                 int equals = mime_change.indexOf("=");
  406.  
  407.                                 if (equals > -1) {
  408.                                         String old = mime_change.substring(0, equals).trim().toLowerCase();
  409.                                         String nw = mime_change.substring(equals + 1).trim().toLowerCase();
  410.                                         mimes.put(old, nw);
  411.                                 }
  412.                         }
  413.                 }
  414.  
  415.                 DLNAPN = new HashMap<String, String>();
  416.                 String DLNAPNchanges = getString(DLNA_PN_CHANGES, null);
  417.  
  418.                 if (DLNAPNchanges != null) {
  419.                         LOGGER.trace("Config DLNAPNchanges: " + DLNAPNchanges);
  420.                 }
  421.  
  422.                 if (StringUtils.isNotBlank(DLNAPNchanges)) {
  423.                         StringTokenizer st = new StringTokenizer(DLNAPNchanges, "|");
  424.                         while (st.hasMoreTokens()) {
  425.                                 String DLNAPN_change = st.nextToken().trim();
  426.                                 int equals = DLNAPN_change.indexOf("=");
  427.                                 if (equals > -1) {
  428.                                         String old = DLNAPN_change.substring(0, equals).trim().toUpperCase();
  429.                                         String nw = DLNAPN_change.substring(equals + 1).trim().toUpperCase();
  430.                                         DLNAPN.put(old, nw);
  431.                                 }
  432.                         }
  433.                 }
  434.  
  435.                 if (f == null) {
  436.                         // the default renderer supports everything !
  437.                         configuration.addProperty(MEDIAPARSERV2, true);
  438.                         configuration.addProperty(MEDIAPARSERV2_THUMB, true);
  439.                         configuration.addProperty(SUPPORTED, "f:.+");
  440.                 }
  441.  
  442.                 if (isMediaParserV2()) {
  443.                         formatConfiguration = new FormatConfiguration(configuration.getList(SUPPORTED));
  444.                 }
  445.         }
  446.  
  447.         public String getDLNAPN(String old) {
  448.                 if (DLNAPN.containsKey(old)) {
  449.                         return DLNAPN.get(old);
  450.                 }
  451.                 return old;
  452.         }
  453.  
  454.         public boolean supportsFormat(Format f) {
  455.                 switch (f.getType()) {
  456.                         case Format.VIDEO:
  457.                                 return isVideoSupported();
  458.                         case Format.AUDIO:
  459.                                 return isAudioSupported();
  460.                         case Format.IMAGE:
  461.                                 return isImageSupported();
  462.                         default:
  463.                                 break;
  464.                 }
  465.  
  466.                 return false;
  467.         }
  468.  
  469.         public boolean isVideoSupported() {
  470.                 return getBoolean(VIDEO, true);
  471.         }
  472.  
  473.         public boolean isAudioSupported() {
  474.                 return getBoolean(AUDIO, true);
  475.         }
  476.  
  477.         public boolean isImageSupported() {
  478.                 return getBoolean(IMAGE, true);
  479.         }
  480.  
  481.         public boolean isTranscodeToWMV() {
  482.                 return getVideoTranscode().equals(WMV);
  483.         }
  484.  
  485.         public boolean isTranscodeToAC3() {
  486.                 return isTranscodeToMPEGPSAC3() || isTranscodeToMPEGTSAC3();
  487.         }
  488.  
  489.         public boolean isTranscodeToMPEGPSAC3() {
  490.                 String videoTranscode = getVideoTranscode();
  491.                 return videoTranscode.equals(MPEGPSAC3) || videoTranscode.equals(DEPRECATED_MPEGPSAC3);
  492.         }
  493.  
  494.         public boolean isTranscodeToMPEGTSAC3() {
  495.                 return getVideoTranscode().equals(MPEGTSAC3);
  496.         }
  497.  
  498.         public boolean isAutoRotateBasedOnExif() {
  499.                 return getBoolean(AUTO_EXIF_ROTATE, false);
  500.         }
  501.  
  502.         public boolean isTranscodeToMP3() {
  503.                 return getAudioTranscode().equals(MP3);
  504.         }
  505.  
  506.         public boolean isTranscodeToLPCM() {
  507.                 return getAudioTranscode().equals(LPCM);
  508.         }
  509.  
  510.         public boolean isTranscodeToWAV() {
  511.                 return getAudioTranscode().equals(WAV);
  512.         }
  513.  
  514.         public boolean isTranscodeAudioTo441() {
  515.                 return getBoolean(TRANSCODE_AUDIO_441KHZ, false);
  516.         }
  517.  
  518.         public boolean isH264Level41Limited() {
  519.                 return getBoolean(H264_L41_LIMITED, false);
  520.         }
  521.  
  522.         public boolean isTranscodeFastStart() {
  523.                 return getBoolean(TRANSCODE_FAST_START, false);
  524.         }
  525.  
  526.         public boolean isDLNALocalizationRequired() {
  527.                 return getBoolean(DLNA_LOCALIZATION_REQUIRED, false);
  528.         }
  529.  
  530.         public String getMimeType(String mimetype) {
  531.                 if (isMediaParserV2()) {
  532.                         if (mimetype != null && mimetype.equals(HTTPResource.VIDEO_TRANSCODE)) {
  533.                                 mimetype = getFormatConfiguration().match(FormatConfiguration.MPEGPS, FormatConfiguration.MPEG2, FormatConfiguration.AC3);
  534.                                 if (isTranscodeToMPEGTSAC3()) {
  535.                                         mimetype = getFormatConfiguration().match(FormatConfiguration.MPEGTS, FormatConfiguration.MPEG2, FormatConfiguration.AC3);
  536.                                 } else if (isTranscodeToWMV()) {
  537.                                         mimetype = getFormatConfiguration().match(FormatConfiguration.WMV, FormatConfiguration.WMV, FormatConfiguration.WMA);
  538.                                 }
  539.                         } else if (mimetype != null && mimetype.equals(HTTPResource.AUDIO_TRANSCODE)) {
  540.                                 mimetype = getFormatConfiguration().match(FormatConfiguration.LPCM, null, null);
  541.  
  542.                                 if (mimetype != null) {
  543.                                         if (isTranscodeAudioTo441()) {
  544.                                                 mimetype += ";rate=44100;channels=2";
  545.                                         } else {
  546.                                                 mimetype += ";rate=48000;channels=2";
  547.                                         }
  548.                                 }
  549.  
  550.                                 if (isTranscodeToWAV()) {
  551.                                         mimetype = getFormatConfiguration().match(FormatConfiguration.WAV, null, null);
  552.                                 } else if (isTranscodeToMP3()) {
  553.                                         mimetype = getFormatConfiguration().match(FormatConfiguration.MP3, null, null);
  554.                                 }
  555.                         }
  556.  
  557.                         return mimetype;
  558.                 }
  559.  
  560.                 if (mimetype != null && mimetype.equals(HTTPResource.VIDEO_TRANSCODE)) {
  561.                         mimetype = HTTPResource.MPEG_TYPEMIME;
  562.                         if (isTranscodeToWMV()) {
  563.                                 mimetype = isMediaParserV2()
  564.                                         ? getFormatConfiguration().match(FormatConfiguration.WMV, FormatConfiguration.WMV, FormatConfiguration.WMA)
  565.                                         : HTTPResource.WMV_TYPEMIME;
  566.                         } else if (isTranscodeToMPEGTSAC3()) {
  567.                                 mimetype = isMediaParserV2()
  568.                                         ? getFormatConfiguration().match(FormatConfiguration.MPEGTS, FormatConfiguration.MPEG2, FormatConfiguration.AC3)
  569.                                         : HTTPResource.MPEG_TYPEMIME;
  570.                         } else { // default: MPEGPSAC3
  571.                                 mimetype = isMediaParserV2()
  572.                                         ? getFormatConfiguration().match(FormatConfiguration.MPEGPS, FormatConfiguration.MPEG2, FormatConfiguration.AC3)
  573.                                         : HTTPResource.MPEG_TYPEMIME;
  574.                         }
  575.                 } else if (mimetype.equals(HTTPResource.AUDIO_TRANSCODE)) {
  576.                         if (isTranscodeToWAV()) {
  577.                                 mimetype = isMediaParserV2()
  578.                                         ? getFormatConfiguration().match(FormatConfiguration.WAV, null, null)
  579.                                         : HTTPResource.AUDIO_WAV_TYPEMIME;
  580.                         } else if (isTranscodeToMP3()) {
  581.                                 mimetype = isMediaParserV2()
  582.                                         ? getFormatConfiguration().match(FormatConfiguration.MP3, null, null)
  583.                                         : HTTPResource.AUDIO_MP3_TYPEMIME;
  584.                         } else { // default: LPCM
  585.                                 mimetype = isMediaParserV2()
  586.                                         ? getFormatConfiguration().match(FormatConfiguration.LPCM, null, null)
  587.                                         : HTTPResource.AUDIO_LPCM_TYPEMIME;
  588.  
  589.                                 if (isTranscodeAudioTo441()) {
  590.                                         mimetype += ";rate=44100;channels=2";
  591.                                 } else {
  592.                                         mimetype += ";rate=48000;channels=2";
  593.                                 }
  594.                         }
  595.  
  596.                         if (isTranscodeToMP3()) {
  597.                                 mimetype = HTTPResource.AUDIO_MP3_TYPEMIME;
  598.                         }
  599.  
  600.                         if (isTranscodeToWAV()) {
  601.                                 mimetype = HTTPResource.AUDIO_WAV_TYPEMIME;
  602.                         }
  603.                 }
  604.  
  605.                 if (mimes.containsKey(mimetype)) {
  606.                         return mimes.get(mimetype);
  607.                 }
  608.  
  609.                 return mimetype;
  610.         }
  611.  
  612.         /**
  613.          * Pattern match a user agent header string to the "UserAgentSearch"
  614.          * expression for this renderer. Will return false when the pattern is
  615.          * empty or when no match can be made.
  616.          *
  617.          * @param header The header containing the user agent.
  618.          * @return True if the pattern matches.
  619.          */
  620.         public boolean matchUserAgent(String header) {
  621.                 String userAgent = getUserAgent();
  622.                 Pattern userAgentPattern = null;
  623.  
  624.                 if (StringUtils.isNotBlank(userAgent)) {
  625.                         userAgentPattern = Pattern.compile(userAgent, Pattern.CASE_INSENSITIVE);
  626.  
  627.                         return userAgentPattern.matcher(header).find();
  628.                 } else {
  629.                         return false;
  630.                 }
  631.         }
  632.  
  633.         /**
  634.          * Pattern match a header string to the "UserAgentAdditionalHeaderSearch"
  635.          * expression for this renderer. Will return false when the pattern is
  636.          * empty or when no match can be made.
  637.          *
  638.          * @param header The additional header string.
  639.          * @return True if the pattern matches.
  640.          */
  641.         public boolean matchAdditionalUserAgent(String header) {
  642.                 String userAgentAdditionalHeader = getUserAgentAdditionalHttpHeaderSearch();
  643.                 Pattern userAgentAddtionalPattern = null;
  644.  
  645.                 if (StringUtils.isNotBlank(userAgentAdditionalHeader)) {
  646.                         userAgentAddtionalPattern = Pattern.compile(userAgentAdditionalHeader, Pattern.CASE_INSENSITIVE);
  647.  
  648.                         return userAgentAddtionalPattern.matcher(header).find();
  649.                 } else {
  650.                         return false;
  651.                 }
  652.         }
  653.  
  654.         /**
  655.          * Returns the pattern to match the User-Agent header to as defined in the
  656.          * renderer configuration. Default value is "".
  657.          *
  658.          * @return The User-Agent search pattern.
  659.          */
  660.         public String getUserAgent() {
  661.                 return getString(USER_AGENT, "");
  662.         }
  663.  
  664.         /**
  665.          * RendererName: Determines the name that is displayed in the PMS user
  666.          * interface when this renderer connects. Default value is "Unknown
  667.          * renderer".
  668.          *
  669.          * @return The renderer name.
  670.          */
  671.         public String getRendererName() {
  672.                 return getString(RENDERER_NAME, Messages.getString("PMS.17"));
  673.         }
  674.  
  675.         /**
  676.          * Returns the icon to use for displaying this renderer in PMS as defined
  677.          * in the renderer configurations. Default value is "unknown.png".
  678.          *
  679.          * @return The renderer icon.
  680.          */
  681.         public String getRendererIcon() {
  682.                 return getString(RENDERER_ICON, "unknown.png");
  683.         }
  684.  
  685.         /**
  686.          * LongFileNameFormat: Determines how media file names are formatted in the
  687.          * regular folders. All supported formatting options are described in
  688.          * {@link net.pms.dlna.DLNAResource#getDisplayName(RendererConfiguration)
  689.          * getDisplayName(RendererConfiguration)}.
  690.          *
  691.          * @return The format for file names in the regular folders.
  692.          */
  693.         public String getLongFileNameFormat() {
  694.                 return getString(LONG_FILE_NAME_FORMAT, Messages.getString("DLNAResource.4"));
  695.         }
  696.  
  697.         /**
  698.          * ShortFileNameFormat: Determines how media file names are formatted in the
  699.          * transcoding virtual folder. All supported formatting options are described in
  700.          * {@link net.pms.dlna.DLNAResource#getDisplayName(RendererConfiguration)
  701.          * getDisplayName(RendererConfiguration)}.
  702.          *
  703.          * @return The format for file names in the transcoding virtual folder.
  704.          */
  705.         public String getShortFileNameFormat() {
  706.                 return getString(SHORT_FILE_NAME_FORMAT, Messages.getString("DLNAResource.3"));
  707.         }
  708.  
  709.         /**
  710.          * Returns the the name of an additional HTTP header whose value should
  711.          * be matched with the additional header search pattern. The header name
  712.          * must be an exact match (read: the header has to start with the exact
  713.          * same case sensitive string). The default value is <code>null</code>.
  714.          *
  715.          * @return The additional HTTP header name.
  716.          */
  717.         public String getUserAgentAdditionalHttpHeader() {
  718.                 return getString(USER_AGENT_ADDITIONAL_HEADER, null);
  719.         }
  720.  
  721.         /**
  722.          * Returns the pattern to match additional headers to as defined in the
  723.          * renderer configuration. Default value is "".
  724.          *
  725.          * @return The User-Agent search pattern.
  726.          */
  727.         public String getUserAgentAdditionalHttpHeaderSearch() {
  728.                 return getString(USER_AGENT_ADDITIONAL_SEARCH, "");
  729.         }
  730.  
  731.         public String getUseSameExtension(String file) {
  732.                 String s = getString(USE_SAME_EXTENSION, null);
  733.  
  734.                 if (s != null) {
  735.                         s = file + "." + s;
  736.                 } else {
  737.                         s = file;
  738.                 }
  739.  
  740.                 return s;
  741.         }
  742.  
  743.         /**
  744.          * Returns true if SeekByTime is set to "true" or "exclusive", false otherwise.
  745.          * Default value is false.
  746.          *
  747.          * @return true if the renderer supports seek-by-time, false otherwise.
  748.          */
  749.         public boolean isSeekByTime() {
  750.                 return isSeekByTimeExclusive() || getBoolean(SEEK_BY_TIME, false);
  751.         }
  752.  
  753.         /**
  754.          * Returns true if SeekByTime is set to "exclusive", false otherwise.
  755.          * Default value is false.
  756.          *
  757.          * @return true if the renderer supports seek-by-time exclusively
  758.          * (i.e. not in conjunction with seek-by-byte), false otherwise.
  759.          */
  760.         public boolean isSeekByTimeExclusive() {
  761.                 return getString(SEEK_BY_TIME, "").equalsIgnoreCase("exclusive");
  762.         }
  763.  
  764.         public boolean isMuxH264MpegTS() {
  765.                 boolean muxCompatible = getBoolean(MUX_H264_WITH_MPEGTS, true);
  766.                 if (isMediaParserV2()) {
  767.                         muxCompatible = getFormatConfiguration().match(FormatConfiguration.MPEGTS, FormatConfiguration.H264, null) != null;
  768.                 }
  769.  
  770.                 if (Platform.isMac() && System.getProperty("os.version") != null && System.getProperty("os.version").contains("10.4.")) {
  771.                         muxCompatible = false; // no tsMuxeR for 10.4 (yet?)
  772.                 }
  773.  
  774.                 return muxCompatible;
  775.         }
  776.  
  777.         public boolean isDTSPlayable() {
  778.                 return isMuxDTSToMpeg() || (isWrapDTSIntoPCM() && isMuxLPCMToMpeg());
  779.         }
  780.  
  781.         public boolean isMuxDTSToMpeg() {
  782.                 if (isMediaParserV2()) {
  783.                         return getFormatConfiguration().isDTSSupported();
  784.                 }
  785.  
  786.                 return getBoolean(MUX_DTS_TO_MPEG, false);
  787.         }
  788.  
  789.         public boolean isWrapDTSIntoPCM() {
  790.                 return getBoolean(WRAP_DTS_INTO_PCM, true);
  791.         }
  792.  
  793.         public boolean isLPCMPlayable() {
  794.                 return isMuxLPCMToMpeg();
  795.         }
  796.  
  797.         public boolean isMuxLPCMToMpeg() {
  798.                 if (isMediaParserV2()) {
  799.                         return getFormatConfiguration().isLPCMSupported();
  800.                 }
  801.  
  802.                 return getBoolean(MUX_LPCM_TO_MPEG, true);
  803.         }
  804.  
  805.         public boolean isMpeg2Supported() {
  806.                 if (isMediaParserV2()) {
  807.                         return getFormatConfiguration().isMpeg2Supported();
  808.                 }
  809.  
  810.                 return isPS3();
  811.         }
  812.  
  813.         /**
  814.          * Returns the codec to use for video transcoding for this renderer as
  815.          * defined in the renderer configuration. Default value is "MPEGPSAC3".
  816.          *
  817.          * @return The codec name.
  818.          */
  819.         public String getVideoTranscode() {
  820.                 return getString(TRANSCODE_VIDEO, MPEGPSAC3);
  821.         }
  822.  
  823.         /**
  824.          * Returns the codec to use for audio transcoding for this renderer as
  825.          * defined in the renderer configuration. Default value is "LPCM".
  826.          *
  827.          * @return The codec name.
  828.          */
  829.         public String getAudioTranscode() {
  830.                 return getString(TRANSCODE_AUDIO, LPCM);
  831.         }
  832.  
  833.         /**
  834.          * Returns whether or not to use the default DVD buffer size for this
  835.          * renderer as defined in the renderer configuration. Default is false.
  836.          *
  837.          * @return True if the default size should be used.
  838.          */
  839.         public boolean isDefaultVBVSize() {
  840.                 return getBoolean(DEFAULT_VBV_BUFSIZE, false);
  841.         }
  842.  
  843.         /**
  844.          * Returns the maximum bitrate (in megabits-per-second) supported by the media renderer as defined
  845.          * in the renderer configuration. The default value is <code>null</code>.
  846.          *
  847.          * @return The bitrate.
  848.          */
  849.         @Deprecated
  850.         // TODO this should return an integer and the units should be bits-per-second
  851.         public String getMaxVideoBitrate() {
  852.                 return getString(MAX_VIDEO_BITRATE, null);
  853.         }
  854.  
  855.         /**
  856.          * Returns the override settings for MEncoder quality settings in PMS as
  857.          * defined in the renderer configuration. The default value is "".
  858.          *
  859.          * @return The MEncoder quality settings.
  860.          */
  861.         public String getCustomMencoderQualitySettings() {
  862.                 return getString(CUSTOM_MENCODER_QUALITY_SETTINGS, "");
  863.         }
  864.  
  865.         /**
  866.          * Returns the override settings for MEncoder custom options in PMS as
  867.          * defined in the renderer configuration. The default value is "".
  868.          *
  869.          * @return The MEncoder custom options.
  870.          */
  871.         public String getCustomMencoderOptions() {
  872.                 return getString(CUSTOM_MENCODER_OPTIONS, "");
  873.         }
  874.  
  875.         /**
  876.          * Returns the maximum video width supported by the renderer as defined in
  877.          * the renderer configuration. The default value 0 means unlimited.
  878.          *
  879.          * @return The maximum video width.
  880.          */
  881.         public int getMaxVideoWidth() {
  882.                 // FIXME why is this 1920 if the default value is 0 (unlimited)?
  883.                 // XXX we should also require width and height to both be 0 or both be > 0
  884.                 return getInt(MAX_VIDEO_WIDTH, 1920);
  885.         }
  886.  
  887.         /**
  888.          * Returns the maximum video height supported by the renderer as defined
  889.          * in the renderer configuration. The default value 0 means unlimited.
  890.          *
  891.          * @return The maximum video height.
  892.          */
  893.         public int getMaxVideoHeight() {
  894.                 // FIXME why is this 1080 if the default value is 0 (unlimited)?
  895.                 // XXX we should also require width and height to both be 0 or both be > 0
  896.                 return getInt(MAX_VIDEO_HEIGHT, 1080);
  897.         }
  898.  
  899.         /**
  900.          * Returns <code>true</code> if the renderer has a maximum supported width
  901.          * or height, <code>false</code> otherwise.
  902.          *
  903.          * @return boolean indicating whether the renderer may need videos to be resized.
  904.          */
  905.         public boolean isVideoRescale() {
  906.                 return getMaxVideoWidth() > 0 && getMaxVideoHeight() > 0;
  907.         }
  908.  
  909.         public boolean isDLNAOrgPNUsed() {
  910.                 return getBoolean(DLNA_ORGPN_USE, true);
  911.         }
  912.  
  913.         /**
  914.          * Returns the comma separated list of file extensions that are forced to
  915.          * be transcoded and never streamed, as defined in the renderer
  916.          * configuration. Default value is "".
  917.          *
  918.          * @return The file extensions.
  919.          */
  920.         public String getTranscodedExtensions() {
  921.                 return getString(TRANSCODE_EXT, "");
  922.         }
  923.  
  924.         /**
  925.          * Returns the comma separated list of file extensions that are forced to
  926.          * be streamed and never transcoded, as defined in the renderer
  927.          * configuration. Default value is "".
  928.          *
  929.          * @return The file extensions.
  930.          */
  931.         public String getStreamedExtensions() {
  932.                 return getString(STREAM_EXT, "");
  933.         }
  934.  
  935.         /**
  936.          * Returns the size to report back to the renderer when transcoding media
  937.          * as defined in the renderer configuration. Default value is 0.
  938.          *
  939.          * @return The size to report.
  940.          */
  941.         public long getTranscodedSize() {
  942.                 return getLong(TRANSCODED_SIZE, 0);
  943.         }
  944.  
  945.         /**
  946.          * Some devices (e.g. Samsung) recognize a custom HTTP header for retrieving
  947.          * the contents of a subtitles file. This method will return the name of that
  948.          * custom HTTP header, or "" if no such header exists. Default value is "".
  949.          *
  950.          * @return The name of the custom HTTP header.
  951.          */
  952.         public String getSubtitleHttpHeader() {
  953.                 return getString(SUBTITLE_HTTP_HEADER, "");
  954.         }
  955.  
  956.         private int getInt(String key, int def) {
  957.                 try {
  958.                         return configuration.getInt(key, def);
  959.                 } catch (ConversionException e) {
  960.                         return def;
  961.                 }
  962.         }
  963.  
  964.         private long getLong(String key, int def) {
  965.                 try {
  966.                         return configuration.getLong(key, def);
  967.                 } catch (ConversionException e) {
  968.                         return def;
  969.                 }
  970.         }
  971.  
  972.         private boolean getBoolean(String key, boolean def) {
  973.                 try {
  974.                         return configuration.getBoolean(key, def);
  975.                 } catch (ConversionException e) {
  976.                         return def;
  977.                 }
  978.         }
  979.  
  980.         /**
  981.      * Return the <code>String</code> value for a given configuration key if the
  982.      * value is non-blank (i.e. not null, not an empty string, not all whitespace).
  983.      * Otherwise return the supplied default value.
  984.      * The value is returned with leading and trailing whitespace removed in both cases.
  985.      * @param key The key to look up.
  986.      * @param def The default value to return when no valid key value can be found.
  987.      * @return The value configured for the key.
  988.      */
  989.     private String getString(String key, String def) {
  990.                 return ConfigurationUtil.getNonBlankConfigurationString(configuration, key, def);
  991.     }
  992.  
  993.         public String toString() {
  994.                 return getRendererName();
  995.         }
  996.  
  997.         public boolean isMediaParserV2() {
  998.                 return getBoolean(MEDIAPARSERV2, false) && LibMediaInfoParser.isValid();
  999.         }
  1000.  
  1001.         public boolean isMediaParserV2ThumbnailGeneration() {
  1002.                 return getBoolean(MEDIAPARSERV2_THUMB, false) && LibMediaInfoParser.isValid();
  1003.         }
  1004.  
  1005.         public boolean isForceJPGThumbnails() {
  1006.                 return (getBoolean(FORCE_JPG_THUMBNAILS, false) && LibMediaInfoParser.isValid()) || isBRAVIA();
  1007.         }
  1008.  
  1009.         public boolean isShowAudioMetadata() {
  1010.                 return getBoolean(SHOW_AUDIO_METADATA, true);
  1011.         }
  1012.  
  1013.         public boolean isShowSubMetadata() {
  1014.                 return getBoolean(SHOW_SUB_METADATA, true);
  1015.         }
  1016.  
  1017.         public boolean isDLNATreeHack() {
  1018.                 return getBoolean(DLNA_TREE_HACK, false) && LibMediaInfoParser.isValid();
  1019.         }
  1020.  
  1021.         /**
  1022.          * Returns whether or not to omit sending a content length header when the
  1023.          * length is unknown, as defined in the renderer configuration. Default
  1024.          * value is false.
  1025.          * <p>
  1026.          * Some renderers are particular about the "Content-Length" headers in
  1027.          * requests (e.g. Sony blu-ray players). By default, PMS will send a
  1028.          * "Content-Length" that refers to the total media size, even if the exact
  1029.          * length is unknown.
  1030.          *
  1031.          * @return True if sending the content length header should be omitted.
  1032.          */
  1033.         public boolean isChunkedTransfer() {
  1034.                 return getBoolean(CHUNKED_TRANSFER, false);
  1035.         }
  1036.  
  1037.         /**
  1038.          * Returns whether or not the renderer can handle the given format
  1039.          * natively, based on its configuration in the renderer.conf. If it can
  1040.          * handle a format natively, content can be streamed to the renderer. If
  1041.          * not, content should be transcoded before sending it to the renderer.
  1042.          *
  1043.          * @param mediainfo The {@link DLNAMediaInfo} information parsed from the
  1044.          *                              media file.
  1045.          * @param format The {@link Format} to test compatibility for.
  1046.          * @return True if the renderer natively supports the format, false
  1047.          *                              otherwise.
  1048.          */
  1049.         public boolean isCompatible(DLNAMediaInfo mediainfo, Format format) {
  1050.                 // Use the configured "Supported" lines in the renderer.conf
  1051.                 // to see if any of them match the MediaInfo library
  1052.                 if (isMediaParserV2() && mediainfo != null && getFormatConfiguration().match(mediainfo) != null) {
  1053.                         return true;
  1054.                 }
  1055.  
  1056.                 if (format != null) {
  1057.                         String noTranscode = "";
  1058.  
  1059.                         if (PMS.getConfiguration() != null) {
  1060.                                 noTranscode = PMS.getConfiguration().getNoTranscode();
  1061.                         }
  1062.  
  1063.                         // Is the format among the ones to be streamed?
  1064.                         return format.skip(noTranscode, getStreamedExtensions());
  1065.                 } else {
  1066.                         // Not natively supported.
  1067.                         return false;
  1068.                 }
  1069.         }
  1070. }
clone this paste RAW Paste Data