/// <summary>
        /// Deserialize XML Batch file.
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        /// Todo: add some error handling.
        public static ArchiveTranscoderBatch ReadBatchFile(string filename)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(ArchiveTranscoderBatch));

            // If the XML document has been altered with unknown
            // nodes or attributes, they could be handled with
            // UnknownNode and UnknownAttribute events.
            //serializer.UnknownNode+= new XmlNodeEventHandler(serializer_UnknownNode);
            //serializer.UnknownAttribute+= new XmlAttributeEventHandler(serializer_UnknownAttribute);

            ArchiveTranscoderBatch b  = null;
            FileStream             fs = null;

            try
            {
                fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
                b  = (ArchiveTranscoderBatch)serializer.Deserialize(fs);
            }
            catch
            {
                b = null;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                }
            }
            return(b);
        }
        /// <summary>
        /// Write Batch file
        /// </summary>
        public static void WriteBatch(ArchiveTranscoderBatch batch, String filename)
        {
            XmlSerializer serializer =
                new XmlSerializer(typeof(ArchiveTranscoderBatch));
            TextWriter writer = new StreamWriter(filename);

            serializer.Serialize(writer, batch);
            writer.Close();
        }
        private void buttonBuild_Click(object sender, System.EventArgs e)
        {
            if (!buildingPreview)
            {
                //validate start time and duration
                DateTime start    = DateTime.MinValue;
                DateTime end      = DateTime.MinValue;
                int      duration = 0;
                try
                {
                    start = DateTime.Parse(this.textBoxStartTime.Text);
                }
                catch
                {
                    MessageBox.Show("Failed to parse Start Time as a date/time: " + this.textBoxStartTime.Text);
                    return;
                }

                try
                {
                    duration = Int32.Parse(this.textBoxDuration.Text);
                }
                catch
                {
                    MessageBox.Show("Failed to parse preview duration as a positive integer.");
                    return;
                }

                if (Directory.Exists(this.previewDirPath))
                {
                    this.axWindowsMediaPlayer1.URL = "";
                    try {
                        Directory.Delete(this.previewDirPath, true);
                    }
                    catch (System.IO.IOException) {
                        //This appears to be a bug.  Even with the recursive flag, it sometimes throws the
                        //"Directory is not empty" exception.  Seems safe to ignore.
                        #if DEBUG
                        MessageBox.Show("Debug message: Directory delete operation may have failed for " + this.previewDirPath +
                                        ".  It is most likely safe to ignore this message.");
                        #endif
                    }
                }

                end = start + TimeSpan.FromSeconds(duration);

                //create an encoder and load a job
                transcoder         = new ArchiveTranscoder();
                transcoder.SQLHost = sqlHost;
                transcoder.DBName  = dbName;
                ArchiveTranscoderBatch batch = new ArchiveTranscoderBatch();
                batch.Job                               = new ArchiveTranscoderJob[1];
                batch.Job[0]                            = new ArchiveTranscoderJob();
                batch.Job[0].ArchiveName                = "ArchiveTranscoder_preview";
                batch.Job[0].Target                     = new ArchiveTranscoderJobTarget[1];
                batch.Job[0].Target[0]                  = new ArchiveTranscoderJobTarget();
                batch.Job[0].Target[0].Type             = "stream";
                batch.Job[0].WMProfile                  = "norecompression";
                batch.Job[0].BaseName                   = "ArchiveTranscoder_preview";
                batch.Job[0].Path                       = Constants.TempDirectory;
                batch.Job[0].Segment                    = new ArchiveTranscoderJobSegment[1];
                batch.Job[0].Segment[0]                 = new ArchiveTranscoderJobSegment();
                batch.Job[0].Segment[0].VideoDescriptor = this.videoStreamGroup.ToVideoDescriptor();
                batch.Job[0].Segment[0].AudioDescriptor = new ArchiveTranscoderJobSegmentAudioDescriptor[this.checkedListBoxAudioSources.CheckedItems.Count];
                int i = 0;
                foreach (StreamGroup sg in this.checkedListBoxAudioSources.CheckedItems)
                {
                    batch.Job[0].Segment[0].AudioDescriptor[i] = sg.ToAudioDescriptor();
                    i++;
                }
                //batch.Job[0].Segment[0].StartTime = start.ToString(Constants.dtformat);
                batch.Job[0].Segment[0].StartTime = Utility.GetLocalizedDateTimeString(start, Constants.timeformat);
                //batch.Job[0].Segment[0].EndTime = end.ToString(Constants.dtformat);
                batch.Job[0].Segment[0].EndTime = Utility.GetLocalizedDateTimeString(end, Constants.timeformat);

                if (useSlideStream)
                {
                    Utility.SetSegmentFlag(batch.Job[0].Segment[0], SegmentFlags.SlidesReplaceVideo);
                    //Since slide streams start out uncompressed, we can't use norecompression.
                    //Use the 256kbps system profile
                    batch.Job[0].WMProfile = "9";
                    //In this case we also need a presentation source and slide decks
                    batch.Job[0].Segment[0].PresentationDescriptor = segment.PresentationDescriptor;
                    batch.Job[0].Segment[0].SlideDecks             = segment.SlideDecks;
                }

                transcoder.LoadJobs(batch);

                previewDirPath  = Path.Combine(Constants.TempDirectory, @"ArchiveTranscoder_preview");
                previewFilePath = Path.Combine(previewDirPath, @"stream\ArchiveTranscoder_preview.wmv");

                //register for stop encode and status events
                transcoder.OnBatchCompleted += new ArchiveTranscoder.batchCompletedHandler(OnBuildCompleted);
                transcoder.OnStatusReport   += new ArchiveTranscoder.statusReportHandler(OnStatusReport);
                transcoder.OnStopCompleted  += new ArchiveTranscoder.stopCompletedHandler(StopCompletedHandler);

                //disable controls during build
                BuildControlsEnable(false, false);

                String result = transcoder.Encode();

                if (result == null)
                {
                    buttonBuild.Text         = "Stop Build";
                    buildingPreview          = true;
                    this.currentPreviewStart = start;
                }
                else
                {
                    MessageBox.Show("Preview build failed to start: " + result);
                    BuildControlsEnable(true, false);
                }
            }
            else
            {
                this.Cursor = Cursors.WaitCursor;
                //stop build in progress..
                if (transcoder != null)
                {
                    transcoder.AsyncStop();
                }

                this.buttonBuild.Enabled = false;
                this.buttonBuild.Text    = "Stopping ...";
            }
        }