Search in sources :

Example 1 with OutputParams

use of net.pms.io.OutputParams in project UniversalMediaServer by UniversalMediaServer.

the class DLNAResource method getDlnaOrgPnFlags.

/**
 * Creates the DLNA.ORG_PN to send.
 * DLNA.ORG_PN is a string that tells the renderer what type of file to expect, like its
 * container, framerate, codecs and resolution.
 * Some renderers will not play a file if it has the wrong DLNA.ORG_PN string, while others
 * are fine with any string or even nothing.
 *
 * @param mediaRenderer
 * 			Media Renderer for which to represent this information.
 * @param localizationValue
 * @return String representation of the DLNA.ORG_PN flags
 */
@SuppressWarnings("deprecation")
private String getDlnaOrgPnFlags(RendererConfiguration mediaRenderer, int localizationValue) {
    // Use device-specific pms conf, if any
    PmsConfiguration configurationSpecificToRenderer = PMS.getConfiguration(mediaRenderer);
    String mime = getRendererMimeType(mediaRenderer);
    String dlnaOrgPnFlags = null;
    if (mediaRenderer.isDLNAOrgPNUsed() || mediaRenderer.isAccurateDLNAOrgPN()) {
        if (mediaRenderer.isPS3()) {
            if (mime.equals(DIVX_TYPEMIME)) {
                dlnaOrgPnFlags = "DLNA.ORG_PN=AVI";
            } else if (mime.equals(WMV_TYPEMIME) && media != null && media.getHeight() > 700) {
                dlnaOrgPnFlags = "DLNA.ORG_PN=WMVHIGH_PRO";
            }
        } else {
            if (mime.equals(MPEG_TYPEMIME)) {
                dlnaOrgPnFlags = "DLNA.ORG_PN=" + getMPEG_PS_PALLocalizedValue(localizationValue);
                if (player != null) {
                    // VLC Web Video (Legacy) and tsMuxeR always output MPEG-TS
                    boolean isFileMPEGTS = TsMuxeRVideo.ID.equals(player.id()) || VideoLanVideoStreaming.ID.equals(player.id());
                    // Check if the renderer settings make the current engine always output MPEG-TS
                    if (!isFileMPEGTS && mediaRenderer.isTranscodeToMPEGTS() && (MEncoderVideo.ID.equals(player.id()) || FFMpegVideo.ID.equals(player.id()) || VLCVideo.ID.equals(player.id()) || AviSynthFFmpeg.ID.equals(player.id()) || AviSynthMEncoder.ID.equals(player.id()))) {
                        isFileMPEGTS = true;
                    }
                    boolean isMuxableResult = getMedia() != null && getMedia().isMuxable(mediaRenderer);
                    // If the engine is capable of automatically muxing to MPEG-TS and the setting is enabled, it might be MPEG-TS
                    if (!isFileMPEGTS && ((configurationSpecificToRenderer.isMencoderMuxWhenCompatible() && MEncoderVideo.ID.equals(player.id())) || (configurationSpecificToRenderer.isFFmpegMuxWithTsMuxerWhenCompatible() && FFMpegVideo.ID.equals(player.id())))) {
                        /**
                         * Media renderer needs ORG_PN to be accurate.
                         * If the value does not match the media, it won't play the media.
                         * Often we can lazily predict the correct value to send, but due to
                         * MEncoder needing to mux via tsMuxeR, we need to work it all out
                         * before even sending the file list to these devices.
                         * This is very time-consuming so we should a) avoid using this
                         * chunk of code whenever possible, and b) design a better system.
                         * Ideally we would just mux to MPEG-PS instead of MPEG-TS so we could
                         * know it will always be PS, but most renderers will not accept H.264
                         * inside MPEG-PS. Another option may be to always produce MPEG-TS
                         * instead and we should check if that will be OK for all renderers.
                         *
                         * This code block comes from Player.setAudioAndSubs()
                         */
                        if (mediaRenderer.isAccurateDLNAOrgPN()) {
                            boolean finishedMatchingPreferences = false;
                            OutputParams params = new OutputParams(configurationSpecificToRenderer);
                            if (params.aid == null && media != null && media.getFirstAudioTrack() != null) {
                                // check for preferred audio
                                DLNAMediaAudio dtsTrack = null;
                                StringTokenizer st = new StringTokenizer(configurationSpecificToRenderer.getAudioLanguages(), ",");
                                while (st.hasMoreTokens()) {
                                    String lang = st.nextToken().trim();
                                    LOGGER.trace("Looking for an audio track with lang: " + lang);
                                    for (DLNAMediaAudio audio : media.getAudioTracksList()) {
                                        if (audio.matchCode(lang)) {
                                            params.aid = audio;
                                            LOGGER.trace("Matched audio track: " + audio);
                                            break;
                                        }
                                        if (dtsTrack == null && audio.isDTS()) {
                                            dtsTrack = audio;
                                        }
                                    }
                                }
                                // preferred audio not found, take a default audio track, dts first if available
                                if (dtsTrack != null) {
                                    params.aid = dtsTrack;
                                    LOGGER.trace("Found priority audio track with DTS: " + dtsTrack);
                                } else {
                                    params.aid = media.getAudioTracksList().get(0);
                                    LOGGER.trace("Chose a default audio track: " + params.aid);
                                }
                            }
                            String currentLang = null;
                            DLNAMediaSubtitle matchedSub = null;
                            if (params.aid != null) {
                                currentLang = params.aid.getLang();
                            }
                            if (params.sid != null && params.sid.getId() == -1) {
                                LOGGER.trace("Don't want subtitles!");
                                params.sid = null;
                                media_subtitle = params.sid;
                                finishedMatchingPreferences = true;
                            }
                            /**
                             * Check for live subtitles
                             */
                            if (!finishedMatchingPreferences && params.sid != null && !StringUtils.isEmpty(params.sid.getLiveSubURL())) {
                                LOGGER.debug("Live subtitles " + params.sid.getLiveSubURL());
                                try {
                                    matchedSub = params.sid;
                                    String file = OpenSubtitle.fetchSubs(matchedSub.getLiveSubURL(), matchedSub.getLiveSubFile());
                                    if (!StringUtils.isEmpty(file)) {
                                        matchedSub.setExternalFile(new File(file), null);
                                        params.sid = matchedSub;
                                        media_subtitle = params.sid;
                                        finishedMatchingPreferences = true;
                                    }
                                } catch (IOException e) {
                                }
                            }
                            if (!finishedMatchingPreferences) {
                                StringTokenizer st = new StringTokenizer(configurationSpecificToRenderer.getAudioSubLanguages(), ";");
                                /**
                                 * Check for external and internal subtitles matching the user's language
                                 * preferences
                                 */
                                boolean matchedInternalSubtitles = false;
                                boolean matchedExternalSubtitles = false;
                                while (st.hasMoreTokens()) {
                                    String pair = st.nextToken();
                                    if (pair.contains(",")) {
                                        String audio = pair.substring(0, pair.indexOf(','));
                                        String sub = pair.substring(pair.indexOf(',') + 1);
                                        audio = audio.trim();
                                        sub = sub.trim();
                                        if (currentLang != null && LOGGER.isTraceEnabled()) {
                                            LOGGER.trace("Searching for a match for language \"{}\" with audio \"{}\" and subtitle \"{}\"", currentLang, audio, sub);
                                        }
                                        if (Iso639.isCodesMatching(audio, currentLang) || (currentLang != null && audio.equals("*"))) {
                                            if (sub.equals("off")) {
                                                /**
                                                 * Ignore the "off" language for external subtitles if the user setting is enabled
                                                 * TODO: Prioritize multiple external subtitles properly instead of just taking the first one we load
                                                 */
                                                if (configurationSpecificToRenderer.isForceExternalSubtitles()) {
                                                    for (DLNAMediaSubtitle present_sub : media.getSubtitleTracksList()) {
                                                        if (present_sub.getExternalFile() != null) {
                                                            matchedSub = present_sub;
                                                            matchedExternalSubtitles = true;
                                                            LOGGER.trace("Ignoring the \"off\" language because there are external subtitles");
                                                            break;
                                                        }
                                                    }
                                                }
                                                if (!matchedExternalSubtitles) {
                                                    matchedSub = new DLNAMediaSubtitle();
                                                    matchedSub.setLang("off");
                                                }
                                            } else if (getMedia() != null) {
                                                for (DLNAMediaSubtitle present_sub : media.getSubtitleTracksList()) {
                                                    if (present_sub.matchCode(sub) || sub.equals("*")) {
                                                        if (present_sub.getExternalFile() != null) {
                                                            if (configurationSpecificToRenderer.isAutoloadExternalSubtitles()) {
                                                                // Subtitle is external and we want external subtitles, look no further
                                                                matchedSub = present_sub;
                                                                LOGGER.trace("Matched external subtitles track: {}", matchedSub);
                                                                break;
                                                            }
                                                            // Subtitle is external but we do not want external subtitles, keep searching
                                                            LOGGER.trace("External subtitles ignored because of user setting: {}", present_sub);
                                                        } else if (!matchedInternalSubtitles) {
                                                            matchedSub = present_sub;
                                                            LOGGER.trace("Matched internal subtitles track: {}", matchedSub);
                                                            if (configurationSpecificToRenderer.isAutoloadExternalSubtitles()) {
                                                                // Subtitle is internal and we will wait to see if an external one is available instead
                                                                matchedInternalSubtitles = true;
                                                            } else {
                                                                // Subtitle is internal and we will use it
                                                                break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            if (matchedSub != null && !matchedInternalSubtitles) {
                                                break;
                                            }
                                        }
                                    }
                                }
                                /**
                                 * Check for external subtitles that were skipped in the above code block
                                 * because they didn't match language preferences, if there wasn't already
                                 * a match and the user settings specify it.
                                 */
                                if (matchedSub == null && configurationSpecificToRenderer.isForceExternalSubtitles()) {
                                    for (DLNAMediaSubtitle present_sub : media.getSubtitleTracksList()) {
                                        if (present_sub.getExternalFile() != null) {
                                            matchedSub = present_sub;
                                            LOGGER.trace("Matched external subtitles track that did not match language preferences: " + matchedSub);
                                            break;
                                        }
                                    }
                                }
                                /**
                                 * Disable chosen subtitles if the user has disabled all subtitles or
                                 * if the language preferences have specified the "off" language.
                                 *
                                 * TODO: Can't we save a bunch of looping by checking for isDisableSubtitles
                                 * just after the Live Subtitles check above?
                                 */
                                if (matchedSub != null && params.sid == null) {
                                    if (configurationSpecificToRenderer.isDisableSubtitles() || (matchedSub.getLang() != null && matchedSub.getLang().equals("off"))) {
                                        LOGGER.trace("Disabled the subtitles: " + matchedSub);
                                    } else {
                                        if (mediaRenderer.isExternalSubtitlesFormatSupported(matchedSub, media)) {
                                            matchedSub.setSubsStreamable(true);
                                        }
                                        params.sid = matchedSub;
                                        media_subtitle = params.sid;
                                    }
                                }
                                /**
                                 * Check for forced subtitles.
                                 */
                                if (!configurationSpecificToRenderer.isDisableSubtitles() && params.sid == null && media != null) {
                                    // Check for subtitles again
                                    File video = new File(getSystemName());
                                    FileUtil.isSubtitlesExists(video, media, false);
                                    if (configurationSpecificToRenderer.isAutoloadExternalSubtitles()) {
                                        boolean forcedSubsFound = false;
                                        // Priority to external subtitles
                                        for (DLNAMediaSubtitle sub : media.getSubtitleTracksList()) {
                                            if (matchedSub != null && matchedSub.getLang() != null && matchedSub.getLang().equals("off")) {
                                                st = new StringTokenizer(configurationSpecificToRenderer.getForcedSubtitleTags(), ",");
                                                while (sub.getSubtitlesTrackTitleFromMetadata() != null && st.hasMoreTokens()) {
                                                    String forcedTags = st.nextToken();
                                                    forcedTags = forcedTags.trim();
                                                    if (sub.getSubtitlesTrackTitleFromMetadata().toLowerCase().contains(forcedTags) && Iso639.isCodesMatching(sub.getLang(), configurationSpecificToRenderer.getForcedSubtitleLanguage())) {
                                                        LOGGER.trace("Forcing preferred subtitles: " + sub.getLang() + "/" + sub.getSubtitlesTrackTitleFromMetadata());
                                                        LOGGER.trace("Forced subtitles track: " + sub);
                                                        if (sub.getExternalFile() != null) {
                                                            LOGGER.trace("Found external forced file: " + sub.getExternalFile().getAbsolutePath());
                                                        }
                                                        if (mediaRenderer.isExternalSubtitlesFormatSupported(sub, media)) {
                                                            sub.setSubsStreamable(true);
                                                        }
                                                        params.sid = sub;
                                                        media_subtitle = params.sid;
                                                        forcedSubsFound = true;
                                                        break;
                                                    }
                                                }
                                                if (forcedSubsFound == true) {
                                                    break;
                                                }
                                            } else {
                                                LOGGER.trace("Found subtitles track: " + sub);
                                                if (sub.getExternalFile() != null) {
                                                    LOGGER.trace("Found external file: " + sub.getExternalFile().getAbsolutePath());
                                                    if (mediaRenderer.isExternalSubtitlesFormatSupported(sub, media)) {
                                                        sub.setSubsStreamable(true);
                                                    }
                                                    params.sid = sub;
                                                    media_subtitle = params.sid;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                    if (matchedSub != null && matchedSub.getLang() != null && matchedSub.getLang().equals("off")) {
                                        finishedMatchingPreferences = true;
                                    }
                                    if (!finishedMatchingPreferences && params.sid == null) {
                                        st = new StringTokenizer(UMSUtils.getLangList(params.mediaRenderer), ",");
                                        while (st.hasMoreTokens()) {
                                            String lang = st.nextToken();
                                            lang = lang.trim();
                                            LOGGER.trace("Looking for a subtitle track with lang: " + lang);
                                            for (DLNAMediaSubtitle sub : media.getSubtitleTracksList()) {
                                                if (sub.matchCode(lang) && !(!configurationSpecificToRenderer.isAutoloadExternalSubtitles() && sub.getExternalFile() != null)) {
                                                    if (mediaRenderer.isExternalSubtitlesFormatSupported(sub, media)) {
                                                        sub.setSubsStreamable(true);
                                                    }
                                                    params.sid = sub;
                                                    LOGGER.trace("Matched subtitles track: " + params.sid);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            if (media_subtitle == null) {
                                LOGGER.trace("We do not want a subtitle for " + getName());
                            } else {
                                LOGGER.trace("We do want a subtitle for " + getName());
                            }
                        }
                        /**
                         * If:
                         * - There are no subtitles
                         * - This is not a DVD track
                         * - The media is muxable
                         * - The renderer accepts media muxed to MPEG-TS
                         * then the file is MPEG-TS
                         */
                        if (media_subtitle == null && !hasExternalSubtitles() && media != null && media.getDvdtrack() == 0 && isMuxableResult && mediaRenderer.isMuxH264MpegTS()) {
                            isFileMPEGTS = true;
                        }
                    }
                    if (isFileMPEGTS) {
                        dlnaOrgPnFlags = "DLNA.ORG_PN=" + getMPEG_TS_SD_EU_ISOLocalizedValue(localizationValue);
                        if (media.isH264() && !VideoLanVideoStreaming.ID.equals(player.id()) && isMuxableResult) {
                            dlnaOrgPnFlags = "DLNA.ORG_PN=AVC_TS_HD_24_AC3_ISO";
                            if (mediaRenderer.isTranscodeToMPEGTSH264AAC()) {
                                dlnaOrgPnFlags = "DLNA.ORG_PN=AVC_TS_HP_HD_AAC";
                            }
                        }
                    }
                } else if (media != null) {
                    if (media.isMpegTS()) {
                        dlnaOrgPnFlags = "DLNA.ORG_PN=" + getMPEG_TS_EULocalizedValue(localizationValue, media.isHDVideo());
                        if (media.isH264()) {
                            dlnaOrgPnFlags = "DLNA.ORG_PN=AVC_TS_HD_50_AC3";
                            if (mediaRenderer.isTranscodeToMPEGTSH264AAC()) {
                                dlnaOrgPnFlags = "DLNA.ORG_PN=AVC_TS_HP_HD_AAC";
                            }
                        }
                    }
                }
            } else if (media != null && mime.equals("video/vnd.dlna.mpeg-tts")) {
                // patters - on Sony BDP m2ts clips aren't listed without this
                dlnaOrgPnFlags = "DLNA.ORG_PN=" + getMPEG_TS_EULocalizedValue(localizationValue, media.isHDVideo());
            } else if (media != null && mime.equals(JPEG_TYPEMIME)) {
                int width = media.getWidth();
                int height = media.getHeight();
                if (width > 1024 || height > 768) {
                    // 1024 * 768
                    dlnaOrgPnFlags = "DLNA.ORG_PN=JPEG_LRG";
                } else if (width > 640 || height > 480) {
                    // 640 * 480
                    dlnaOrgPnFlags = "DLNA.ORG_PN=JPEG_MED";
                } else if (width > 160 || height > 160) {
                    // 160 * 160
                    dlnaOrgPnFlags = "DLNA.ORG_PN=JPEG_SM";
                } else {
                    dlnaOrgPnFlags = "DLNA.ORG_PN=JPEG_TN";
                }
            } else if (mime.equals(AUDIO_MP3_TYPEMIME)) {
                dlnaOrgPnFlags = "DLNA.ORG_PN=MP3";
            } else if (mime.substring(0, 9).equals(AUDIO_LPCM_TYPEMIME) || mime.equals(AUDIO_WAV_TYPEMIME)) {
                dlnaOrgPnFlags = "DLNA.ORG_PN=LPCM";
            }
        }
        if (dlnaOrgPnFlags != null) {
            dlnaOrgPnFlags = "DLNA.ORG_PN=" + mediaRenderer.getDLNAPN(dlnaOrgPnFlags.substring(12));
        }
    }
    return dlnaOrgPnFlags;
}
Also used : PmsConfiguration(net.pms.configuration.PmsConfiguration) OutputParams(net.pms.io.OutputParams)

Example 2 with OutputParams

use of net.pms.io.OutputParams in project UniversalMediaServer by UniversalMediaServer.

the class DVDISOFile method resolveOnce.

@Override
protected void resolveOnce() {
    double[] titles = new double[100];
    String[] cmd = new String[] { configuration.getMplayerPath(), "-identify", "-endpos", "0", "-ao", "null", "-vc", "null", "-vo", "null", "-dvd-device", ProcessUtil.getShortFileNameIfWideChars(file.getAbsolutePath()), "dvd://" };
    OutputParams params = new OutputParams(configuration);
    params.maxBufferSize = 1;
    params.log = true;
    final ProcessWrapperImpl pw = new ProcessWrapperImpl(cmd, params, true, false);
    Runnable r = new Runnable() {

        @Override
        public void run() {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
            }
            pw.stopProcess();
        }
    };
    Thread failsafe = new Thread(r, "DVDISO Failsafe");
    failsafe.start();
    pw.runInSameThread();
    List<String> lines = pw.getOtherResults();
    if (lines != null) {
        for (String line : lines) {
            if (line.startsWith("ID_DVD_TITLE_") && line.contains("_LENGTH")) {
                int rank = Integer.parseInt(line.substring(13, line.indexOf("_LENGT")));
                double duration = Double.parseDouble(line.substring(line.lastIndexOf("LENGTH=") + 7));
                titles[rank] = duration;
            } else if (line.startsWith("ID_DVD_VOLUME_ID")) {
                String volumeId = line.substring(line.lastIndexOf("_ID=") + 4).trim();
                if (configuration.isPrettifyFilenames()) {
                    volumeId = volumeId.replaceAll("_", " ");
                    if (isNotBlank(volumeId) && volumeId.equals(volumeId.toUpperCase(PMS.getLocale()))) {
                        volumeId = WordUtils.capitalize(volumeId.toLowerCase(PMS.getLocale()));
                    }
                }
                this.volumeId = volumeId;
            }
        }
    }
    double oldduration = -1;
    for (int i = 1; i < 99; i++) {
        /**
         * Don't take into account titles less than 10 seconds
         * Also, workaround for the MPlayer bug which reports a unique title with the same length several times
         * The "maybe wrong" title is taken into account only if its duration is less than 1 hour.
         * Common-sense is a single video track on a DVD is usually greater than 1h
         */
        if (titles[i] > 10 && (titles[i] != oldduration || oldduration < 3600)) {
            DVDISOTitle dvd = new DVDISOTitle(file, volumeId, i);
            addChild(dvd);
            oldduration = titles[i];
        }
    }
    if (childrenNumber() > 0) {
        PMS.get().storeFileInCache(file, Format.ISO);
    }
}
Also used : OutputParams(net.pms.io.OutputParams) ProcessWrapperImpl(net.pms.io.ProcessWrapperImpl)

Example 3 with OutputParams

use of net.pms.io.OutputParams in project UniversalMediaServer by UniversalMediaServer.

the class DLNAMediaInfo method getMplayerThumbnail.

private ProcessWrapperImpl getMplayerThumbnail(InputFile media, boolean resume, RendererConfiguration renderer) throws IOException {
    File file = media.getFile();
    String[] args = new String[14];
    args[0] = configuration.getMplayerPath();
    args[1] = "-ss";
    if (resume) {
        args[2] = "" + (int) getDurationInSeconds();
    } else {
        args[2] = "" + configuration.getThumbnailSeekPos();
    }
    args[3] = "-quiet";
    if (file != null) {
        args[4] = ProcessUtil.getShortFileNameIfWideChars(file.getAbsolutePath());
    } else {
        args[4] = "-";
    }
    args[5] = "-msglevel";
    args[6] = "all=4";
    int thumbnailWidth = 320;
    int thumbnailHeight = 180;
    boolean isThumbnailPadding = true;
    if (renderer != null) {
        thumbnailWidth = renderer.getThumbnailWidth();
        thumbnailHeight = renderer.getThumbnailHeight();
        isThumbnailPadding = renderer.isThumbnailPadding();
    }
    if (isThumbnailPadding) {
        args[7] = "-vf";
        args[8] = "scale=" + thumbnailWidth + ":-2,expand=:" + thumbnailHeight;
    } else {
        args[7] = "-vf";
        args[8] = "scale=" + thumbnailWidth + ":-2";
    }
    args[9] = "-frames";
    args[10] = "1";
    args[11] = "-vo";
    String frameName = "" + media.hashCode();
    frameName = "mplayer_thumbs:subdirs=\"" + frameName + "\"";
    frameName = frameName.replace(',', '_');
    args[12] = "jpeg:outdir=" + frameName;
    args[13] = "-nosound";
    OutputParams params = new OutputParams(configuration);
    params.workDir = configuration.getTempFolder();
    params.maxBufferSize = 1;
    params.stdin = media.getPush();
    params.log = true;
    // not serious if anything happens during the thumbnailer
    params.noexitcheck = true;
    final ProcessWrapperImpl pw = new ProcessWrapperImpl(args, true, params);
    // FAILSAFE
    synchronized (parsingLock) {
        parsing = true;
    }
    Runnable r = new Runnable() {

        @Override
        public void run() {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
            pw.stopProcess();
            synchronized (parsingLock) {
                parsing = false;
            }
        }
    };
    Thread failsafe = new Thread(r, "MPlayer Thumbnail Failsafe");
    failsafe.start();
    pw.runInSameThread();
    synchronized (parsingLock) {
        parsing = false;
    }
    return pw;
}
Also used : OutputParams(net.pms.io.OutputParams) AudioFile(org.jaudiotagger.audio.AudioFile) ProcessWrapperImpl(net.pms.io.ProcessWrapperImpl)

Example 4 with OutputParams

use of net.pms.io.OutputParams in project UniversalMediaServer by UniversalMediaServer.

the class RemotePlayHandler method mkPage.

private String mkPage(String id, HttpExchange t) throws IOException {
    HashMap<String, Object> vars = new HashMap<>();
    vars.put("serverName", configuration.getServerDisplayName());
    LOGGER.debug("Make play page " + id);
    RootFolder root = parent.getRoot(RemoteUtil.userName(t), t);
    if (root == null) {
        LOGGER.debug("root not found");
        throw new IOException("Unknown root");
    }
    WebRender renderer = (WebRender) root.getDefaultRenderer();
    renderer.setBrowserInfo(RemoteUtil.getCookie("UMSINFO", t), t.getRequestHeaders().getFirst("User-agent"));
    // List<DLNAResource> res = root.getDLNAResources(id, false, 0, 0, renderer);
    DLNAResource r = root.getDLNAResource(id, renderer);
    if (r == null) {
        LOGGER.debug("Bad web play id: " + id);
        throw new IOException("Bad Id");
    }
    if (!r.isCodeValid(r)) {
        LOGGER.debug("coded object with invalid code");
        throw new IOException("Bad code");
    }
    if (r instanceof VirtualVideoAction) {
        // waste of resource to play dummy video
        if (((VirtualVideoAction) r).enable()) {
            renderer.notify(renderer.INFO, r.getName() + " enabled");
        } else {
            renderer.notify(renderer.INFO, r.getName() + " disabled");
        }
        return returnPage();
    }
    Format format = r.getFormat();
    boolean isImage = format.isImage();
    boolean isVideo = format.isVideo();
    boolean isAudio = format.isAudio();
    String query = t.getRequestURI().getQuery();
    boolean forceFlash = StringUtils.isNotEmpty(RemoteUtil.getQueryVars(query, "flash"));
    boolean forcehtml5 = StringUtils.isNotEmpty(RemoteUtil.getQueryVars(query, "html5"));
    boolean flowplayer = isVideo && (forceFlash || (!forcehtml5 && configuration.getWebFlash()));
    // hack here to ensure we got a root folder to use for recently played etc.
    root.getDefaultRenderer().setRootFolder(root);
    String id1 = URLEncoder.encode(id, "UTF-8");
    String name = StringEscapeUtils.escapeHtml(r.resumeName());
    String mime = root.getDefaultRenderer().getMimeType(r.mimeType(), r.getMedia());
    String mediaType = isVideo ? "video" : isAudio ? "audio" : isImage ? "image" : "";
    String auto = "autoplay";
    @SuppressWarnings("unused") String coverImage = "";
    if (isVideo) {
        if (mime.equals(FormatConfiguration.MIMETYPE_AUTO)) {
            if (r.getMedia() != null && r.getMedia().getMimeType() != null) {
                mime = r.getMedia().getMimeType();
            }
        }
        if (!flowplayer) {
            if (!RemoteUtil.directmime(mime) || RemoteUtil.transMp4(mime, r.getMedia()) || r.isResume()) {
                WebRender render = (WebRender) r.getDefaultRenderer();
                mime = render != null ? render.getVideoMimeType() : RemoteUtil.transMime();
            }
        }
    }
    vars.put("isVideo", isVideo);
    vars.put("name", name);
    vars.put("id1", id1);
    vars.put("autoContinue", configuration.getWebAutoCont(format));
    if (configuration.isDynamicPls()) {
        if (r.getParent() instanceof Playlist) {
            vars.put("plsOp", "del");
            vars.put("plsSign", "-");
            vars.put("plsAttr", RemoteUtil.getMsgString("Web.4", t));
        } else {
            vars.put("plsOp", "add");
            vars.put("plsSign", "+");
            vars.put("plsAttr", RemoteUtil.getMsgString("Web.5", t));
        }
    }
    addNextByType(r, vars);
    if (isImage) {
        // do this like this to simplify the code
        // skip all player crap since img tag works well
        int delay = configuration.getWebImgSlideDelay() * 1000;
        if (delay > 0 && configuration.getWebAutoCont(format)) {
            vars.put("delay", delay);
        }
    } else {
        vars.put("mediaType", mediaType);
        vars.put("auto", auto);
        vars.put("mime", mime);
        if (flowplayer) {
            if (RemoteUtil.directmime(mime) && !RemoteUtil.transMp4(mime, r.getMedia()) && !r.isResume() && !forceFlash) {
                vars.put("src", true);
            }
        } else {
            vars.put("width", renderer.getVideoWidth());
            vars.put("height", renderer.getVideoHeight());
        }
    }
    if (configuration.useWebControl()) {
        vars.put("push", true);
    }
    if (isVideo && configuration.getWebSubs()) {
        // only if subs are requested as <track> tags
        // otherwise we'll transcode them in
        boolean isFFmpegFontConfig = configuration.isFFmpegFontConfig();
        if (isFFmpegFontConfig) {
            // do not apply fontconfig to flowplayer subs
            configuration.setFFmpegFontConfig(false);
        }
        OutputParams p = new OutputParams(configuration);
        p.sid = r.getMediaSubtitle();
        Player.setAudioAndSubs(r.getName(), r.getMedia(), p);
        if (p.sid != null && p.sid.getType().isText()) {
            try {
                File subFile = SubtitleUtils.getSubtitles(r, r.getMedia(), p, configuration, SubtitleType.WEBVTT);
                LOGGER.debug("subFile " + subFile);
                if (subFile != null) {
                    vars.put("sub", parent.getResources().add(subFile));
                }
            } catch (Exception e) {
                LOGGER.debug("error when doing sub file " + e);
            }
        }
        // return back original fontconfig value
        configuration.setFFmpegFontConfig(isFFmpegFontConfig);
    }
    return parent.getResources().getTemplate(isImage ? "image.html" : flowplayer ? "flow.html" : "play.html").execute(vars);
}
Also used : WebRender(net.pms.configuration.WebRender) HashMap(java.util.HashMap) IOException(java.io.IOException) IOException(java.io.IOException) DLNAResource(net.pms.dlna.DLNAResource) Playlist(net.pms.dlna.Playlist) Format(net.pms.formats.Format) VirtualVideoAction(net.pms.dlna.virtual.VirtualVideoAction) RootFolder(net.pms.dlna.RootFolder) OutputParams(net.pms.io.OutputParams) File(java.io.File)

Example 5 with OutputParams

use of net.pms.io.OutputParams in project UniversalMediaServer by UniversalMediaServer.

the class DCRaw method getThumbnail.

/**
 * Extracts or generates a thumbnail for {@code fileName}.
 *
 * @param params the {@link OutputParams} to use. Can be {@code null}.
 * @param fileName the path of the image file to process.
 * @param imageInfo the {@link ImageInfo} for the image file.
 * @return A byte array containing the thumbnail or {@code null}.
 * @throws IOException if an IO error occurs.
 */
@Override
public byte[] getThumbnail(OutputParams params, String fileName, ImageInfo imageInfo) {
    boolean trace = LOGGER.isTraceEnabled();
    if (trace) {
        LOGGER.trace("Extracting thumbnail from \"{}\" with DCRaw", fileName);
    }
    if (params == null) {
        params = new OutputParams(PMS.getConfiguration());
    }
    // Use device-specific pms conf
    PmsConfiguration configuration = PMS.getConfiguration(params);
    params.log = false;
    // This is a wild guess at a decent buffer size for an embedded thumbnail.
    // Every time the buffer has to grow, the whole buffer must be copied in memory.
    params.outputByteArrayStreamBufferSize = 150000;
    // First try to get the embedded thumbnail
    String[] cmdArray = new String[6];
    cmdArray[0] = configuration.getDCRawPath();
    cmdArray[1] = "-e";
    cmdArray[2] = "-c";
    cmdArray[3] = "-M";
    cmdArray[4] = "-w";
    cmdArray[5] = fileName;
    ProcessWrapperImpl pw = new ProcessWrapperImpl(cmdArray, true, params, false, true);
    pw.runInSameThread();
    byte[] bytes = pw.getOutputByteArray().toByteArray();
    List<String> results = pw.getResults();
    if (bytes.length > 0) {
        // DCRaw doesn't seem to apply Exif Orientation to embedded thumbnails, handle it
        boolean isJPEG = (bytes[0] & 0xFF) == 0xFF && (bytes[1] & 0xFF) == 0xD8;
        ExifOrientation thumbnailOrientation = null;
        Dimension jpegResolution = null;
        int exifOrientationOffset = -1;
        if (isJPEG) {
            try {
                ByteArrayReader reader = new ByteArrayReader(bytes);
                exifOrientationOffset = ImagesUtil.getJPEGExifIFDTagOffset(0x112, reader);
                jpegResolution = ImagesUtil.getJPEGResolution(reader);
            } catch (IOException e) {
                exifOrientationOffset = -1;
                LOGGER.debug("Unexpected error while trying to find Exif orientation offset in embedded thumbnail for \"{}\": {}", fileName, e.getMessage());
                LOGGER.trace("", e);
            }
            if (exifOrientationOffset > 0) {
                thumbnailOrientation = ExifOrientation.typeOf(bytes[exifOrientationOffset]);
            } else {
                LOGGER.debug("Couldn't find Exif orientation in the thumbnail extracted from \"{}\"", fileName);
            }
        }
        ExifOrientation imageOrientation = imageInfo instanceof ExifInfo ? ((ExifInfo) imageInfo).getOriginalExifOrientation() : null;
        if (imageOrientation != null && imageOrientation != thumbnailOrientation) {
            if (thumbnailOrientation != null) {
                if (imageInfo.getWidth() > 0 && imageInfo.getHeight() > 0 && jpegResolution != null && jpegResolution.getWidth() > 0 && jpegResolution.getHeight() > 0) {
                    // Try to determine which orientation to trust
                    double imageAspect, thumbnailAspect;
                    if (ImagesUtil.isExifAxesSwapNeeded(imageOrientation)) {
                        imageAspect = (double) imageInfo.getHeight() / imageInfo.getWidth();
                    } else {
                        imageAspect = (double) imageInfo.getWidth() / imageInfo.getHeight();
                    }
                    if (ImagesUtil.isExifAxesSwapNeeded(thumbnailOrientation)) {
                        thumbnailAspect = (double) jpegResolution.getHeight() / jpegResolution.getWidth();
                    } else {
                        thumbnailAspect = (double) jpegResolution.getWidth() / jpegResolution.getHeight();
                    }
                    if (Math.abs(imageAspect - thumbnailAspect) > 0.001d) {
                        // The image and the thumbnail seems to have different aspect ratios, use that of the image
                        bytes[exifOrientationOffset] = (byte) imageOrientation.getValue();
                    }
                }
            } else if (imageOrientation != ExifOrientation.TOP_LEFT) {
                // Apply the orientation to the thumbnail
                try {
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    Thumbnails.of(new ByteArrayInputStream(bytes)).scale(1.0d).addFilter(ExifFilterUtils.getFilterForOrientation(imageOrientation.getThumbnailatorOrientation())).outputFormat(// PNG here to avoid further degradation from rotation
                    "PNG").outputQuality(1.0f).toOutputStream(outputStream);
                    bytes = outputStream.toByteArray();
                } catch (IOException e) {
                    LOGGER.error("Unexpected error when trying to rotate thumbnail for \"{}\" - cancelling rotation: {}", fileName, e.getMessage());
                    LOGGER.trace("", e);
                }
            }
        }
    }
    if (bytes.length == 0 || !results.isEmpty() && results.get(0).contains("has no thumbnail")) {
        // No embedded thumbnail retrieved, generate thumbnail from the actual file
        if (trace) {
            LOGGER.trace("No embedded thumbnail found in \"{}\", " + "trying to generate thumbnail from the image itself", fileName);
        }
        params.outputByteArrayStreamBufferSize = imageInfo != null && imageInfo.getSize() != ImageInfo.SIZE_UNKNOWN ? (int) imageInfo.getSize() / 4 : 500000;
        cmdArray[1] = "-h";
        pw = new ProcessWrapperImpl(cmdArray, true, params);
        pw.runInSameThread();
        bytes = pw.getOutputByteArray().toByteArray();
    }
    if (trace && (bytes == null || bytes.length == 0)) {
        LOGGER.trace("Failed to generate thumbnail with DCRaw for image \"{}\"", fileName);
    }
    return bytes != null && bytes.length > 0 ? bytes : null;
}
Also used : Dimension(java.awt.Dimension) IOException(java.io.IOException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) PmsConfiguration(net.pms.configuration.PmsConfiguration) ByteArrayInputStream(java.io.ByteArrayInputStream) ExifInfo(net.pms.image.ExifInfo) OutputParams(net.pms.io.OutputParams) ExifOrientation(net.pms.image.ExifOrientation) ByteArrayReader(com.drew.lang.ByteArrayReader) ProcessWrapperImpl(net.pms.io.ProcessWrapperImpl)

Aggregations

OutputParams (net.pms.io.OutputParams)17 ProcessWrapperImpl (net.pms.io.ProcessWrapperImpl)10 IOException (java.io.IOException)5 PmsConfiguration (net.pms.configuration.PmsConfiguration)5 ProcessWrapper (net.pms.io.ProcessWrapper)4 InputStream (java.io.InputStream)3 Matcher (java.util.regex.Matcher)3 DLNAResource (net.pms.dlna.DLNAResource)3 ImagePlayer (net.pms.encoders.ImagePlayer)3 Format (net.pms.formats.Format)3 ByteArrayInputStream (java.io.ByteArrayInputStream)2 File (java.io.File)2 FileInputStream (java.io.FileInputStream)2 OutputStream (java.io.OutputStream)2 MalformedURLException (java.net.MalformedURLException)2 Socket (java.net.Socket)2 URL (java.net.URL)2 SimpleDateFormat (java.text.SimpleDateFormat)2 ArrayList (java.util.ArrayList)2 ParserConfigurationException (javax.xml.parsers.ParserConfigurationException)2