using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections.ObjectModel; using MatrixIO.IO.Bmff; using Microsoft.Win32; using System.IO; using System.Windows.Controls.Primitives; using System.Diagnostics; using MatrixIO.IO.Bmff.Boxes; namespace BmffViewer { /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { private readonly ObservableCollection _files = new ObservableCollection(); public ObservableCollection Files { get { return _files; } } public VirtualizedBinaryReader BinaryReader; public MainWindow() { InitializeComponent(); } private void SupportedBoxes_Executed(object sender, ExecutedRoutedEventArgs e) { var supportedBoxes = new SupportedBoxesWindow(); supportedBoxes.ShowDialog(); } private static readonly string FileFormats = String.Join("|", new string[] { "All Supported Files|*.mp4;*.m4a;*.m4v;*.mov;*.moov;*.qif;*.qtif;*.ismv;*.isma;*.ismt;*.3gp;*.3gpp;*.3g2;*.3gpp2;*.dcf;*.m21;*.mp21;*.dvb;*.jp2;*.jpx;*.f4v;*.f4p;*.f4a;*.f4b", "Audio Files|*.m4a;*.isma;*.f4a", "Caption Files|*.ismt", "Mobile Files|*.3gp;*.3gpp;*.3g2;*.3gpp2;*.dcf", "Image Files|*.jp2;*.jpx;*.qif;*.qtif", "Video files|*.mp4;*.m4a;*.m4v;*.mov;*.moov;*.ismv;*.isma;*.ismt;*.3gp;*.3gpp;*.3g2;*.3gpp2;*.m21;*.mp21;*.dvb;*.f4v;*.f4p", "3GPP|*.3gp;*.3gpp;*.3g2;*.3gpp2", "DCF|*.dcf", "DVB|*.dvb", "JPEG2000|*.jp2;*.jpx;*.jpm", "MPEG|*.mp4;*.m4a;*.m4v;*.m21;*.mp21", "PIFF|*.ismv;*.isma;*.ismt", "Flash|*.f4v;*.f4p;*.f4a;*.f4b", "All Files|*.*", }); private void Open_Executed(object sender, ExecutedRoutedEventArgs e) { var openFileDialog = new OpenFileDialog {Filter = FileFormats, CheckFileExists = true, Multiselect = true}; openFileDialog.FileOk += (source, cancelEventArgs) => { foreach (var bmf in from fileName in openFileDialog.FileNames where !Files.Any(file => file.FullName == fileName ? true : false) select new BaseMediaFile(fileName)) { Files.Add(bmf); } }; openFileDialog.ShowDialog(this); e.Handled = true; } private void Close_CanExecute(object sender, CanExecuteRoutedEventArgs e) { var item = TreeView1.Tag as TreeViewItem; if (item == null) return; BaseMediaFile bmf = GetFileForItem(item); if (bmf == null) return; e.CanExecute = true; e.Handled = true; } private void Close_Executed(object sender, ExecutedRoutedEventArgs e) { var item = TreeView1.Tag as TreeViewItem; if (item == null) return; BaseMediaFile bmf = GetFileForItem(item); if (bmf == null) return; Files.Remove(bmf); bmf.Close(); bmf.Dispose(); e.Handled = true; } private void SaveAs_CanExecute(object sender, CanExecuteRoutedEventArgs e) { var item = TreeView1.Tag as TreeViewItem; if (item == null) return; BaseMediaFile bmf = GetFileForItem(item); if (bmf == null) return; e.CanExecute = true; e.Handled = true; } private void SaveAs_Executed(object sender, ExecutedRoutedEventArgs e) { var item = TreeView1.Tag as TreeViewItem; if (item == null) return; BaseMediaFile bmf = GetFileForItem(item); if (bmf == null) return; var saveFileDialog = new SaveFileDialog { FileName = bmf.NameWithoutExtension + " (Copy)" + bmf.Extension, InitialDirectory = bmf.DirectoryName, Filter = FileFormats, CheckFileExists = false }; saveFileDialog.FileOk += (source, cancelEventArgs) => { if (saveFileDialog.FileName != bmf.FullName) { bmf.SaveAs(saveFileDialog.FileName); Files.Add(new BaseMediaFile(saveFileDialog.FileName)); } else MessageBox.Show("Cannot Save As to the same filename as the source file.", "Error"); }; saveFileDialog.ShowDialog(this); e.Handled = true; } private void FastStart_CanExecute(object sender, CanExecuteRoutedEventArgs e) { var item = TreeView1.Tag as TreeViewItem; if (item == null) return; BaseMediaFile bmf = GetFileForItem(item); if (bmf == null) return; var moov = bmf.Children.OfType().SingleOrDefault(); if (moov == null) return; var mdat = bmf.Children.OfType().SingleOrDefault(); if (mdat == null) return; if (bmf.Children.IndexOf(moov) > bmf.Children.IndexOf(mdat)) e.CanExecute = true; else { bool foundJunk = false; for (int i = bmf.Children.IndexOf(moov) + 1; i < bmf.Children.IndexOf(mdat); i++) { if (bmf.Children[i].Type == "junk" || bmf.Children[i].Type == "skip" || bmf.Children[i].Type == "free" || bmf.Children[i].Type == "wide") foundJunk = true; } if (!foundJunk) return; e.CanExecute = true; } e.Handled = true; } private void FastStart_Executed(object sender, ExecutedRoutedEventArgs e) { var item = TreeView1.Tag as TreeViewItem; if (item == null) return; BaseMediaFile bmf = GetFileForItem(item); if (bmf == null) return; var saveFileDialog = new SaveFileDialog { FileName = bmf.NameWithoutExtension + ".Progressive" + bmf.Extension, InitialDirectory = bmf.DirectoryName, Filter = FileFormats, CheckFileExists = false }; saveFileDialog.FileOk += (source, cancelEventArgs) => { if (saveFileDialog.FileName != bmf.FullName) { bmf.FastStart(saveFileDialog.FileName); Files.Add(new BaseMediaFile(saveFileDialog.FileName)); } else MessageBox.Show("Cannot FastStart to the same filename as the source file.", "Error"); }; saveFileDialog.ShowDialog(this); e.Handled = true; } private void DecompressMovieHeader_CanExecute(object sender, CanExecuteRoutedEventArgs e) { var item = TreeView1.Tag as TreeViewItem; if (item == null) return; BaseMediaFile bmf = GetFileForItem(item); if (bmf == null) return; var moov = bmf.Children.OfType().SingleOrDefault(); if (moov == null) return; var cmov = moov.Children.OfType().SingleOrDefault(); if (cmov == null) return; var dcom = cmov.Children.OfType().SingleOrDefault(); if (dcom == null) return; var cmvd = cmov.Children.OfType().SingleOrDefault(); if (cmvd == null) return; e.CanExecute = true; e.Handled = true; } private void DecompressMovieHeader_Executed(object sender, ExecutedRoutedEventArgs e) { var item = TreeView1.Tag as TreeViewItem; if (item == null) return; BaseMediaFile bmf = GetFileForItem(item); if (bmf == null) return; bmf.DecompressMovieHeader(); e.Handled = true; } // This is a bit hackish but it saves the TreeViewItem for the current selected item. private void TreeView1_TreeViewItem_Selected(object sender, RoutedEventArgs e) { var tv = sender as TreeView; if (tv != null) tv.Tag = e.OriginalSource; } private BaseMediaFile GetFileForItem(TreeViewItem item) { var currentItem = item; while(currentItem != null) { var parent = GetTreeViewItemParent(currentItem); if (parent !=null) currentItem = parent; else break; } var treeViewItem = (TreeViewItem) currentItem; return (treeViewItem != null) ? treeViewItem.DataContext as BaseMediaFile : null; } private TreeViewItem GetTreeViewItemParent(TreeViewItem item) { var parent = VisualTreeHelper.GetParent(item); while (parent != null && !(parent is TreeViewItem || parent is TreeView)) { parent = VisualTreeHelper.GetParent(parent); } return parent as TreeViewItem; } private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e) { e.Row.Header = e.Row.DataContext == CollectionView.NewItemPlaceholder ? "*" : e.Row.GetIndex().ToString(CultureInfo.InvariantCulture); } private LogWindow _logWindow; private void Log_Executed(object sender, ExecutedRoutedEventArgs e) { if (_logWindow == null) { _logWindow = new LogWindow(); _logWindow.Closed += (sender2, e2) => { _logWindow = null; }; _logWindow.Show(); } else { _logWindow.Activate(); } } } }