/** * decode palette from the input stream * * @param pic SubPicture object containing info about the current caption * @return * @throws CoreException */ private Palette decodePalette(SubPictureBD pic) throws CoreException { boolean fadeOut = false; int paletteIndex; List<PaletteInfo> paletteInfos = pic.getPalettes().get(pic.getImageObject().getPaletteID()); if (paletteInfos == null) { throw new CoreException("Palette ID out of bounds."); } Palette palette = new Palette(256, Core.usesBT601()); // by definition, index 0xff is always completely transparent // also all entries must be fully transparent after initialization try { for (PaletteInfo paletteInfo : paletteInfos) { int index = paletteInfo.getPaletteOffset(); for (int i = 0; i < paletteInfo.getPaletteSize(); i++) { // each palette entry consists of 5 bytes paletteIndex = buffer.getByte(index); int y = buffer.getByte(++index); int cr, cb; if (configuration.isSwapCrCb()) { cb = buffer.getByte(++index); cr = buffer.getByte(++index); } else { cr = buffer.getByte(++index); cb = buffer.getByte(++index); } int alpha = buffer.getByte(++index); int alphaOld = palette.getAlpha(paletteIndex); // avoid fading out if (alpha >= alphaOld) { if (alpha < configuration .getAlphaCrop()) { // to not mess with scaling algorithms, make transparent // color black y = 16; cr = 128; cb = 128; } palette.setAlpha(paletteIndex, alpha); } else { fadeOut = true; } palette.setYCbCr(paletteIndex, y, cb, cr); index++; } } if (fadeOut) { logger.warn("fade out detected -> patched palette\n"); } return palette; } catch (FileBufferException ex) { throw new CoreException(ex.getMessage()); } }
@Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) { state = findState(qName); String at; if (state != XmlState.BDN && !valid) { logger.error("BDN tag missing"); } txt = null; switch (state) { case UNKNOWN: logger.error("Unknown tag " + qName + "\n"); break; case BDN: if (valid) { logger.error("BDN must be used only once"); } else { valid = true; } break; case NAME: at = atts.getValue("Title"); if (at != null) { title = at; logger.trace("Title: " + title + "\n"); } break; case LANGUAGE: at = atts.getValue("Code"); if (at != null) { language = at; logger.trace("Language: " + language + "\n"); } break; case FORMAT: at = atts.getValue("FrameRate"); if (at != null) { fps = SubtitleUtils.getFps(at); fpsXml = XmlFps(fps); logger.trace("fps: " + ToolBox.formatDouble(fps) + "\n"); } at = atts.getValue("VideoFormat"); if (at != null) { String res = at; for (Resolution r : Resolution.values()) { if (res.length() == 4 && res.charAt(0) != '7') { // hack to rename 480p/576p to 480i/576i res = res.replace('p', 'i'); } if (r.getResolutionNameForXml().equalsIgnoreCase(res)) { resolution = r; logger.trace("Language: " + r.getResolutionNameForXml() + "\n"); break; } } } break; case EVENTS: at = atts.getValue("NumberofEvents"); if (at != null) { int n = ToolBox.getInt(at); if (n > 0) { /* number of subtitles read from the xml */ Core.setProgressMax(n); } } break; case EVENT: pic = new SubPictureXml(); subPictures.add(pic); int num = subPictures.size(); logger.info("#" + num + "\n"); Core.setProgress(num); at = atts.getValue("InTC"); if (at != null) { pic.setStartTime(timeStrXmlToPTS(at, fpsXml)); if (pic.getStartTime() == -1) { pic.setStartTime(0); logger.warn("Invalid start time " + at + "\n"); } } at = atts.getValue("OutTC"); if (at != null) { pic.setEndTime(timeStrXmlToPTS(at, fpsXml)); if (pic.getEndTime() == -1) { pic.setEndTime(0); logger.warn("Invalid end time " + at + "\n"); } } if (fps != fpsXml) { pic.setStartTime((pic.getStartTime() * 1001 + 500) / 1000); pic.setEndTime((pic.getEndTime() * 1001 + 500) / 1000); } at = atts.getValue("Forced"); pic.setForced(at != null && at.equalsIgnoreCase("true")); if (pic.isForced()) { numForcedFrames++; } int dim[] = resolution.getDimensions(); pic.setWidth(dim[0]); pic.setHeight(dim[1]); break; case GRAPHIC: pic.setImageWidth(ToolBox.getInt(atts.getValue("Width"))); pic.setImageHeight(ToolBox.getInt(atts.getValue("Height"))); pic.setOfsX(ToolBox.getInt(atts.getValue("X"))); pic.setOfsY(ToolBox.getInt(atts.getValue("Y"))); pic.storeOriginalOffsets(); txt = new StringBuffer(); break; } }