Ejemplo n.º 1
0
        public void ExtractMKVSegments(String argMKVFile, List <gMKVSegment> argMKVSegmentsToExtract,
                                       String argOutputDirectory, MkvChapterTypes argChapterType, TimecodesExtractionMode argTimecodesExtractionMode, CuesExtractionMode argCueExtractionMode)
        {
            _Abort                   = false;
            _AbortAll                = false;
            _ErrorBuilder.Length     = 0;
            _MKVExtractOutput.Length = 0;
            // Analyze the MKV segments and get the initial parameters
            List <TrackParameter> initialParameters = new List <TrackParameter>();

            foreach (gMKVSegment seg in argMKVSegmentsToExtract)
            {
                if (_AbortAll)
                {
                    _ErrorBuilder.AppendLine("User aborted all the processes!");
                    break;
                }
                try
                {
                    initialParameters.AddRange(GetTrackParameters(seg, argMKVFile, argOutputDirectory, argChapterType, argTimecodesExtractionMode, argCueExtractionMode));
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    _ErrorBuilder.AppendLine(String.Format("Segment: {0}\r\nException: {1}\r\n", seg, ex.Message));
                }
            }

            // Group the initial parameters, in order to batch extract the mkv segments
            List <TrackParameter> finalParameters = new List <TrackParameter>();

            foreach (TrackParameter initPar in initialParameters)
            {
                TrackParameter currentPar = null;
                foreach (TrackParameter finalPar in finalParameters)
                {
                    if (finalPar.ExtractMode == initPar.ExtractMode)
                    {
                        currentPar = finalPar;
                        break;
                    }
                }
                if (currentPar != null)
                {
                    currentPar.TrackOutput = String.Format("{0} {1}", currentPar.TrackOutput, initPar.TrackOutput);
                }
                else
                {
                    finalParameters.Add(initPar);
                }
            }

            // Time to extract the mkv segments
            foreach (TrackParameter finalPar in finalParameters)
            {
                if (_AbortAll)
                {
                    _ErrorBuilder.AppendLine("User aborted all the processes!");
                    break;
                }
                try
                {
                    if (finalPar.WriteOutputToFile)
                    {
                        _OutputFileWriter = new StreamWriter(finalPar.OutputFilename, false, new UTF8Encoding(false, true));
                    }

                    OnMkvExtractTrackUpdated(Enum.GetName(finalPar.ExtractMode.GetType(), finalPar.ExtractMode));
                    ExtractMkvSegment(argMKVFile,
                                      String.Format("{0} {1} \"{2}\" {3}",
                                                    Enum.GetName(finalPar.ExtractMode.GetType(), finalPar.ExtractMode),
                                                    finalPar.Options,
                                                    argMKVFile,
                                                    finalPar.TrackOutput),
                                      finalPar.WriteOutputToFile);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    _ErrorBuilder.AppendLine(String.Format("Track output: {0}\r\nException: {1}\r\n", finalPar.TrackOutput, ex.Message));
                }
                finally
                {
                    if (finalPar.WriteOutputToFile)
                    {
                        _OutputFileWriter.Close();
                        _OutputFileWriter = null;

                        try
                        {
                            // If we have chapters with CUE format, then we read the XML chapters and convert it to CUE
                            if (finalPar.ExtractMode == MkvExtractModes.chapters)
                            {
                                if (finalPar.OutputFilename.EndsWith("cue"))
                                {
                                    Chapters c = null;
                                    using (StreamReader sr = new StreamReader(finalPar.OutputFilename))
                                    {
                                        XmlSerializer serializer = new XmlSerializer(typeof(Chapters));
                                        c = (Chapters)serializer.Deserialize(sr);
                                    }
                                    Cue cue = new Cue();
                                    cue.File     = Path.GetFileName(argMKVFile);
                                    cue.FileType = "WAVE";
                                    cue.Title    = Path.GetFileName(argMKVFile);
                                    cue.Tracks   = new List <CueTrack>();

                                    if (c.EditionEntry != null &&
                                        c.EditionEntry.Length > 0 &&
                                        c.EditionEntry[0].ChapterAtom != null &&
                                        c.EditionEntry[0].ChapterAtom.Length > 0)
                                    {
                                        Int32 currentChapterTrackNumber = 1;
                                        foreach (ChapterAtom atom in c.EditionEntry[0].ChapterAtom)
                                        {
                                            CueTrack tr = new CueTrack();
                                            tr.Number = currentChapterTrackNumber;
                                            if (atom.ChapterDisplay != null &&
                                                atom.ChapterDisplay.Length > 0)
                                            {
                                                tr.Title = atom.ChapterDisplay[0].ChapterString;
                                            }
                                            if (!String.IsNullOrEmpty(atom.ChapterTimeStart) &&
                                                atom.ChapterTimeStart.Contains(":"))
                                            {
                                                String[] timeElements = atom.ChapterTimeStart.Split(new String[] { ":" }, StringSplitOptions.None);
                                                if (timeElements.Length == 3)
                                                {
                                                    // Find cue minutes from hours and minutes
                                                    Int32 hours   = Int32.Parse(timeElements[0]);
                                                    Int32 minutes = Int32.Parse(timeElements[1]) + 60 * hours;
                                                    // Convert nanoseconds to frames (each second is 75 frames)
                                                    Int64 nanoSeconds   = 0;
                                                    Int32 frames        = 0;
                                                    Int32 secondsLength = timeElements[2].Length;
                                                    if (timeElements[2].Contains("."))
                                                    {
                                                        secondsLength = timeElements[2].IndexOf(".");
                                                        nanoSeconds   = Int64.Parse(timeElements[2].Substring(timeElements[2].IndexOf(".") + 1));
                                                        // I take the integer part of the result action in order to get the first frame
                                                        frames = Convert.ToInt32(Math.Floor(Convert.ToDouble(nanoSeconds) / 1000000000.0 * 75.0));
                                                    }
                                                    tr.Index = String.Format("{0}:{1}:{2}",
                                                                             minutes.ToString("#00")
                                                                             , timeElements[2].Substring(0, secondsLength)
                                                                             , frames.ToString("00")
                                                                             );
                                                }
                                            }

                                            cue.Tracks.Add(tr);
                                            currentChapterTrackNumber++;
                                        }
                                    }

                                    StringBuilder cueBuilder = new StringBuilder();

                                    cueBuilder.AppendFormat("REM GENRE \"\"\r\n");
                                    cueBuilder.AppendFormat("REM DATE \"\"\r\n");
                                    cueBuilder.AppendFormat("PERFORMER \"\"\r\n");
                                    cueBuilder.AppendFormat("TITLE \"{0}\"\r\n", cue.Title);
                                    cueBuilder.AppendFormat("FILE \"{0}\" {1}\r\n", cue.File, cue.FileType);

                                    foreach (CueTrack tr in cue.Tracks)
                                    {
                                        cueBuilder.AppendFormat("\tTRACK {0} AUDIO\r\n", tr.Number.ToString("00"));
                                        cueBuilder.AppendFormat("\t\tTITLE \"{0}\"\r\n", tr.Title);
                                        cueBuilder.AppendFormat("\t\tPERFORMER \"\"\r\n");
                                        cueBuilder.AppendFormat("\t\tINDEX 01 {0}\r\n", tr.Index);
                                    }

                                    using (StreamWriter sw = new StreamWriter(finalPar.OutputFilename, false, Encoding.UTF8))
                                    {
                                        sw.Write(cueBuilder.ToString());
                                    }
                                }
                            }
                        }
                        catch (Exception exc)
                        {
                            Debug.WriteLine(exc);
                            _ErrorBuilder.AppendLine(String.Format("Track output: {0}\r\nException: {1}\r\n", finalPar.TrackOutput, exc.Message));
                        }
                    }
                }
            }

            // check for errors
            if (_ErrorBuilder.Length > 0)
            {
                throw new Exception(_ErrorBuilder.ToString());
            }
        }
Ejemplo n.º 2
0
        private List <TrackParameter> GetTrackParameters(gMKVSegment argSeg,
                                                         String argMKVFile, String argOutputDirectory, MkvChapterTypes argChapterType,
                                                         TimecodesExtractionMode argTimecodesExtractionMode, CuesExtractionMode argCueExtractionMode)
        {
            // create the new parameter list type
            List <TrackParameter> trackParameterList = new List <TrackParameter>();

            // check the selected segment's type
            if (argSeg is gMKVTrack)
            {
                // if we are in a mode that requires timecodes extraction, add the parameter for the track
                if (argTimecodesExtractionMode != TimecodesExtractionMode.NoTimecodes)
                {
                    trackParameterList.Add(new TrackParameter(
                                               MkvExtractModes.timecodes_v2,
                                               String.Empty,
                                               String.Format("{0}:\"{1}\"",
                                                             ((gMKVTrack)argSeg).TrackID,
                                                             Path.Combine(
                                                                 argOutputDirectory,
                                                                 String.Format("{0}_track{1}_{2}.tc.txt",
                                                                               Path.GetFileNameWithoutExtension(argMKVFile),
                                                                               ((gMKVTrack)argSeg).TrackNumber,
                                                                               ((gMKVTrack)argSeg).Language))),
                                               false,
                                               String.Empty
                                               ));
                }

                // if we are in a mode that requires cues extraction, add the parameter for the track
                if (argCueExtractionMode != CuesExtractionMode.NoCues)
                {
                    trackParameterList.Add(new TrackParameter(
                                               MkvExtractModes.cues,
                                               String.Empty,
                                               String.Format("{0}:\"{1}\"",
                                                             ((gMKVTrack)argSeg).TrackID,
                                                             Path.Combine(
                                                                 argOutputDirectory,
                                                                 String.Format("{0}_track{1}_{2}.cue",
                                                                               Path.GetFileNameWithoutExtension(argMKVFile),
                                                                               ((gMKVTrack)argSeg).TrackNumber,
                                                                               ((gMKVTrack)argSeg).Language))),
                                               false,
                                               String.Empty
                                               ));
                }

                // check if the mode requires the extraction of the segment itself
                if (
                    !(
                        (argTimecodesExtractionMode == TimecodesExtractionMode.OnlyTimecodes &&
                         argCueExtractionMode == CuesExtractionMode.NoCues) ||
                        (argTimecodesExtractionMode == TimecodesExtractionMode.NoTimecodes &&
                         argCueExtractionMode == CuesExtractionMode.OnlyCues)
                        ) ||
                    (argTimecodesExtractionMode == TimecodesExtractionMode.OnlyTimecodes &&
                     argCueExtractionMode == CuesExtractionMode.OnlyCues)
                    )
                {
                    String outputFileExtension = String.Empty;
                    String outputDelayPart     = String.Empty;

                    // check the track's type in order to get the output file's extension and the delay for audio tracks
                    switch (((gMKVTrack)argSeg).TrackType)
                    {
                    case MkvTrackType.video:
                        // get the extension of the output via the CODEC_ID of the track
                        outputFileExtension = getVideoFileExtensionFromCodecID((gMKVTrack)argSeg);
                        break;

                    case MkvTrackType.audio:
                        // add the delay to the extraOutput for the track filename
                        outputDelayPart = String.Format("_DELAY {0}ms", ((gMKVTrack)argSeg).EffectiveDelay.ToString(CultureInfo.InvariantCulture));
                        // get the extension of the output via the CODEC_ID of the track
                        outputFileExtension = getAudioFileExtensionFromCodecID((gMKVTrack)argSeg);
                        break;

                    case MkvTrackType.subtitles:
                        // get the extension of the output via the CODEC_ID of the track
                        outputFileExtension = getSubtitleFileExtensionFromCodecID((gMKVTrack)argSeg);
                        break;

                    default:
                        break;
                    }

                    // add the parameter for extracting the track
                    trackParameterList.Add(new TrackParameter(
                                               MkvExtractModes.tracks,
                                               String.Empty,
                                               String.Format("{0}:\"{1}\"",
                                                             ((gMKVTrack)argSeg).TrackID,
                                                             Path.Combine(
                                                                 argOutputDirectory,
                                                                 String.Format("{0}_track{1}_{2}{3}.{4}",
                                                                               Path.GetFileNameWithoutExtension(argMKVFile),
                                                                               ((gMKVTrack)argSeg).TrackNumber,
                                                                               ((gMKVTrack)argSeg).Language,
                                                                               outputDelayPart,
                                                                               outputFileExtension))),
                                               false,
                                               String.Empty
                                               ));
                }
            }
            else if (argSeg is gMKVAttachment)
            {
                // check if the mode requires the extraction of the segment itself
                if (
                    !(
                        (argTimecodesExtractionMode == TimecodesExtractionMode.OnlyTimecodes &&
                         argCueExtractionMode == CuesExtractionMode.NoCues) ||
                        (argTimecodesExtractionMode == TimecodesExtractionMode.NoTimecodes &&
                         argCueExtractionMode == CuesExtractionMode.OnlyCues)
                        ) ||
                    (argTimecodesExtractionMode == TimecodesExtractionMode.OnlyTimecodes &&
                     argCueExtractionMode == CuesExtractionMode.OnlyCues)
                    )
                {
                    // add the parameter for extracting the attachment
                    trackParameterList.Add(new TrackParameter(
                                               MkvExtractModes.attachments,
                                               String.Empty,
                                               String.Format("{0}:\"{1}\"",
                                                             ((gMKVAttachment)argSeg).ID,
                                                             Path.Combine(
                                                                 argOutputDirectory,
                                                                 ((gMKVAttachment)argSeg).Filename)),
                                               false,
                                               String.Empty
                                               ));
                }
            }
            else if (argSeg is gMKVChapter)
            {
                // check if the mode requires the extraction of the segment itself
                if (
                    !(
                        (argTimecodesExtractionMode == TimecodesExtractionMode.OnlyTimecodes &&
                         argCueExtractionMode == CuesExtractionMode.NoCues) ||
                        (argTimecodesExtractionMode == TimecodesExtractionMode.NoTimecodes &&
                         argCueExtractionMode == CuesExtractionMode.OnlyCues)
                        ) ||
                    (argTimecodesExtractionMode == TimecodesExtractionMode.OnlyTimecodes &&
                     argCueExtractionMode == CuesExtractionMode.OnlyCues)
                    )
                {
                    String outputFileExtension = String.Empty;
                    String options             = String.Empty;
                    // check the chapter's type to determine the output file's extension and options
                    switch (argChapterType)
                    {
                    case MkvChapterTypes.XML:
                        outputFileExtension = "xml";
                        break;

                    case MkvChapterTypes.OGM:
                        outputFileExtension = "ogm.txt";
                        options             = "--simple";
                        break;

                    case MkvChapterTypes.CUE:
                        outputFileExtension = "cue";
                        break;

                    default:
                        break;
                    }

                    // add the parameter for extracting the chapters
                    trackParameterList.Add(new TrackParameter(
                                               MkvExtractModes.chapters,
                                               options,
                                               String.Empty,
                                               true,
                                               Path.Combine(
                                                   argOutputDirectory,
                                                   String.Format("{0}_chapters.{1}",
                                                                 Path.GetFileNameWithoutExtension(argMKVFile),
                                                                 outputFileExtension))
                                               ));
                }
            }

            return(trackParameterList);
        }