private void saveEDLCmd_Click(object sender, RoutedEventArgs e)
 {
     System.Windows.Forms.SaveFileDialog edlFile = new System.Windows.Forms.SaveFileDialog();
     edlFile.InitialDirectory = System.IO.Path.GetDirectoryName(mediaPlayer.Source.LocalPath);
     edlFile.FileName         = FilePaths.GetFullPathWithoutExtension(mediaPlayer.Source.LocalPath) + ".edl"; // Default filename is same as original filename
     edlFile.DefaultExt       = "*.edl";
     edlFile.AddExtension     = true;
     edlFile.Filter           = "EDL files|*.edl|All files|*.*";
     if (edlFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
     {
         WriteEDL(edlFile.FileName);
     }
 }
        private void mediaPlayer_MediaOpened(object sender, RoutedEventArgs e)
        {
            ResetMediaOpenButton();

            if (!mediaPlayer.NaturalDuration.HasTimeSpan)
            {
                MessageBox.Show(Localise.GetPhrase("Failed to read media duration"), Localise.GetPhrase("Media Read Error"), MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            _totalVideoTime    = mediaPlayer.NaturalDuration.TimeSpan; // Total video time
            timeSlider.Maximum = _totalVideoTime.TotalMilliseconds;    // Set the slider max value

            // NOTE: Update the timeStamp - don't fire event (simulate button) since it sets the mediaplayer to mode to manual and it fails to show the first frame of the video
            RoutedPropertyChangedEventArgs <double> newEventArgs = new RoutedPropertyChangedEventArgs <double>(1, 0);

            timeSlider_ValueChanged(sender, newEventArgs);

            // Enable button in the end after setting everything
            if (!_playing)
            {
                playStopCmd.IsEnabled      = timeSlider.IsEnabled = cutStartCmd.IsEnabled = true;
                cutEndCmd.IsEnabled        = false;
                mediaPlayer.LoadedBehavior = MediaState.Manual; // Set to manual and pause it so that the seek function works (otherwise it needs to be manually played for seek to work)
                mediaPlayer.Pause();                            // Load and pause the video
            }

            // Load the EDL file if found
            if (edlCuts.Items.Count <= 0) // MediaOpened is called multiple times sometimes, only load it once
            {
                string edlFile  = FilePaths.GetFullPathWithoutExtension(mediaPlayer.Source.LocalPath) + ".edl";
                string vprjFile = FilePaths.GetFullPathWithoutExtension(mediaPlayer.Source.LocalPath) + ".vprj";
                if (FileIO.FileSize(edlFile) > 0) // Check if it exists
                {
                    ReadEDL(edlFile);
                }
                else if (FileIO.FileSize(vprjFile) > 0)                     // Check for VPRJ file
                {
                    if (EDL.ConvertVPRJtoEDL(vprjFile, edlFile, new Log())) // Convert to EDL
                    {
                        if (FileIO.FileSize(edlFile) > 0)
                        {
                            ReadEDL(edlFile);
                        }
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Extracts subtitles from a video file into a SRT format (with same name) and cleans it up.
        /// It will overwrite any existing SRT files
        /// If there are multiple subtitles it extracts them into multiple files with incremental names.
        /// </summary>
        /// <param name="sourceFile">Path to video file</param>
        /// <param name="offset">Offset of the subtitles during extraction</param>
        /// <param name="overWrite">True to overwrite existing SRT files, false to create new ones with incremental names</param>
        /// <param name="languageExtractList">List of 3 digit language codes to extract (blank to extract all, unnamed languages will always be extracted)</param>
        /// <returns>True if successful</returns>
        public bool ExtractSubtitles(string sourceFile, string workingPath, int startTrim, int endTrim, double offset, bool overWrite, List <string> languageExtractList)
        {
            _jobLog.WriteEntry(this, ("Extracting Subtitles from " + sourceFile + " into SRT file"), Log.LogEntryType.Information);
            _jobLog.WriteEntry(this, "Source File : " + sourceFile, Log.LogEntryType.Debug);
            _jobLog.WriteEntry(this, "Working Path " + workingPath, Log.LogEntryType.Debug);
            _jobLog.WriteEntry(this, "Start Trim : " + startTrim.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug);
            _jobLog.WriteEntry(this, "Stop Trim : " + endTrim.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug);
            _jobLog.WriteEntry(this, "Offset : " + offset.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Debug);

            if (String.IsNullOrEmpty(sourceFile))
            {
                return(true); // nothing to do
            }
            if (!File.Exists(sourceFile))
            {
                _jobLog.WriteEntry(this, ("File does not exist " + sourceFile), Log.LogEntryType.Warning);
                return(true); //nothing to process
            }

            FFmpegMediaInfo mediaInfo = new FFmpegMediaInfo(sourceFile, _jobStatus, _jobLog);

            if (!mediaInfo.Success || mediaInfo.ParseError)
            {
                _jobLog.WriteEntry(this, ("Error reading subtitle info from file"), Log.LogEntryType.Error);
                return(false);
            }

            _jobLog.WriteEntry(this, "Found " + mediaInfo.SubtitleTracks.ToString() + " Subtitle tracks, extract only the first matching track", Log.LogEntryType.Debug);

            bool extractedSubtitle = false;

            for (int i = 0; i < mediaInfo.SubtitleTracks; i++)
            {
                if (extractedSubtitle) // Only extract and use one subtitle (sometimes chapter tracks are misidentified as subtitle tracks)
                {
                    continue;
                }

                // Build the command line
                string parameters    = "";
                string outputSRTFile = ""; // Using Serviio subtitle filename format (filename.srt or filename_language.srt or filename_uniquenumber.srt)

                // Check for language comparison if required
                if (languageExtractList != null)
                {
                    if (languageExtractList.Count > 0) // If list is empty, we extract all
                    {
                        _jobLog.WriteEntry(this, "Subtitle language extraction list -> " + String.Join(",", languageExtractList.ToArray()), Log.LogEntryType.Debug);

                        if (!String.IsNullOrWhiteSpace(mediaInfo.MediaInfo.SubtitleInfo[i].Language))        // check if we have a language defined for this track
                        {
                            if (!languageExtractList.Contains(mediaInfo.MediaInfo.SubtitleInfo[i].Language)) // This language is not in the list of extraction
                            {
                                _jobLog.WriteEntry(this, "Skipping subtitle extraction since subtitle language >" + mediaInfo.MediaInfo.SubtitleInfo[i].Language + "< is NOT in the subtitle language list", Log.LogEntryType.Warning);
                                continue; // Skip this subtitle track
                            }
                        }
                        else
                        {
                            _jobLog.WriteEntry(this, "Extracting subtitle since there is no language defined for track", Log.LogEntryType.Debug);
                        }
                    }
                }

                // Check for existing SRT files
                if (overWrite)
                {
                    outputSRTFile = Path.Combine(workingPath, Path.GetFileNameWithoutExtension(sourceFile)) + (i > 0 ? (String.IsNullOrWhiteSpace(mediaInfo.MediaInfo.SubtitleInfo[i].Language) ? "_" + i.ToString() : "_" + mediaInfo.MediaInfo.SubtitleInfo[i].Language) : "") + ".srt"; // First file user default name, then try to name with language first, if not give a unique number
                    parameters   += " -y";
                }
                else // Create a unique SRT file name
                {
                    int existingSRTCount = 0;
                    outputSRTFile = Path.Combine(workingPath, Path.GetFileNameWithoutExtension(sourceFile)) + ".srt"; // Try default name
                    while (File.Exists(outputSRTFile))
                    {
                        _jobLog.WriteEntry(this, "Subtitle file " + outputSRTFile + " exists, creating a new unique SRT filename", Log.LogEntryType.Debug);
                        outputSRTFile = Path.Combine(workingPath, Path.GetFileNameWithoutExtension(sourceFile)) + (String.IsNullOrWhiteSpace(mediaInfo.MediaInfo.SubtitleInfo[i].Language) ? "_" + existingSRTCount.ToString() : "_" + mediaInfo.MediaInfo.SubtitleInfo[i].Language + (existingSRTCount > 0 ? existingSRTCount.ToString() : "")) + ".srt"; // Create a unique SRT filename, try with language first, if not give a unique identifier, avoid a loop
                        existingSRTCount++;
                    }
                }

                // Build ffmpeg command line
                parameters += " -i " + FilePaths.FixSpaces(sourceFile);
                parameters += " -an -vn";
                parameters += " -map 0:" + mediaInfo.MediaInfo.SubtitleInfo[i].Stream.ToString(); // Subtitle steam no
                parameters += " -scodec copy -copyinkf -f srt " + FilePaths.FixSpaces(outputSRTFile);

                // Now extract it
                _jobLog.WriteEntry(this, "Extracting Subtitle " + (i + 1).ToString() + " with language >" + mediaInfo.MediaInfo.SubtitleInfo[i].Language + "< to " + outputSRTFile, Log.LogEntryType.Debug);
                FFmpeg ffmpeg = new FFmpeg(parameters, _jobStatus, _jobLog);
                ffmpeg.Run();
                if (!ffmpeg.Success)
                {
                    FileIO.TryFileDelete(outputSRTFile); // Delete partial file

                    // Backup, try using MP4Box instead to extract it
                    _jobLog.WriteEntry(this, ("FFMPEG failed to extract subtitles into SRT file, retrying using MP4Box"), Log.LogEntryType.Warning);
                    parameters = "-srt " + (mediaInfo.MediaInfo.SubtitleInfo[i].Stream + 1).ToString() + " " + FilePaths.FixSpaces(sourceFile);
                    // MP4Box create an output file called <input>_<track>_text.srt
                    // Check if the output srt exists and then rename it if it does
                    string tempSrtOutput = FilePaths.GetFullPathWithoutExtension(sourceFile) + "_" + (mediaInfo.MediaInfo.SubtitleInfo[i].Stream + 1).ToString() + "_text.srt";
                    bool   tempSrtExists = false;
                    if (File.Exists(tempSrtOutput)) // Save the output srt filename if it exists
                    {
                        try
                        {
                            FileIO.MoveAndInheritPermissions(tempSrtOutput, tempSrtOutput + ".tmp");
                        }
                        catch (Exception e)
                        {
                            _jobLog.WriteEntry(this, ("Error extracting subtitles into SRT file.\r\n" + e.ToString()), Log.LogEntryType.Error);
                            return(false);
                        }
                        tempSrtExists = true;
                    }

                    // Extract the subtitle
                    MP4Box mp4Box = new MP4Box(parameters, _jobStatus, _jobLog);
                    mp4Box.Run();
                    if (!mp4Box.Success)
                    {
                        _jobLog.WriteEntry(this, ("Error extracting subtitles into SRT file"), Log.LogEntryType.Error);
                        FileIO.TryFileDelete(tempSrtOutput); // Delete partial file
                        if (tempSrtExists)
                        {
                            RestoreSavedSrt(tempSrtOutput);
                        }
                        return(false);
                    }

                    if (FileIO.FileSize(tempSrtOutput) <= 0) // MP4Box always return success even if nothing is extracted, so check if has been extracted
                    {
                        _jobLog.WriteEntry(this, "No or empty Subtitle file " + tempSrtOutput + " extracted by MP4Box, skipping", Log.LogEntryType.Debug);
                        FileIO.TryFileDelete(tempSrtOutput); // Delete empty file
                    }
                    else
                    {
                        // Rename the temp output SRT to the expected name
                        try
                        {
                            FileIO.MoveAndInheritPermissions(tempSrtOutput, outputSRTFile);
                        }
                        catch (Exception e)
                        {
                            _jobLog.WriteEntry(this, ("Error extracting subtitles into SRT file.\r\n" + e.ToString()), Log.LogEntryType.Error);
                            FileIO.TryFileDelete(tempSrtOutput); // Delete partial file
                            if (tempSrtExists)
                            {
                                RestoreSavedSrt(tempSrtOutput);
                            }
                            return(false);
                        }
                    }

                    // Restore temp SRT file if it exists
                    if (tempSrtExists)
                    {
                        RestoreSavedSrt(tempSrtOutput);
                    }
                }

                if (FileIO.FileSize(outputSRTFile) <= 0) // Check for empty files
                {
                    _jobLog.WriteEntry(this, "Empty Subtitle file " + outputSRTFile + " extracted, deleting it", Log.LogEntryType.Warning);
                    FileIO.TryFileDelete(outputSRTFile); // Delete empty file
                }
                else
                {
                    // Trim the SRT file if required
                    if (startTrim > 0 || endTrim > 0)
                    {
                        // Get the length of the video, needed to calculate end point
                        float Duration = 0;
                        Duration = VideoParams.VideoDuration(sourceFile);
                        if (Duration <= 0)
                        {
                            FFmpegMediaInfo ffmpegStreamInfo = new FFmpegMediaInfo(sourceFile, _jobStatus, _jobLog);
                            if (ffmpegStreamInfo.Success && !ffmpegStreamInfo.ParseError)
                            {
                                // Converted file should contain only 1 audio stream
                                Duration = ffmpegStreamInfo.MediaInfo.VideoInfo.Duration;
                                _jobLog.WriteEntry(this, ("Video duration") + " : " + Duration.ToString(CultureInfo.InvariantCulture), Log.LogEntryType.Information);

                                if (Duration == 0)
                                {
                                    _jobLog.WriteEntry(this, ("Video duration 0"), Log.LogEntryType.Error);
                                    return(false);
                                }
                            }
                            else
                            {
                                _jobLog.WriteEntry(this, ("Cannot read video duration"), Log.LogEntryType.Error);
                                return(false);
                            }
                        }

                        // Trim the subtitle
                        if (!TrimSubtitle(outputSRTFile, workingPath, startTrim, endTrim, Duration, 0))
                        {
                            _jobLog.WriteEntry(this, ("Error trimming SRT file"), Log.LogEntryType.Error);
                            return(false);
                        }
                    }

                    // Clean it up and offset the SRT if required
                    if (!SRTValidateAndClean(outputSRTFile, offset))
                    {
                        _jobLog.WriteEntry(this, ("Cannot clean and set offset for SRT file"), Log.LogEntryType.Error);
                        return(false);
                    }

                    // Check for empty file
                    if (Util.FileIO.FileSize(outputSRTFile) <= 0)
                    {
                        FileIO.TryFileDelete(outputSRTFile); // Delete the empty file
                        _jobLog.WriteEntry(this, ("No valid SRT file found"), Log.LogEntryType.Warning);
                        continue;                            // check for the next subtitle track
                    }

                    _extractedSRTFile = outputSRTFile; // Save it
                    _jobLog.WriteEntry(this, "Extracted Subtitle file " + outputSRTFile + ", size [KB] " + (FileIO.FileSize(outputSRTFile) / 1024).ToString("N", CultureInfo.InvariantCulture), Log.LogEntryType.Debug);
                    extractedSubtitle = true;          // We have success
                }
            }

            return(true);
        }