mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-22 11:12:36 +01:00
Merge pull request #8281 from ivandrofly/feature/generatevideowithhardsubs
Feature/generatevideowithhardsubs
This commit is contained in:
commit
ca9fa80b4b
34
src/Test/Logic/DimensionTest.cs
Normal file
34
src/Test/Logic/DimensionTest.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using Nikse.SubtitleEdit.Core.Common;
|
||||||
|
|
||||||
|
namespace Test.Logic
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class DimensionTest
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void InvalidTest()
|
||||||
|
{
|
||||||
|
var dimension = new Dimension();
|
||||||
|
Assert.AreEqual(0, dimension.Width);
|
||||||
|
Assert.AreEqual(0, dimension.Height);
|
||||||
|
Assert.IsTrue(!dimension.IsValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ValidTest()
|
||||||
|
{
|
||||||
|
var dimension = new Dimension(10, 10);
|
||||||
|
Assert.IsTrue(dimension.IsValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void EqualityTest()
|
||||||
|
{
|
||||||
|
var dimensionOne = new Dimension();
|
||||||
|
var dimensionTwo = new Dimension();
|
||||||
|
Assert.AreEqual(dimensionOne, dimensionTwo);
|
||||||
|
Assert.IsTrue(dimensionOne == dimensionTwo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -76,6 +76,7 @@
|
|||||||
<Compile Include="Logic\BeautifyTimeCodesTest.cs" />
|
<Compile Include="Logic\BeautifyTimeCodesTest.cs" />
|
||||||
<Compile Include="Logic\ConvertColorsToDialogTest.cs" />
|
<Compile Include="Logic\ConvertColorsToDialogTest.cs" />
|
||||||
<Compile Include="Core\LanguageAutoDetectLanguagesTest.cs" />
|
<Compile Include="Core\LanguageAutoDetectLanguagesTest.cs" />
|
||||||
|
<Compile Include="Logic\DimensionTest.cs" />
|
||||||
<Compile Include="Logic\NetflixHelperTest.cs" />
|
<Compile Include="Logic\NetflixHelperTest.cs" />
|
||||||
<Compile Include="Logic\SubtitleFormats\EbuStlTest.cs" />
|
<Compile Include="Logic\SubtitleFormats\EbuStlTest.cs" />
|
||||||
<Compile Include="Logic\SubtitleFormats\NetflixTimedTextTest.cs" />
|
<Compile Include="Logic\SubtitleFormats\NetflixTimedTextTest.cs" />
|
||||||
|
40
src/libse/Common/Dimension.cs
Normal file
40
src/libse/Common/Dimension.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Nikse.SubtitleEdit.Core.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Struct representing the dimensions of an object.
|
||||||
|
/// </summary>
|
||||||
|
public struct Dimension : IEquatable<Dimension>
|
||||||
|
{
|
||||||
|
public int Height { get; set; }
|
||||||
|
public int Width { get; set; }
|
||||||
|
|
||||||
|
public Dimension(int height, int width) => (Height, Width) = (height, width);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of the Dimension object, representing its height and width.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A string representation of the Dimension object, in the format "height x width".</returns>
|
||||||
|
public override string ToString() => $"{Height}x{Width}";
|
||||||
|
|
||||||
|
public bool Equals(Dimension other) => Height == other.Height && Width == other.Width;
|
||||||
|
public override bool Equals(object obj) => obj is Dimension other && Equals(other);
|
||||||
|
public static bool operator ==(Dimension left, Dimension right) => left.Equals(right);
|
||||||
|
public static bool operator !=(Dimension left, Dimension right) => !(left == right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the dimension (height and width) is valid.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if the dimension is valid; otherwise, false.</returns>
|
||||||
|
public bool IsValid() => Width > 0 && Height > 0;
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
return (Height * 397) ^ Width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,8 @@ namespace Nikse.SubtitleEdit.Core.Common
|
|||||||
public class FfmpegMediaInfo
|
public class FfmpegMediaInfo
|
||||||
{
|
{
|
||||||
public List<FfmpegTrackInfo> Tracks { get; set; }
|
public List<FfmpegTrackInfo> Tracks { get; set; }
|
||||||
public int VideoWidth { get; set; }
|
|
||||||
public int VideoHeight { get; set; }
|
public Dimension Dimension { get; set; }
|
||||||
|
|
||||||
private static readonly Regex ResolutionRegex = new Regex(@"\d\d+x\d\d+", RegexOptions.Compiled);
|
private static readonly Regex ResolutionRegex = new Regex(@"\d\d+x\d\d+", RegexOptions.Compiled);
|
||||||
|
|
||||||
@ -65,13 +65,12 @@ namespace Nikse.SubtitleEdit.Core.Common
|
|||||||
if (resolutionMatch.Success)
|
if (resolutionMatch.Success)
|
||||||
{
|
{
|
||||||
var parts = resolutionMatch.Value.Split('x');
|
var parts = resolutionMatch.Value.Split('x');
|
||||||
if (info.VideoWidth == 0 &&
|
if (info.Dimension.Width == 0 &&
|
||||||
parts.Length == 2 &&
|
parts.Length == 2 &&
|
||||||
int.TryParse(parts[0], out var w) &&
|
int.TryParse(parts[0], out var w) &&
|
||||||
int.TryParse(parts[1], out var h))
|
int.TryParse(parts[1], out var h))
|
||||||
{
|
{
|
||||||
info.VideoWidth = w;
|
info.Dimension = new Dimension(h, w);
|
||||||
info.VideoHeight = h;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using Nikse.SubtitleEdit.Core.VobSub;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
@ -707,5 +708,53 @@ namespace Nikse.SubtitleEdit.Core.Common
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string TryLocateSubtitleFile(string path, string videoFileName)
|
||||||
|
{
|
||||||
|
// search in these subdirectories: \Subs;\Sub;\Subtitles;
|
||||||
|
var knownSubtitleDirectories = new[]
|
||||||
|
{
|
||||||
|
path, Path.Combine(path, "Subs"), Path.Combine(path, "Sub"), Path.Combine(path, "Subtitles")
|
||||||
|
};
|
||||||
|
|
||||||
|
// handles if video file was sent with full path
|
||||||
|
if (Path.IsPathRooted(videoFileName))
|
||||||
|
{
|
||||||
|
videoFileName = Path.GetFileName(videoFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var knownSubtitleDirectory in knownSubtitleDirectories)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(knownSubtitleDirectory))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to locate subtitle file that has the same name as the video file
|
||||||
|
var defaultSubtitles = new[]
|
||||||
|
{
|
||||||
|
Path.Combine(knownSubtitleDirectory, Path.ChangeExtension(videoFileName, ".ass")),
|
||||||
|
Path.Combine(knownSubtitleDirectory, Path.ChangeExtension(videoFileName, ".srt"))
|
||||||
|
};
|
||||||
|
foreach (var defaultSubtitle in defaultSubtitles)
|
||||||
|
{
|
||||||
|
if (File.Exists(defaultSubtitle))
|
||||||
|
{
|
||||||
|
return defaultSubtitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get first subtitle in path with extension .ass or .srt
|
||||||
|
var assEnumerable = Directory.EnumerateFiles(knownSubtitleDirectory, "*.ass", SearchOption.TopDirectoryOnly);
|
||||||
|
var subRipEnumerable = Directory.EnumerateFiles(knownSubtitleDirectory, "*.srt", SearchOption.TopDirectoryOnly);
|
||||||
|
var subtitleFile = assEnumerable.Concat(subRipEnumerable).FirstOrDefault();
|
||||||
|
if (!string.IsNullOrEmpty(subtitleFile))
|
||||||
|
{
|
||||||
|
return subtitleFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2139,100 +2139,88 @@ namespace Nikse.SubtitleEdit.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddInputFile(string fileName)
|
private void AddInputFile(string videoFileName)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(fileName))
|
if (string.IsNullOrEmpty(videoFileName))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ext = Path.GetExtension(fileName).ToLowerInvariant();
|
var ext = Path.GetExtension(videoFileName).ToLowerInvariant();
|
||||||
if ((Utilities.AudioFileExtensions.Contains(ext) || Utilities.VideoFileExtensions.Contains(ext)) && File.Exists(fileName))
|
if ((Utilities.AudioFileExtensions.Contains(ext) || Utilities.VideoFileExtensions.Contains(ext)) && File.Exists(videoFileName))
|
||||||
{
|
{
|
||||||
var item = new BatchVideoAndSub();
|
var videoDimension = GetVideoDimension(videoFileName);
|
||||||
item.VideoFileName = fileName;
|
if (!videoDimension.IsValid())
|
||||||
item.VideoFileSizeInBytes = new FileInfo(fileName).Length;
|
|
||||||
|
|
||||||
var path = Path.GetDirectoryName(fileName);
|
|
||||||
var fileNameNoExt = Path.GetFileNameWithoutExtension(fileName);
|
|
||||||
var subFileName = Path.ChangeExtension(fileName, ".ass");
|
|
||||||
|
|
||||||
if (!File.Exists(subFileName))
|
|
||||||
{
|
{
|
||||||
subFileName = Path.ChangeExtension(fileName, ".srt");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File.Exists(subFileName))
|
var batchVideoAndSub = CreateBatchVideoAndSub(videoFileName);
|
||||||
{
|
var listViewItem = new ListViewItem(videoFileName) { Tag = batchVideoAndSub };
|
||||||
var files = Directory.GetFiles(path, fileNameNoExt + "*.ass");
|
listViewItem.SubItems.Add(videoDimension.ToString());
|
||||||
if (files.Length > 0)
|
var s = Utilities.FormatBytesToDisplayFileSize(batchVideoAndSub.VideoFileSizeInBytes);
|
||||||
{
|
|
||||||
subFileName = files[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!File.Exists(subFileName))
|
|
||||||
{
|
|
||||||
var files = Directory.GetFiles(path, fileNameNoExt + "*.srt");
|
|
||||||
if (files.Length > 0)
|
|
||||||
{
|
|
||||||
subFileName = files[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(subFileName))
|
|
||||||
{
|
|
||||||
item.SubtitleFileName = subFileName;
|
|
||||||
item.SubtitleFileFileSizeInBytes = new FileInfo(subFileName).Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mediaInfo = FfmpegMediaInfo.Parse(fileName);
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
if (mediaInfo.VideoWidth > 0 && mediaInfo.VideoHeight > 0)
|
|
||||||
{
|
|
||||||
width = mediaInfo.VideoWidth;
|
|
||||||
height = mediaInfo.VideoHeight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var vInfo = new VideoInfo { Success = false };
|
|
||||||
if (fileName.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
vInfo = QuartsPlayer.GetVideoInfo(fileName);
|
|
||||||
if (!vInfo.Success)
|
|
||||||
{
|
|
||||||
vInfo = LibMpvDynamic.GetVideoInfo(fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vInfo.Success)
|
|
||||||
{
|
|
||||||
vInfo = UiUtil.GetVideoInfo(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
width = vInfo.Width;
|
|
||||||
height = vInfo.Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width == 0 || height == 0)
|
|
||||||
{
|
|
||||||
SeLogger.Error("Skipping burn-in file with no video: " + fileName);
|
|
||||||
return; // skip audio or damaged files
|
|
||||||
}
|
|
||||||
|
|
||||||
var listViewItem = new ListViewItem(fileName);
|
|
||||||
listViewItem.Tag = item;
|
|
||||||
listViewItem.SubItems.Add($"{width}x{height}");
|
|
||||||
var s = Utilities.FormatBytesToDisplayFileSize(item.VideoFileSizeInBytes);
|
|
||||||
listViewItem.SubItems.Add(s);
|
listViewItem.SubItems.Add(s);
|
||||||
listViewItem.SubItems.Add(Path.GetFileName(item.SubtitleFileName));
|
listViewItem.SubItems.Add(Path.GetFileName(batchVideoAndSub.SubtitleFileName));
|
||||||
listViewItem.SubItems.Add(string.Empty);
|
listViewItem.SubItems.Add(string.Empty);
|
||||||
listViewBatch.Items.Add(listViewItem);
|
listViewBatch.Items.Add(listViewItem);
|
||||||
_batchVideoAndSubList.Add(item);
|
_batchVideoAndSubList.Add(batchVideoAndSub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BatchVideoAndSub CreateBatchVideoAndSub(string videoFileName)
|
||||||
|
{
|
||||||
|
var batchVideoAndSub = new BatchVideoAndSub
|
||||||
|
{
|
||||||
|
VideoFileName = videoFileName,
|
||||||
|
VideoFileSizeInBytes = new FileInfo(videoFileName).Length
|
||||||
|
};
|
||||||
|
|
||||||
|
var path = Path.GetDirectoryName(videoFileName);
|
||||||
|
// try to locate subtitle file for the input vide file
|
||||||
|
var subtitleFile = FileUtil.TryLocateSubtitleFile(path, videoFileName);
|
||||||
|
if (File.Exists(subtitleFile))
|
||||||
|
{
|
||||||
|
batchVideoAndSub.SubtitleFileName = subtitleFile;
|
||||||
|
batchVideoAndSub.SubtitleFileFileSizeInBytes = new FileInfo(subtitleFile).Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return batchVideoAndSub;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dimension GetVideoDimension(string videoFileName)
|
||||||
|
{
|
||||||
|
var mediaInfo = FfmpegMediaInfo.Parse(videoFileName);
|
||||||
|
if (mediaInfo.Dimension.IsValid())
|
||||||
|
{
|
||||||
|
return mediaInfo.Dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
var vInfo = new VideoInfo { Success = false };
|
||||||
|
if (videoFileName.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
vInfo = QuartsPlayer.GetVideoInfo(videoFileName);
|
||||||
|
if (!vInfo.Success)
|
||||||
|
{
|
||||||
|
vInfo = LibMpvDynamic.GetVideoInfo(videoFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vInfo.Success)
|
||||||
|
{
|
||||||
|
vInfo = UiUtil.GetVideoInfo(videoFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dimension = new Dimension(vInfo.Height, vInfo.Width);
|
||||||
|
|
||||||
|
// skip audio or damaged files
|
||||||
|
if (!dimension.IsValid())
|
||||||
|
{
|
||||||
|
SeLogger.Error("Skipping burn-in file with no video: " + videoFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
|
private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var indices = new List<int>();
|
var indices = new List<int>();
|
||||||
|
Loading…
Reference in New Issue
Block a user