FileDocCategorySizeDatePackage
IsoViewerPanel.javaAPI Docmp4parser 1.0-RC-1713607Wed Dec 19 20:10:21 GMT 2012com.coremedia.iso.gui

IsoViewerPanel.java

/*  
 * Copyright 2008 CoreMedia AG, Hamburg
 *
 * Licensed under the Apache License, Version 2.0 (the License); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an AS IS BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */

package com.coremedia.iso.gui;

import com.coremedia.iso.IsoFile;
import com.coremedia.iso.boxes.Box;
import com.coremedia.iso.boxes.SampleDescriptionBox;
import com.coremedia.iso.boxes.TrackBox;
import com.coremedia.iso.boxes.fragment.TrackFragmentBox;
import com.coremedia.iso.boxes.h264.AvcConfigurationBox;
import com.coremedia.iso.boxes.mdat.SampleList;
import com.coremedia.iso.gui.hex.JHexEditor;
import com.googlecode.mp4parser.boxes.basemediaformat.AvcNalUnitStorageBox;
import com.googlecode.mp4parser.util.ByteBufferByteChannel;
import com.googlecode.mp4parser.util.Path;
import org.jdesktop.application.Action;
import org.jdesktop.application.Resource;
import org.jdesktop.application.session.PropertySupport;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTree;
import javax.swing.ListSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Frame;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import static com.googlecode.mp4parser.util.CastUtils.l2i;

/**
 * The main UI class for the ISO viewer. Contains all other UI components.
 */
public class IsoViewerPanel extends JPanel implements PropertySupport {


    private JTree tree;
    private JList trackList;
    private JPanel detailPanel;
    private JSplitPane rawDataSplitPane;

    @Resource
    private String trackViewDetailPaneHeader = "T %s";
    @Resource
    private String tabbedPaneHeaderTrack = "T&S";
    @Resource
    private String tabbedPaneHeaderBox = "BS";

    private Object details;

    private Frame mainFrame;
    private File file;


    public IsoViewerPanel(Frame mainFrame) {
        this.mainFrame = mainFrame;
        this.setName("IsoViewerPanel");

    }


    public void createLayout() {
        IsoFile dummy = new IsoFile();
        tree = new BoxJTree();
        tree.setModel(new IsoFileTreeModel(dummy));

        tree.addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(TreeSelectionEvent e) {
                Box node = (Box) e.getPath().getLastPathComponent();
                showDetails(node);
            }
        });


        detailPanel = new JPanel();
        detailPanel.setLayout(new BorderLayout());
        detailPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));


        rawDataSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        rawDataSplitPane.setName("rawDataSplitPane");
        rawDataSplitPane.setBorder(null);
        rawDataSplitPane.setOneTouchExpandable(true);
        JScrollPane scrollPane = new JScrollPane(detailPanel);
        scrollPane.getVerticalScrollBar().setUnitIncrement(16);
        rawDataSplitPane.setTopComponent(scrollPane);
        rawDataSplitPane.setBottomComponent(new JHexEditor(ByteBuffer.allocate(0)));
        rawDataSplitPane.setResizeWeight(0.8);

        JSplitPane splitPane = new JSplitPane();
        splitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
        splitPane.setOneTouchExpandable(true);
        JTabbedPane jTabbedPane = new JTabbedPane();
        jTabbedPane.setName("tracksOrBoxes");
        JScrollPane jScrollPane = new JScrollPane(tree);
        jScrollPane.setName("boxTreeScrollPane");
        jTabbedPane.add(tabbedPaneHeaderBox, jScrollPane);
        jTabbedPane.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                int index = ((JTabbedPane) e.getSource()).getSelectedIndex();
                if (index == 0) {
                    if (tree.getSelectionPath() != null) {
                        Object selected = tree.getSelectionPath().getLastPathComponent();
                        if (selected != null) {
                            showDetails(selected);
                        }
                    }
                } else if (index == 1) {
                    showSamples(trackList.getSelectedValue());
                }
            }
        });

        trackList = new JList();
        trackList.setCellRenderer(new TrackListRenderer());
        trackList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        trackList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                final Object selectedValue = ((JList) e.getSource()).getSelectedValue();
                showSamples(selectedValue);
            }
        });

        jTabbedPane.add(tabbedPaneHeaderTrack, trackList);
        splitPane.setLeftComponent(jTabbedPane);
        splitPane.setRightComponent(rawDataSplitPane);
        splitPane.setResizeWeight(0.6);
        splitPane.setName("treeLeftdataRight");

        this.setLayout(new BorderLayout());
        this.add(splitPane, BorderLayout.CENTER);


    }

    private void showSamples(Object selectedValue) {
        if (selectedValue != null && selectedValue instanceof TrackBox) {
            final TrackBox trackBox = (TrackBox) selectedValue;
            SampleDescriptionBox sampleDescriptionBox = trackBox.getMediaBox().getMediaInformationBox().getSampleTableBox().getSampleDescriptionBox();
            showSamples(new SampleListModel(new SampleList(trackBox),
                    trackBox.getTrackHeaderBox().getTrackId(), sampleDescriptionBox.getSampleEntry(), null));
        } else if (selectedValue != null && selectedValue instanceof TrackFragmentBox) {
            final TrackFragmentBox trackFragmentBox = (TrackFragmentBox) selectedValue;
            final List<AvcNalUnitStorageBox> avcNalUnitStorageBoxes = trackFragmentBox.getBoxes(AvcNalUnitStorageBox.class);
            AvcConfigurationBox.AVCDecoderConfigurationRecord avcDecoderConfigurationRecord
                    = avcNalUnitStorageBoxes != null && avcNalUnitStorageBoxes.size() > 0 ?
                    avcNalUnitStorageBoxes.get(0).getAvcDecoderConfigurationRecord() : null;
            showSamples(new SampleListModel(new SampleList(trackFragmentBox),
                    trackFragmentBox.getTrackFragmentHeaderBox().getTrackId(), null, avcDecoderConfigurationRecord));
        }
    }

    private void showSamples(SampleListModel sampleListModel) {
        detailPanel.removeAll();
        JComponent detailPane = new JPanel(new BorderLayout());

        JList jlist = new JList();
        jlist.setCellRenderer(new SampleListRenderer());

        //SampleDescriptionBox sampleDescriptionBox = tb.getMediaBox().getMediaInformationBox().getSampleTableBox().getSampleDescriptionBox();
        //jlist.setModel(new SampleListModel(new SampleList(tb), tb.getTrackHeaderBox().getTrackId(), sampleDescriptionBox.getSampleEntry()));
        jlist.setModel(sampleListModel);
        jlist.setLayoutOrientation(JList.VERTICAL);
        jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        jlist.setPrototypeCellValue(new SampleListModel.Entry(ByteBuffer.allocate(1000), 1000000000, 0, null, null));
        JScrollPane jScrollPane = new JScrollPane();
        jScrollPane.getViewport().add(jlist);
        detailPane.add(new JLabel(String.format(trackViewDetailPaneHeader, sampleListModel.getTrackId())), BorderLayout.PAGE_START);
        detailPane.add(jScrollPane, BorderLayout.CENTER);
        jlist.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    rawDataSplitPane.setBottomComponent(new JHexEditor(((SampleListModel.Entry) ((JList) e.getSource()).getSelectedValue()).sample));

                }
            }
        });
        detailPanel.add(detailPane);
        detailPanel.revalidate();
    }

    JFileChooser fileChooser = new JFileChooser();


    public void open(File f) throws IOException {
        this.file = f;
        IsoFile isoFile = new IsoFile(new RandomAccessFile(f, "r").getChannel());
        long start = System.nanoTime();
        final List<LogRecord> messages = new LinkedList<LogRecord>();
        Handler myTemperaryLogHandler = new Handler() {
            @Override
            public void publish(LogRecord record) {
                messages.add(record);
            }

            @Override
            public void flush() {
            }

            @Override
            public void close() throws SecurityException {
            }
        };
        Logger.getLogger("").addHandler(myTemperaryLogHandler);


        Logger.getAnonymousLogger().removeHandler(myTemperaryLogHandler);
        System.err.println("Parsing took " + ((System.nanoTime() - start) / 1000000d) + "ms.");

        tree.setModel(new IsoFileTreeModel(isoFile));
        tree.revalidate();


        trackList.setModel(new TrackListModel(isoFile));
        if (!messages.isEmpty()) {
            String message = "";
            for (LogRecord logRecord : messages) {
                message += logRecord.getMessage() + "\n";
            }
            JOptionPane.showMessageDialog(this,
                    message,
                    "Parser Messages",
                    JOptionPane.WARNING_MESSAGE);

        }
        if (details instanceof Box) {
            String path = Path.createPath((Box) details);
            Box nuDetail = Path.getPath(isoFile, path);
            if (nuDetail != null) {
                showDetails(nuDetail);
            } else {
                showDetails(isoFile);
            }
        } else {
            showDetails(isoFile);
        }
        mainFrame.setTitle("Iso Viewer - " + f.getAbsolutePath());

    }


    @Action(name = "open-iso-file")
    public void open() {

        int state = fileChooser.showOpenDialog(IsoViewerPanel.this);
        if (state == JFileChooser.APPROVE_OPTION) {
            try {
                open(fileChooser.getSelectedFile());
            } catch (IOException e) {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                PrintStream ps = new PrintStream(baos);
                e.printStackTrace(ps);
                JOptionPane.showMessageDialog(this,
                        new String(baos.toByteArray()),
                        "e.getMessage()",
                        JOptionPane.ERROR_MESSAGE);
                ;
            }

        }

    }

    public void showDetails(Object object) {
        details = object;
        Cursor oldCursor = getCursor();
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        try {
            JComponent detailPane = new JPanel();
            if (object instanceof Box) {
                detailPane = new GenericBoxPane((Box) object);
            }
            detailPanel.removeAll();
            detailPanel.add(detailPane, BorderLayout.CENTER);
            detailPanel.revalidate();
            ByteBuffer displayMe;
            if (object instanceof Box && !(object instanceof IsoFile)) {
                displayMe = ByteBuffer.allocate(l2i(((Box) object).getSize()));
                try {
                    ((Box) object).getBox(new ByteBufferByteChannel(displayMe));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            } else if (object instanceof IsoFile) {
                FileChannel fc = new FileInputStream(this.file).getChannel();
                displayMe = fc.map(FileChannel.MapMode.READ_ONLY, 0, Math.min(this.file.length(), Integer.MAX_VALUE));
                fc.close();
            } else {
                displayMe = ByteBuffer.allocate(0);
            }
            rawDataSplitPane.setBottomComponent(new JHexEditor(displayMe));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            setCursor(oldCursor);

        }
    }

    public Object getSessionState(Component c) {
        return this.file.getAbsolutePath();
    }

    public void setSessionState(Component c, Object state) {
        try {
            open(new File(state.toString()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}