/* * @(#)PicturePanel * * Copyright (c) 2003-2008 by dvb.matt, All Rights Reserved. * * This file is part of ProjectX, a free Java based demux utility. * By the authors, ProjectX is intended for educational purposes only, * as a non-commercial test project. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /** * resizable preview window * idea & introduced 12/2008 by Frank (The Dragon) */ package net.sourceforge.dvb.projectx.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.image.MemoryImageSource; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.text.NumberFormat; import java.util.Arrays; import java.util.Hashtable; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.UIManager; import net.sourceforge.dvb.projectx.common.Common; import net.sourceforge.dvb.projectx.common.Keys; import net.sourceforge.dvb.projectx.common.Resource; import net.sourceforge.dvb.projectx.parser.CommonParsing; import net.sourceforge.dvb.projectx.video.PreviewObject; import net.sourceforge.dvb.projectx.xinput.StreamInfo; public class PicturePanel extends JPanel { private Image StreamTypeImage = Resource.loadImage("_container.gif"); private Image VideoImage = Resource.loadImage("_video.gif"); private Image AudioImage = Resource.loadImage("_audio.gif"); private Image TeletextImage = Resource.loadImage("_teletext.gif"); private Image SubtitleImage = Resource.loadImage("_subtitle.gif"); private Image PlaytimeImage = Resource.loadImage("_playtime.gif"); private Image PalPlusImage = Resource.loadImage("_ppl.gif"); private Image SubpictureImage; private Image image; private Image mixed_image; private Image thumb_image; private Image InfoBackground = Resource.loadImage("ibg.gif"); private Image SlideBackground = Resource.loadImage("sbg.gif"); private MemoryImageSource source; private MemoryImageSource mixed_source; private MemoryImageSource thumb_source; private boolean showFileInfo = false; private boolean isSubpictureAvailable = false; private boolean isThumbnailAvailable = false; private boolean isOSDInfoAvailable = false; private boolean isOSDErrorInfo = false; private boolean PLAY = true; private boolean isMixedImageAvailable = false; private boolean isMatrixImageAvailable = false; private boolean isFilterActive = false; private boolean fullScaled = false; private boolean manualzoom = false; private boolean definezoom = false; private int[] zoomrect = new int[6]; private int[] mixed_image_array; private int[] thumb_image_array; private String mixed_image_info = ""; private int matrix_index = -1; private int matrix_new_width = 128; // 100 private int matrix_new_height = 72; // 56 private Hashtable matrix_positions = new Hashtable(); // 4x4 matrix private int[][] matrix_table = { { 0, 0 }, { 128, 1 }, { 256, 1 }, { 384, 1 }, { 0, 72 }, { 128, 72 }, { 256, 72 }, { 384, 72 }, { 0, 144 }, { 128, 144 }, { 256, 144 }, { 384, 144 }, { 0, 216 }, { 128, 216 }, { 256, 216 }, { 384, 216 }, }; // 5x5 matrix // private int[][] matrix_table_5x5 = { { 2, 1 }, { 104, 1 }, { 206, 1 }, { // 308, 1 }, { 410, 1 }, { 2, 58 }, // { 104, 58 }, { 206, 58 }, { 308, 58 }, { 410, 58 }, { 2, 117 }, { 104, // 117 }, { 206, 117 }, { 308, 117 }, // { 410, 117 }, { 2, 174 }, { 104, 174 }, { 206, 174 }, { 308, 174 }, { 410 // , 174 }, { 2, 231 }, { 104, 231 }, // { 206, 231 }, { 308, 231 }, { 410, 231 } }; private StreamInfo streamInfo = null; private Font font_1; private Font font_2; private Font font_3; private NumberFormat percentage; private int ErrorFlag = 0; private int bmpCount = 0; private int collection_number = -1; private int[] imageSizeMin = { 512, 288 }; private final String tooltip1 = Resource.getString("mpvdecoder.tip1"); private long cutfiles_length = 0; private long[] cutfiles_points = null; private long chapter_length = 0; private long[] chapter_points = null; private Object[] OSDInfo; private JPopupMenu popup; private JPanel sliderPanel; private Clock clock; private Dimension previewImageSize; private static final Color OUTLINE_COLOR_1 = Color.lightGray; private static final Color OUTLINE_COLOR_2 = Color.white; private static final Color OUTLINE_COLOR_3 = new Color(151, 151, 151); private Dimension infoParts = new Dimension(184, 44); /** * class to control short OSD fadings */ private class Clock implements Runnable { private Thread clockThread = null; private int sleepAmount = 3000; public void start() { start(3000); } public void start(int value) { if (clockThread == null) { clockThread = new Thread(this, "Clock_4"); clockThread.setPriority(Thread.MIN_PRIORITY); sleepAmount = value; clockThread.start(); } } public void run() { Thread myThread = Thread.currentThread(); while (clockThread == myThread) { try { Thread.sleep(sleepAmount); // time on screen } catch (InterruptedException e) { } if (update()) { repaint(); } stop(); } } private boolean update() { boolean b = false; if (collection_number >= 0) { collection_number = -1; b = true; } if (showFileInfo) { showFileInfo = false; b = true; } if (isOSDInfoAvailable) { isOSDInfoAvailable = false; b = true; } return b; } public void stop() { clockThread = null; } } /** * */ public PicturePanel() { percentage = NumberFormat.getPercentInstance(); percentage.setMaximumFractionDigits(2); source = new MemoryImageSource(imageSizeMin[0], imageSizeMin[1], Common.getMpvDecoderClass().getPreviewPixel(), 0, imageSizeMin[0]); source.setAnimated(true); image = createImage(source); mixed_image_array = new int[imageSizeMin[0] * imageSizeMin[1]]; mixed_source = new MemoryImageSource(imageSizeMin[0], imageSizeMin[1], mixed_image_array, 0, imageSizeMin[0]); mixed_source.setAnimated(true); mixed_image = createImage(mixed_source); thumb_image_array = new int[160 * 90]; thumb_source = new MemoryImageSource(160, 90, thumb_image_array, 0, 160); thumb_source.setAnimated(true); thumb_image = createImage(thumb_source); font_1 = new Font("Tahoma", Font.PLAIN, 12); font_2 = new Font("Tahoma", Font.BOLD, 12); font_3 = new Font("Tahoma", Font.BOLD, 24); setBackground(Color.black); setVisible(true); setToolTipText(tooltip1); // <- VORSCHLAG 1 Tooltip! // setSize(512, 346); buildPopupMenu(); sliderPanel = buildSliderPanel(); addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() >= 1 && (showFileInfo || isOSDInfoAvailable)) { showFileInfo = false; isOSDInfoAvailable = false; repaint(); } if (isMatrixImageAvailable) { if (e.getClickCount() == 1 && e.getModifiers() == InputEvent.BUTTON1_MASK) { if (matrix_positions.containsKey(String.valueOf(matrix_index))) { long value = ((Long) matrix_positions.get(String.valueOf(matrix_index))).longValue(); CommonGui.getCutPanel().startMatrix(value); } else { CommonGui.getCutPanel().stopMatrix(); } } if (e.getClickCount() >= 2 && e.getModifiers() == InputEvent.BUTTON3_MASK) { if (matrix_positions.containsKey(String.valueOf(matrix_index))) { long value = ((Long) matrix_positions.get(String.valueOf(matrix_index))).longValue(); disableMatrix(); CommonGui.getCutPanel().stopMatrix(); CommonGui.getCutPanel().preview(value); } } } else if (e.getClickCount() >= 1 && e.getModifiers() == InputEvent.BUTTON3_MASK) { popup.show(getParent(), e.getX(), e.getY()); } if (e.getClickCount() >= 2 && e.getModifiers() == InputEvent.BUTTON1_MASK) { CommonGui.getPlayerFrame().repaintPicture(); } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { if (!definezoom) { return; } definezoom = false; manualzoom = false; repaint(); Common.getMpvDecoderClass().setZoomMode(zoomrect); } }); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent e) { if (Common.getMpvDecoderClass().getZoomMode() == 2) { zoomrect[0] = e.getX() < 0 ? 0 : e.getX(); zoomrect[1] = e.getY() < 0 ? 0 : e.getY(); Common.getMpvDecoderClass().setZoomMode(zoomrect); } if (!definezoom) { return; } if (!manualzoom) { manualzoom = true; zoomrect[0] = e.getX(); zoomrect[1] = e.getY(); } else { zoomrect[2] = e.getX() - zoomrect[0]; zoomrect[3] = (int) (9.0 * zoomrect[2] / 16.0); } repaint(); } public void mouseMoved(MouseEvent e) { int tmp_val = 0; if (isMatrixImageAvailable) { tmp_val = e.getX() / matrix_new_width + imageSizeMin[0] / matrix_new_width * (e.getY() / matrix_new_height); if (tmp_val < matrix_table.length) { matrix_index = tmp_val; repaint(); } } if (!definezoom || manualzoom) { return; } zoomrect[4] = e.getX(); zoomrect[5] = e.getY(); repaint(); } }); clock = new Clock(); } /** * */ protected void buildPopupMenu() { final String[] popup_modes = { "normalzoom", "lbzoom", "zoomarea", "save_1", "save_2" }; ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { String actName = e.getActionCommand(); if (actName.equals(popup_modes[3])) { saveBMP(Common.getMpvDecoderClass().getPixels(), Common.getMpvDecoderClass().getWidth(), Common.getMpvDecoderClass().getHeight(), 0, false); } else if (actName.equals(popup_modes[4])) { saveBMP(Common.getMpvDecoderClass().getPixels(), Common.getMpvDecoderClass().getWidth(), Common.getMpvDecoderClass().getHeight(), Common.getMpvDecoderClass().getAspectRatio(), true); } else if (actName.equals(popup_modes[0])) { Common.getMpvDecoderClass().setZoomMode(0); } else if (actName.equals(popup_modes[1])) { Common.getMpvDecoderClass().setZoomMode(1); } else if (actName.equals(popup_modes[2])) { definezoom = true; Arrays.fill(zoomrect, 0); } } }; popup = new JPopupMenu("save"); JMenuItem menuitem_1 = popup.add("Normal Zoom"); menuitem_1.setActionCommand(popup_modes[0]); JMenuItem menuitem_2 = popup.add("LB Zoom"); menuitem_2.setActionCommand(popup_modes[1]); JMenuItem menuitem_3 = popup.add("Zoom Area.."); menuitem_3.setActionCommand(popup_modes[2]); popup.addSeparator(); JMenuItem menuitem_4 = popup.add(Resource.getString("PreviewPanel.saveCurrentPicture")); menuitem_4.setActionCommand(popup_modes[3]); JMenuItem menuitem_5 = popup.add(Resource.getString("PreviewPanel.saveCurrentPictureDAR")); menuitem_5.setActionCommand(popup_modes[4]); popup.pack(); UIManager.addPropertyChangeListener(new UISwitchListener(popup)); menuitem_1.addActionListener(al); menuitem_2.addActionListener(al); menuitem_3.addActionListener(al); menuitem_4.addActionListener(al); menuitem_5.addActionListener(al); } /** * */ protected JPanel buildSliderPanel() { JPanel panel = new JPanel(new BorderLayout()); JSlider scanSlider = new JSlider(); scanSlider.setOrientation(SwingConstants.VERTICAL); scanSlider.setInverted(true); scanSlider.setMaximum(100); scanSlider.setMajorTickSpacing(10); scanSlider.setMinorTickSpacing(1); scanSlider.setPaintTicks(true); scanSlider.setValue(50); scanSlider.setPreferredSize(new Dimension(30, 356)); scanSlider.setMaximumSize(new Dimension(30, 356)); scanSlider.setMinimumSize(new Dimension(30, 356)); panel.add(scanSlider); return panel; } /** * */ public JPanel getSliderPanel() { return sliderPanel; } /** * holds special messages */ public void startClock() { clock.start(); } /** * holds special messages */ public void startClock(int value) { clock.start(value); } /** * updates the preview graphic */ public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); previewImageSize = new Dimension(this.getSize().width - infoParts.width, this.getSize().height - infoParts.height); setPreviewSize(previewImageSize.width, previewImageSize.height); paintInfoBackground(g); paintOutline(g); paintPreviewPicture(g, g2); paintMixedCutPreviewPicture(g, g2); paintMatrixPreviewPicture(g); paintZoomInfo(g); paintSlideBackground(g); paintVideoInfo(g); paintWSSInfo(g); paintErrorInfo(g); paintPlayInfo(g); g.setFont(font_2); paintCutInfo(g); paintPositionInfo(g); paintChapterInfo(g); paintSubpicture(g, g2); paintOSDInfo(g); paintFileInfo(g); paintCollectionNumber(g); paintZoomRect(g); } /** * paint background */ private void paintInfoBackground(Graphics g) { g.setColor(new Color(0, 35, 110)); g.fillRect(0, 0, previewImageSize.width + 200, previewImageSize.height + 100); g.drawImage(InfoBackground, 0, previewImageSize.height + 2, previewImageSize.width, InfoBackground.getHeight(this), this); } /** * paint background */ private void paintSlideBackground(Graphics g) { g.drawImage(SlideBackground, previewImageSize.width + 2, 0, infoParts.width, previewImageSize.height + infoParts.height, this); } /** * paint preview */ private void paintPreviewPicture(Graphics g, Graphics2D g2) { //erste variante, only up-scale again the down-scaled prev.image // dont use, affects text negative: // g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); if (!fullScaled) g2.drawImage(image, 0, 0, previewImageSize.width, previewImageSize.height, this); else g.drawImage(image, 0, 0, this); } /** * paint cut mixed preview */ private void paintMixedCutPreviewPicture(Graphics g, Graphics2D g2) { if (!isMixedImageAvailable) { return; } if (!fullScaled) g2.drawImage(mixed_image, 0, 0, previewImageSize.width, previewImageSize.height, this); else g.drawImage(mixed_image, 0, 0, this); // g.drawImage(mixed_image, 2, 2, this); g.setFont(font_2); g.setColor(Color.green); g.drawString(mixed_image_info, 340, 280); } /** * paint cut matrix preview */ private void paintMatrixPreviewPicture(Graphics g) { if (!isMatrixImageAvailable) { return; } g.drawImage(mixed_image, 0, 0, this); if (matrix_index < 0 || matrix_index >= matrix_table.length) { return; } if (!matrix_positions.containsKey(String.valueOf(matrix_index))) { return; } g.setColor(Color.green); g.drawRect(matrix_table[matrix_index][0], matrix_table[matrix_index][1], matrix_new_width + 1, matrix_new_height + 1); // g.drawRect(matrix_table[matrix_index][0] + 1, matrix_table[matrix_index][1] + 1, matrix_new_width + 1, matrix_new_height + 1); g.setFont(font_2); g.drawString(String.valueOf(matrix_index), matrix_table[matrix_index][0] + 5, matrix_table[matrix_index][1] + 14); g.drawString(matrix_positions.get(String.valueOf(matrix_index)).toString(), matrix_table[matrix_index][0] + 5, matrix_table[matrix_index][1] + 54); g.drawString(matrix_positions.get(String.valueOf(matrix_index) + "TC").toString(), matrix_table[matrix_index][0] + 5, matrix_table[matrix_index][1] + 68); g.drawString(percentage.format(((Long) matrix_positions.get(String.valueOf(matrix_index))).doubleValue() / ((Long) matrix_positions.get("end")).doubleValue()), matrix_table[matrix_index][0] + 50, matrix_table[matrix_index][1] + 14); } /** * paint outline */ private void paintOutline(Graphics g) { int infoBackgroundHeight = infoParts.height; g.setColor(OUTLINE_COLOR_3); g.drawLine(1, 1, previewImageSize.width, 1); g.drawLine(1, 1, 1, previewImageSize.height + infoBackgroundHeight); g.setColor(OUTLINE_COLOR_1); g.drawLine(2, previewImageSize.height, previewImageSize.width, previewImageSize.height); g.drawLine(previewImageSize.width, 2, previewImageSize.width, previewImageSize.height + infoBackgroundHeight); g.setColor(OUTLINE_COLOR_2); g.drawLine(0, 0, previewImageSize.width + 1, 0); g.drawLine(0, 0, 0, previewImageSize.height + infoBackgroundHeight); g.drawLine(0, previewImageSize.height + 1, previewImageSize.width + 1, previewImageSize.height + 1); g.drawLine(previewImageSize.width + 1, 0, previewImageSize.width + 1, previewImageSize.height + infoBackgroundHeight); } /** * paint videoinfo */ private void paintVideoInfo(Graphics g) { g.setFont(font_1); g.setColor(Color.white); String[] mpg_info = Common.getMpvDecoderClass().getMpgInfo(); for (int i = 0, x = previewImageSize.width + 8, y = 18; i < mpg_info.length - 1; i++, y += 14) { if (mpg_info[i] != null) { g.drawString(mpg_info[i], x, y); } } } /** * paint */ private void paintCollectionNumber(Graphics g) { if (collection_number < 0) { return; } g.setFont(font_2); g.setColor(Color.green); g.drawString("Collection", previewImageSize.width - 60, 16); g.setFont(font_3); g.setColor(Color.green); g.drawString(String.valueOf(collection_number), previewImageSize.width - 50, 38); } /** * paint */ private void paintZoomInfo(Graphics g) { g.setFont(font_2); g.setColor(Color.green); g.drawString(Common.getMpvDecoderClass().getZoomInfo(), 20, previewImageSize.height - 5); } /** * paint */ private void paintZoomRect(Graphics g) { if (!definezoom) { return; } if (!manualzoom) { g.setColor(new Color(255, 255, 255, 255)); g.drawLine(zoomrect[4] - 10, zoomrect[5], zoomrect[4] + 10, zoomrect[5]); g.drawLine(zoomrect[4], zoomrect[5] - 10, zoomrect[4], zoomrect[5] + 10); } else { g.setColor(new Color(100, 100, 255, 120)); g.fillRect(zoomrect[0], zoomrect[1], zoomrect[2], zoomrect[3]); g.setColor(new Color(255, 255, 255, 255)); g.drawRect(zoomrect[0], zoomrect[1], zoomrect[2], zoomrect[3]); } } /** * paint wss info */ private void paintWSSInfo(Graphics g) { String str; if ((str = Common.getMpvDecoderClass().getWSSInfo()) == null) { setToolTipText(tooltip1); return; } g.setFont(font_2); g.setColor(Color.green); g.drawString("WSS present", 10, 16); g.drawString(Common.getMpvDecoderClass().getWSSFormatInfo(), 10, 30); if (Common.getMpvDecoderClass().getPalPlusInfo()) { g.drawImage(PalPlusImage, 8, 34, this); } setToolTipText("<html>" + tooltip1 + "<p><p>" + str + "</html>"); } /** * paint play info */ private void paintPlayInfo(Graphics g) { int x[] = { previewImageSize.width + 8, previewImageSize.width + 8, previewImageSize.width + 28 }; int y[] = { previewImageSize.height + 18, previewImageSize.height + 38, previewImageSize.height + 28 }; if (isFilterActive && PLAY) { g.setColor(Color.yellow); g.drawString("Export Filter Mismatch !", previewImageSize.width + 32, previewImageSize.height + 32); g.fillRect(previewImageSize.width + 8, previewImageSize.height + 18, 8, 20); g.fillRect(previewImageSize.width + 20, previewImageSize.height + 18, 8, 20); // yellow border around pic g.drawRect(0, 0, previewImageSize.width - 1, previewImageSize.height - 1); g.drawRect(1, 1, previewImageSize.width - 3, previewImageSize.height - 3); } else if (PLAY) { g.setColor(Color.green); g.fillPolygon(x, y, 3); g.drawString("Inside Export Range", previewImageSize.width + 32, previewImageSize.height + 32); } else { g.setColor(Color.red); g.fillRect(previewImageSize.width + 8, previewImageSize.height + 18, 20, 20); g.drawString("Outside Export Range", previewImageSize.width + 32, previewImageSize.height + 32); // red border around pic g.drawRect(0, 0, previewImageSize.width - 1, previewImageSize.height - 1); g.drawRect(1, 1, previewImageSize.width - 3, previewImageSize.height - 3); } } /** * paint error info */ private void paintErrorInfo(Graphics g) { ErrorFlag = Common.getMpvDecoderClass().getErrors(); if ((ErrorFlag & 1) != 0) { g.setColor(Color.white); g.fill3DRect(150, 120, 200, 20, true); g.setColor(Color.red); g.drawString("picture decoding not possible", 160, 133); } // if ((ErrorFlag & 4) != 0) { if ((ErrorFlag & 0xC) == 4) { g.setColor(Color.white); g.fill3DRect(150, 135, 200, 20, true); g.setColor(Color.red); g.drawString("not enough data in buffer", 160, 148); } if ((ErrorFlag & 2) != 0) { g.setColor(Color.white); g.fill3DRect(150, 150, 200, 20, true); g.setColor(Color.red); g.drawString("cannot find sequence header", 160, 163); } if ((ErrorFlag & 0x13) > 0x10) // 5 + 2 + 1 { g.setColor(Color.white); g.fill3DRect(150, 150, 200, 20, true); g.setColor(Color.red); g.drawString("no Sequ. but GOP header found", 160, 163); } if ((ErrorFlag & 8) != 0) { g.setColor(Color.white); // g.fill3DRect(150, 165, 200, 20, true); g.fill3DRect(150, 135, 200, 20, true); g.setColor(Color.red); // g.drawString("data seems to be MPEG-4/H.264", 160, 178); g.drawString("no preview for MPEG-4/H.264", 160, 148); } if ((ErrorFlag & 0x20) != 0) { g.setColor(Color.white); g.fill3DRect(150, 165, 200, 20, true); g.setColor(Color.red); g.drawString("java instance out of memory", 160, 178); } } /** * paint cut info */ private void paintCutInfo(Graphics g) { if (cutfiles_length <= 0) { return; } // int x1 = 10, y1 = 327, w1 = 492, h1 = 6; int x1 = 10, y1 = previewImageSize.height + 12, w1 = previewImageSize.width - 22, h1 = 6; g.setColor(new Color(0, 200, 0)); g.fillRect(x1, y1, w1, h1); g.setColor(Color.white); g.drawRect(x1 - 2, y1 - 2, w1 + 3, h1 + 3); /** * paint cut markers */ if (cutfiles_points != null && cutfiles_points.length > 0) { int p0 = 0, p1 = 0; for (int i = 0; i < cutfiles_points.length; i++) { if (cutfiles_points[i] > cutfiles_length) { break; } p0 = i == 0 ? 0 : (int) (cutfiles_points[i - 1] * w1 / cutfiles_length); p1 = (int) (cutfiles_points[i] * w1 / cutfiles_length); if (i % 2 == 0) { g.setColor(new Color(150, 0, 0)); g.fillRect(x1 + p0, y1, p1 - p0, h1); } g.setColor(new Color(200, 100, 200)); g.fillRect(x1 + p1 - 1, y1 - 4, 2, h1 + 8); // int[] x = { x1 + p1 - 1, x1 + p1 - 5, x1 + p1 + 5 }; int[] y = { y1 - 3, y1 - 3 - 5, y1 - 3 - 5 }; int[] x_1 = { x1 + p1 - 1, x1 + p1 - 1, x1 + p1 + 5 }; int[] x_2 = { x1 + p1 + 1, x1 + p1 - 5, x1 + p1 + 1 }; if (i % 2 == 0) { g.fillPolygon(x_1, y, 3); } else { g.fillPolygon(x_2, y, 3); } } if ((cutfiles_points.length & 1) == 0) { p0 = (int) (cutfiles_points[cutfiles_points.length - 1] * w1 / cutfiles_length); g.setColor(new Color(150, 0, 0)); g.fillRect(x1 + p0, y1, w1 - p0, h1); } } } /** * paint position info */ private void paintPositionInfo(Graphics g) { // int x1 = 10, y1 = 346, w1 = 492, h1 = 8; int x1 = 10, y1 = previewImageSize.height + 30, w1 = previewImageSize.width - 22, h1 = 8; List positions = Common.getMpvDecoderClass().getPositions(); /** * paint current position */ g.setColor(Color.white); g.fillRect(x1, y1, 2, h1); // start g.fillRect(x1 + w1, y1, 2, h1); // end g.fillRect(x1, y1 + 3, w1, 2); // axis long pos; long max = 1; int mark; if (!positions.isEmpty()) { max = ((Long) positions.get(positions.size() - 1)).longValue(); for (int i = 1, j = positions.size() - 1; i < j; i++) { pos = ((Long) positions.get(i)).longValue(); mark = (int) (pos * w1 / max); g.fillRect(x1 + mark, y1, 2, h1); // mark } pos = ((Long) positions.get(0)).longValue(); mark = (int) (pos * w1 / max); g.setColor(Color.red); g.fillRect(x1 + mark, y1, 2, h1); // mark } g.setFont(font_2); g.setColor(Color.green); String str = Common.getMpvDecoderClass().getPidAndFileInfo(); int sep1 = str.indexOf("-"); int sep2 = sep1; if (sep1 < 0) { sep1 = sep2 = str.length(); } else { sep1 -= 1; sep2 += 2; } g.drawString(str.substring(0, sep1), previewImageSize.width + 8, previewImageSize.height + 12); // pid g.drawString(str.substring(sep2), previewImageSize.width + 8, previewImageSize.height - 2); // file // matrix if (!isMatrixImageAvailable) { return; } for (int i = 0; i < matrix_table.length; i++) { if (matrix_positions.containsKey(String.valueOf(i))) { pos = ((Long) matrix_positions.get(String.valueOf(i))).longValue(); mark = (int) (pos * w1 / max); g.fillRect(x1 + mark, y1 + 4, 2, h1 - 4); // mark matrix // position } } if (matrix_positions.containsKey(String.valueOf(matrix_index))) { pos = ((Long) matrix_positions.get(String.valueOf(matrix_index))).longValue(); mark = (int) (pos * w1 / max); g.setColor(Color.magenta); g.fillRect(x1 + mark, y1, 2, h1); // mark matrix position } } /** * paint chapter info */ private void paintChapterInfo(Graphics g) { if (chapter_length <= 0) { return; } // int x1 = 10, y1 = 327, w1 = 492, h1 = 6; int x1 = 10, y1 = previewImageSize.height + 22, w1 = previewImageSize.width - 22, h1 = 6; /** * paint chapter markers */ if (chapter_points != null && chapter_points.length > 0) { int p0 = 0; int p1 = 0; for (int i = 0; i < chapter_points.length; i++) { if (chapter_points[i] > chapter_length) { break; } p0 = i == 0 ? 0 : (int) (chapter_points[i - 1] * w1 / chapter_length); p1 = (int) (chapter_points[i] * w1 / chapter_length); g.setColor(new Color(195, 205, 255)); g.fillRect(x1 + p1 - 1, y1 - 4, 2, h1 + 8); int[] x = { x1 + p1 - 1, x1 + p1 - 5, x1 + p1 + 5 }; int[] y = { y1 + h1 + 3, y1 + h1 + 3 + 5, y1 + h1 + 3 + 5 }; g.fillPolygon(x, y, 3); } } } /** * paint */ private void paintOSDBg(Graphics g, int x3, int y3, int w3, int h3) { Color blue_1 = new Color(150, 150, 255, 210); Color blue_2 = new Color(50, 20, 225, 210); Color red_1 = new Color(255, 150, 150, 210); Color red_2 = new Color(225, 20, 20, 210); g.setColor(isOSDErrorInfo ? red_1 : blue_1); g.fillRect(x3, y3 + 20, w3, previewImageSize.height - 70); g.setColor(isOSDErrorInfo ? red_2 : blue_2); g.fillRect(x3, y3, w3, 20); g.fillRect(x3, y3 + h3, w3, 34); g.setColor(Color.white); g.drawLine(x3, y3 + 20, x3 + w3 - 1, y3 + 20); g.drawLine(x3, y3 + previewImageSize.height - 50, x3 + w3 - 1, y3 + previewImageSize.height - 50); } /** * paint prescan file info */ private void paintOSDInfo(Graphics g) { if (!isOSDInfoAvailable || OSDInfo == null || OSDInfo.length == 0) { return; } int x3 = 8; // 15; int y3 = 8; int w3 = previewImageSize.width - 18; // 482; int h3 = previewImageSize.height - 50; int yOffset = 0; paintOSDBg(g, x3, y3, w3, h3); g.setColor(Color.white); g.drawString(OSDInfo[0].toString(), x3 + 10, y3 + 14); g.drawString(OSDInfo[1].toString(), x3 + 10, y3 + h3 + 16); yOffset = y3 + 24; for (int i = 2; i < OSDInfo.length; i++) { yOffset = paintSubInfo(g, OSDInfo[i].toString(), null, x3, yOffset); } } /** * paint prescan file info */ private void paintFileInfo(Graphics g) { if (!showFileInfo) { return; } int x3 = 8; // 15; int y3 = 8; int w3 = previewImageSize.width - 18; // 482; int h3 = previewImageSize.height - 50; int yOffset = 0; Object[] obj; paintOSDBg(g, x3, y3, w3, h3); g.setColor(Color.white); g.drawString(streamInfo.getFileSourceAndName(), x3 + 6, y3 + 14); g.drawString(streamInfo.getFileDate(), x3 + 6, y3 + h3 + 16); g.drawString(streamInfo.getFileSize(), x3 + 6, y3 + h3 + 30); //thumbnail if (isThumbnailAvailable) { g.setColor(Color.gray); g.drawRect(x3 + w3 - 160 - 5, y3 + h3 - 90 - 5, 160 + 1, 90 + 1); g.drawImage(thumb_image, x3 + w3 - 160 - 4, y3 + h3 - 90 - 4, this); } g.setColor(Color.white); yOffset = y3 + 24; yOffset = paintSubInfo(g, streamInfo.getFileType(), StreamTypeImage, x3, yOffset); obj = streamInfo.getVideoStreams(); yOffset = paintSubInfo(g, obj, VideoImage, x3, yOffset); obj = streamInfo.getAudioStreams(); yOffset = paintSubInfo(g, obj, AudioImage, x3, yOffset); obj = streamInfo.getTeletextStreams(); yOffset = paintSubInfo(g, obj, TeletextImage, x3, yOffset); obj = streamInfo.getSubpictureStreams(); yOffset = paintSubInfo(g, obj, SubtitleImage, x3, yOffset); yOffset = paintSubInfo(g, streamInfo.getPlaytime(), PlaytimeImage, x3, yOffset); } /** * line height = 16 */ private int paintSubInfo(Graphics g, String str, Image icon, int x, int y) { if (str != null && str.length() > 0) { if (y > previewImageSize.height - 60) { g.fillPolygon(new int[] { x + 3, x + 17, x + 9 }, new int[] { y, y, y + 7 }, 3); g.drawString("...", x + 25, y + 6); return y; } int i = str.indexOf("\t"); int j = icon != null ? 25 : 10; if (icon != null) { g.drawImage(icon, x + 2, y, this); } if (i >= 0) { g.drawString(str.substring(i + 1), x + j + 120, y + 12); g.drawString(str.substring(0, i), x + j, y + 12); } else { g.drawString(str, x + j, y + 12); } y += 16; } return y; } /** * */ private int paintSubInfo(Graphics g, Object[] obj, Image icon, int x, int y) { if (obj != null && obj.length > 0) { for (int i = 0; i < obj.length; i++) { y = paintSubInfo(g, "" + (i + 1) + ". " + obj[i].toString(), icon, x, y); } } return y; } /** * paint prescan subpic info */ private void paintSubpicture(Graphics g, Graphics2D g2) { if (!isSubpictureAvailable) { return; } // if (!fullScaled) g2.drawImage(SubpictureImage, 0, 0, previewImageSize.width, previewImageSize.height, this); // else // g.drawImage(SubpictureImage, 66, 0, this); } /** * */ private void loadSubpicture() { SubpictureImage = !isSubpictureAvailable ? null : Common.getSubpictureClass().getScaledImage(previewImageSize.width, previewImageSize.height); } /** * */ public void setPreviewSize(int w, int h) { if (!Common.getSettings().getBooleanProperty(Keys.KEY_Preview_fullScaled)) { w = 512; h = 288; } if (w == imageSizeMin[0] && h == imageSizeMin[1]) return; imageSizeMin[0] = w; imageSizeMin[1] = h; Common.getMpvDecoderClass().setPreviewSize(w, h); source = new MemoryImageSource(imageSizeMin[0], imageSizeMin[1], Common.getMpvDecoderClass().getPreviewPixel(), 0, imageSizeMin[0]); source.setAnimated(true); image = createImage(source); source.newPixels(); } /** * */ public void setStreamInfo(StreamInfo _streamInfo) { streamInfo = _streamInfo.getNewInstance(); // betta to get a copy showFileInfo = streamInfo != null; isThumbnailAvailable = showFileInfo && streamInfo.getThumbnail() != null && streamInfo.getThumbnail().length > 0; if (isThumbnailAvailable) { int[] thumb = streamInfo.getThumbnail(); System.arraycopy(thumb, 0, thumb_image_array, 0, thumb.length); thumb_source.newPixels(); } if (showFileInfo && !Common.getSettings().getBooleanProperty(Keys.KEY_holdStreamInfoOnOSD)) { startClock(10000); } isSubpictureAvailable = showFileInfo && streamInfo.getStreamType() == CommonParsing.ES_SUP_TYPE; loadSubpicture(); isOSDInfoAvailable = false; isOSDErrorInfo = false; repaint(); } /** * */ public void setOSD(Object[] obj) { isOSDErrorInfo = false; setOSDMessage(obj); } /** * */ public void setOSDMessage(String str, boolean b) { isOSDErrorInfo = b; setOSDMessage(new Object[] { b ? "Fehler" : "Info", "", "", str }); } /** * */ public void setOSDMessage(Object[] obj) { setOSDMessage(obj, false); } /** * */ public void setOSDMessage(Object[] obj, boolean hold) { OSDInfo = obj; isOSDInfoAvailable = true; showFileInfo = false; if (!hold) { startClock(10000); } repaint(); } /** * */ public void showCollectionNumber(int value) { collection_number = value; startClock(); repaint(); } /** * */ public Image getPreviewImage() { return image; } /** * */ public void updatePreviewPixel() { source.newPixels(); } /** * modify transparency */ public void setMixedPreviewPixel(int[] picture, int transparency) { isMixedImageAvailable = picture != null && transparency > 0; mixed_image_info = isMixedImageAvailable ? "CutImage Mix Mode: " + transparency * 100 / 255 + "%" : ""; if (!isMixedImageAvailable) { clearMixedImage(); } else { for (int i = 0, j = mixed_image_array.length; i < j; i++) { mixed_image_array[i] = 0xFFFFFF & picture[i] | transparency << 24; } } isMatrixImageAvailable = false; mixed_source.newPixels(); } /** * */ public void clearMixedImage() { Arrays.fill(mixed_image_array, 0); } /** * modify matrix image */ public void setMatrixPreviewPixel(int index) { isMatrixImageAvailable = true; Common.getMpvDecoderClass().getScaledCutMatrixImage(mixed_image_array, matrix_new_width, matrix_new_height, matrix_table[index][0], matrix_table[index][1]); mixed_source.newPixels(); } /** * get matrix */ public int[][] getMatrixTable() { return matrix_table; } /** * set matrix pos */ public void setMatrixIndexPosition(int index, long value, String str) { matrix_positions.put(String.valueOf(index), new Long(value)); // pos matrix_positions.put(String.valueOf(index) + "TC", str); // TC } /** * set matrix pos */ public void setMatrixEndPosition(long value) { matrix_positions.put("end", new Long(value)); } /** * set matrix pos */ public void resetMatrixPositions(long value) { matrix_positions.clear(); setMatrixEndPosition(value); clearMixedImage(); } /** * set matrix */ public void disableMatrix() { isMatrixImageAvailable = false; } /** * get filter mismatch */ public void setFilterStatus(boolean b) { isFilterActive = b; } /** * updates cut symbols in preview info field * * @param1 - do_export bool * @param2 - cutpoints list array * @param3 - previewlist of files */ public void showCutIcon(boolean play, Object[] obj, Object list) { PLAY = play; List previewList = (List) list; if (!previewList.isEmpty()) { cutfiles_length = ((PreviewObject) previewList.get(previewList.size() - 1)).getEnd(); if (obj != null) { cutfiles_points = new long[obj.length]; for (int i = 0; i < cutfiles_points.length; i++) { cutfiles_points[i] = CommonParsing.parseCutValue(obj[i].toString(), false); } } else { cutfiles_points = null; } } else { cutfiles_length = 0; cutfiles_points = null; } repaint(); } /** * updates chapter symbols in preview info field * * @param1 - do_export bool * @param2 - chapterpoints list array * @param3 - previewlist of files */ public void showChapterIcon(Object[] obj, Object list) { List previewList = (List) list; if (!previewList.isEmpty()) { chapter_length = ((PreviewObject) previewList.get(previewList.size() - 1)).getEnd(); if (obj != null) { chapter_points = new long[obj.length]; for (int i = 0; i < chapter_points.length; i++) { chapter_points[i] = CommonParsing.parseCutValue(obj[i].toString(), false); } } else { chapter_points = null; } } else { chapter_length = 0; chapter_points = null; } repaint(); } /** * performs YUV to RGB conversion */ private int YUVtoRGB(int YUV) { int T = 0xFF; int Y = 0xFF & YUV >>> 16; int Cb = 0xFF & YUV >>> 8; int Cr = 0xFF & YUV; if (Y == 0) { return 0; } int R = (int) (Y + 1.402f * (Cr - 128)); int G = (int) (Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128)); int B = (int) (Y + 1.722 * (Cb - 128)); R = R < 0 ? 0 : R > 0xFF ? 0xFF : R; G = G < 0 ? 0 : G > 0xFF ? 0xFF : G; B = B < 0 ? 0 : B > 0xFF ? 0xFF : B; return T << 24 | R << 16 | G << 8 | B; } /** * BMP 24-bit header */ private byte bmpHead[] = { 0x42, 0x4D, // 'B','M' 0, 0, 0, 0, // real filesize 32bit, little endian (real size*3 + // header(0x36)) 0, 0, 0, 0, 0x36, 0, 0, 0, // bitmap info size 0x28, 0, 0, 0, 0, 0, 0, 0, // hsize 0, 0, 0, 0, // vsize 1, 0, // nplane 0x18, 0, // bitcount 24b 0, 0, 0, 0, // ncompr 0, 0, 0, 0, // image bytesize (byte) 0x88, 0xB, 0, 0, // nxpm (byte) 0x88, 0xB, 0, 0, // nypm 0, 0, 0, 0, // nclrused, 0, 0, 0, 0 // nclrimp }; /** * performs change of byte order * * @param1 - source byte array * @param2 - array position * @param3 - source int value */ private void littleEndian(byte[] array, int aPos, int value) { for (int i = 0; i < 4; i++) { array[aPos + i] = (byte) (value >> (i << 3) & 0xFF); } } /** * */ private double[] aspectratio_table = { 1.3333, 1.3333, 1.3333, 1.7778, 2.2100, 1.3333, 1.3333, 1.3333, 1.3333, 1.3333, 1.3333, 1.3333, 1.3333, 1.3333, 1.3333, 1.3333 }; /** * saves cached preview source picture as BMP * * @param1 - automatic saving (demux mode - <extern> panel option) * @param2 - if GUI is not visible, don't update */ private void saveBMP(int[] pixels, int horizontal_size, int vertical_size, int aspectratio_index, boolean useAspectRatio) { int[] sourcepixel = null; int source_mb_width = (0xF & horizontal_size) != 0 ? (horizontal_size & ~0xF) + 16 : horizontal_size; if (useAspectRatio) { sourcepixel = getScaledPixel(pixels, horizontal_size, vertical_size, aspectratio_table[aspectratio_index]); if (sourcepixel == null) { sourcepixel = pixels; } else { horizontal_size = (int) Math.round(aspectratio_table[aspectratio_index] * vertical_size); source_mb_width = horizontal_size; } } else { sourcepixel = pixels; } int size = horizontal_size * vertical_size; if (size <= 0) { return; } X_JFileChooser chooser = CommonGui.getMainFileChooser(); if (bmpCount == 0) { // suggest the current collection directory } String newfile = chooser.getCurrentDirectory() + System.getProperty("file.separator") + "X_picture(" + bmpCount + ").bmp"; chooser.setSelectedFile(new File(newfile)); chooser.rescanCurrentDirectory(); chooser.setDialogTitle("save picture"); int retval = chooser.showSaveDialog(this); if (retval == JFileChooser.APPROVE_OPTION) { File theFile = chooser.getSelectedFile(); if (theFile != null && !theFile.isDirectory()) { newfile = theFile.getAbsolutePath(); } } else { return; } byte[] bmp24 = new byte[3]; // int source_mb_width = (0xF & horizontal_size) != 0 ? (horizontal_size // & ~0xF) + 16 : horizontal_size; int padding = (horizontal_size & 3) != 0 ? horizontal_size & 3 : 0; size = horizontal_size * vertical_size * 3 + (padding > 0 ? padding * vertical_size : 0); littleEndian(bmpHead, 2, (54 + size)); littleEndian(bmpHead, 18, horizontal_size); littleEndian(bmpHead, 22, vertical_size); littleEndian(bmpHead, 34, size); try { BufferedOutputStream BMPfile = new BufferedOutputStream(new FileOutputStream(newfile), 2048000); BMPfile.write(bmpHead); byte[] padding_bytes = new byte[padding]; for (int a = vertical_size - 1, tmp1; a >= 0; a--) { tmp1 = a * source_mb_width; for (int b = 0, pixel = 0; b < horizontal_size; b++) { pixel = YUVtoRGB(sourcepixel[b + tmp1]); for (int c = 0; c < 3; c++) { bmp24[c] = (byte) (pixel >> (c << 3) & 0xFF); } BMPfile.write(bmp24); } if (padding > 0) { BMPfile.write(padding_bytes); } } BMPfile.flush(); BMPfile.close(); bmpCount++; } catch (Exception e) { Common.setExceptionMessage(e); } } /** * create new cutimage pixel data jdk122 seems to have a problem when it * does multiplication !! */ private int[] getScaledPixel(int[] pixels, int horizontal_size, int vertical_size, double aspectratio) { int source_height = vertical_size; int source_width = horizontal_size; int source_mb_width = (0xF & horizontal_size) != 0 ? (horizontal_size & ~0xF) + 16 : horizontal_size; int new_height = vertical_size; int new_width = (int) Math.round(vertical_size * aspectratio); int new_size = new_width * new_height; // oversized or zero ? if (new_size > 0x1000000 || new_size <= 0) { return null; } float Y = 0; float X = 0; double decimate_height = (double) source_height / new_height; double decimate_width = (double) source_width / new_width; int[] new_image = new int[new_size]; for (int y = 0; Y < source_height && y < new_height; Y += decimate_height, y++, X = 0) { for (int x = 0; X < source_width && x < new_width; X += decimate_width, x++) { new_image[x + y * new_width] = pixels[(int) X + (int) Y * source_mb_width]; } } return new_image; } }