mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-22 03:02:35 +01:00
Working on FCP format
This commit is contained in:
parent
61c25e9896
commit
b7fb7251b1
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ SubtitleEdit-*-setup.exe
|
|||||||
/SubtitleEdit.tar
|
/SubtitleEdit.tar
|
||||||
/SubtitleEdit.tgz
|
/SubtitleEdit.tgz
|
||||||
/tabspace.exe
|
/tabspace.exe
|
||||||
|
/src/Languages/LanguageMaster.xml
|
||||||
|
175
src/Logic/SubtitleFormats/FinalCutProXml14Text.cs
Normal file
175
src/Logic/SubtitleFormats/FinalCutProXml14Text.cs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
|
namespace Nikse.SubtitleEdit.Logic.SubtitleFormats
|
||||||
|
{
|
||||||
|
public class FinalCutProXml14Text : SubtitleFormat
|
||||||
|
{
|
||||||
|
public double FrameRate { get; set; }
|
||||||
|
|
||||||
|
public override string Extension
|
||||||
|
{
|
||||||
|
get { return ".fcpxml"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name
|
||||||
|
{
|
||||||
|
get { return "Final Cut Pro Xml 1.4 Text"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsTimeBased
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsMine(List<string> lines, string fileName)
|
||||||
|
{
|
||||||
|
var subtitle = new Subtitle();
|
||||||
|
LoadSubtitle(subtitle, lines, fileName);
|
||||||
|
return subtitle.Paragraphs.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToText(Subtitle subtitle, string title)
|
||||||
|
{
|
||||||
|
if (Configuration.Settings.General.CurrentFrameRate > 26)
|
||||||
|
FrameRate = 30;
|
||||||
|
else
|
||||||
|
FrameRate = 25;
|
||||||
|
|
||||||
|
string xmlStructure =
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" + Environment.NewLine +
|
||||||
|
"<!DOCTYPE fcpxml>" + Environment.NewLine +
|
||||||
|
Environment.NewLine +
|
||||||
|
"<fcpxml version=\"1.4\">" + Environment.NewLine +
|
||||||
|
" <resources>" + Environment.NewLine +
|
||||||
|
" <format height=\"1080\" width=\"1440\" frameDuration=\"100/2400s\" id=\"r1\"/>" + Environment.NewLine +
|
||||||
|
" <effect id=\"r2\" uid=\".../Titles.localized/Bumper:Opener.localized/Basic Title.localized/Basic Title.moti\" name=\"Basic Title\"/>" + Environment.NewLine +
|
||||||
|
// " <effect id=\"r4\" name=\"Basic Subtitles\" uid=\"~/Generators.localized/My FCPeffects - BG/BG Basic Subtitles/Basic Subtitles.motn\"/>" + Environment.NewLine +
|
||||||
|
" </resources>" + Environment.NewLine +
|
||||||
|
" <library location=\"\">" + Environment.NewLine +
|
||||||
|
" <event name=\"Title\" uid=\"15A02C43-1B7A-4CF8-8007-5C266E77A91E\">" + Environment.NewLine +
|
||||||
|
" <project name=\"SUBTITLES\" uid=\"E04A4539-1369-47C8-AC44-F459A96AC90F\">" + Environment.NewLine +
|
||||||
|
" <sequence duration=\"929s\" format=\"r1\" tcStart=\"0s\" tcFormat=\"NDF\" audioLayout=\"stereo\" audioRate=\"48k\">" + Environment.NewLine +
|
||||||
|
" <spine>" + Environment.NewLine +
|
||||||
|
" <gap name=\"Gap\" offset=\"0s\" duration=\"929s\" start=\"3600s\">" + Environment.NewLine +
|
||||||
|
" </gap>" + Environment.NewLine +
|
||||||
|
" </spine>" + Environment.NewLine +
|
||||||
|
" </sequence>" + Environment.NewLine +
|
||||||
|
" </project>" + Environment.NewLine +
|
||||||
|
" </event>" + Environment.NewLine +
|
||||||
|
" </library>" + Environment.NewLine +
|
||||||
|
"</fcpxml>";
|
||||||
|
|
||||||
|
string xmlClipStructure =
|
||||||
|
"<title name=\"Basic Title: [TITLEID]\" lane=\"1\" offset=\"8665300/2400s\" ref=\"r2\" duration=\"13400/2400s\" start=\"3600s\">" + Environment.NewLine +
|
||||||
|
" <param name=\"Position\" key=\"9999/999166631/999166633/1/100/101\" value=\"-1.67499 -470.934\"/>" + Environment.NewLine +
|
||||||
|
" <text>" + Environment.NewLine +
|
||||||
|
" <text-style ref=\"ts[NUMBER]\">THE NOISEMAKER</text-style>" + Environment.NewLine +
|
||||||
|
" </text>" + Environment.NewLine +
|
||||||
|
" <text-style-def id=\"ts[NUMBER]\">" + Environment.NewLine +
|
||||||
|
" <text-style font=\"Lucida Grande\" fontSize=\"36\" fontFace=\"Regular\" fontColor=\"0.793266 0.793391 0.793221 1\" baseline=\"29\" shadowColor=\"0 0 0 1\" shadowOffset=\"5 315\" alignment=\"center\"/>" + Environment.NewLine +
|
||||||
|
" </text-style-def>" + Environment.NewLine +
|
||||||
|
"</title>";
|
||||||
|
|
||||||
|
var xml = new XmlDocument();
|
||||||
|
xml.LoadXml(xmlStructure);
|
||||||
|
XmlNode videoNode = xml.DocumentElement.SelectSingleNode("//project/sequence/spine/gap");
|
||||||
|
int number = 1;
|
||||||
|
foreach (Paragraph p in subtitle.Paragraphs)
|
||||||
|
{
|
||||||
|
XmlNode video = xml.CreateElement("video");
|
||||||
|
video.InnerXml = xmlClipStructure.Replace("[NUMBER]", number.ToString(CultureInfo.InvariantCulture)).Replace("[TITLEID]", Utilities.RemoveHtmlTags(p.Text.Replace(Environment.NewLine," ").Replace(" ", " "), true));
|
||||||
|
|
||||||
|
XmlNode generatorNode = video.SelectSingleNode("title");
|
||||||
|
generatorNode.Attributes["offset"].Value = Convert.ToInt64(p.StartTime.TotalSeconds * 2400000) + "/2400000s";
|
||||||
|
generatorNode.Attributes["duration"].Value = Convert.ToInt64(p.Duration.TotalSeconds * 2400000) + "/2400000s";
|
||||||
|
generatorNode.Attributes["start"].Value = Convert.ToInt64(p.StartTime.TotalSeconds * 2400000) + "/2400000s";
|
||||||
|
|
||||||
|
XmlNode param = video.SelectSingleNode("title/text/text-style");
|
||||||
|
param.InnerText = Utilities.RemoveHtmlTags(p.Text);
|
||||||
|
|
||||||
|
videoNode.AppendChild(generatorNode);
|
||||||
|
number++;
|
||||||
|
}
|
||||||
|
|
||||||
|
string xmlAsText = ToUtf8XmlString(xml);
|
||||||
|
xmlAsText = xmlAsText.Replace("fcpxml[]", "fcpxml");
|
||||||
|
xmlAsText = xmlAsText.Replace("fcpxml []", "fcpxml");
|
||||||
|
return xmlAsText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName)
|
||||||
|
{
|
||||||
|
_errorCount = 0;
|
||||||
|
FrameRate = Configuration.Settings.General.CurrentFrameRate;
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
lines.ForEach(line => sb.AppendLine(line));
|
||||||
|
string x = sb.ToString();
|
||||||
|
if (!x.Contains("<fcpxml version=\"1.4\">") && !x.Contains("<fcpxml version=\"1.5\">"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var xml = new XmlDocument();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
xml.LoadXml(x.Trim());
|
||||||
|
|
||||||
|
if (subtitle.Paragraphs.Count == 0)
|
||||||
|
{
|
||||||
|
foreach (XmlNode node in xml.SelectNodes("//project/sequence/spine/gap/title/text"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string text = node.ParentNode.InnerText;
|
||||||
|
Paragraph p = new Paragraph();
|
||||||
|
p.Text = text.Trim();
|
||||||
|
p.StartTime = DecodeTime(node.ParentNode.Attributes["offset"]);
|
||||||
|
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + DecodeTime(node.ParentNode.Attributes["duration"]).TotalMilliseconds;
|
||||||
|
bool add = true;
|
||||||
|
if (subtitle.Paragraphs.Count > 0)
|
||||||
|
{
|
||||||
|
var prev = subtitle.Paragraphs[subtitle.Paragraphs.Count - 1];
|
||||||
|
if (prev.Text == p.Text && prev.StartTime.TotalMilliseconds == p.StartTime.TotalMilliseconds)
|
||||||
|
add = false;
|
||||||
|
}
|
||||||
|
if (add)
|
||||||
|
subtitle.Paragraphs.Add(p);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_errorCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subtitle.Renumber(1);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_errorCount = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TimeCode DecodeTime(XmlAttribute duration)
|
||||||
|
{
|
||||||
|
// 220220/60000s
|
||||||
|
if (duration != null)
|
||||||
|
{
|
||||||
|
var arr = duration.Value.TrimEnd('s').Split('/');
|
||||||
|
if (arr.Length == 2)
|
||||||
|
{
|
||||||
|
return TimeCode.FromSeconds(long.Parse(arr[0]) / double.Parse(arr[1]));
|
||||||
|
}
|
||||||
|
else if (arr.Length == 1)
|
||||||
|
{
|
||||||
|
return TimeCode.FromSeconds(float.Parse(arr[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new TimeCode(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -65,6 +65,7 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats
|
|||||||
new FinalCutProXCM(),
|
new FinalCutProXCM(),
|
||||||
new FinalCutProXml13(),
|
new FinalCutProXml13(),
|
||||||
new FinalCutProXml14(),
|
new FinalCutProXml14(),
|
||||||
|
new FinalCutProXml14Text(),
|
||||||
new FinalCutProTestXml(),
|
new FinalCutProTestXml(),
|
||||||
new FinalCutProTest2Xml(),
|
new FinalCutProTest2Xml(),
|
||||||
new FlashXml(),
|
new FlashXml(),
|
||||||
|
@ -889,6 +889,7 @@
|
|||||||
<Compile Include="Logic\SubtitleFormats\AdobeEncore.cs" />
|
<Compile Include="Logic\SubtitleFormats\AdobeEncore.cs" />
|
||||||
<Compile Include="Logic\SubtitleFormats\Chk.cs" />
|
<Compile Include="Logic\SubtitleFormats\Chk.cs" />
|
||||||
<Compile Include="Logic\SubtitleFormats\DvdStudioProSpaceOne.cs" />
|
<Compile Include="Logic\SubtitleFormats\DvdStudioProSpaceOne.cs" />
|
||||||
|
<Compile Include="Logic\SubtitleFormats\FinalCutProXml14Text.cs" />
|
||||||
<Compile Include="Logic\SubtitleFormats\FinalCutProXml14.cs" />
|
<Compile Include="Logic\SubtitleFormats\FinalCutProXml14.cs" />
|
||||||
<Compile Include="Logic\SubtitleFormats\JsonType6.cs" />
|
<Compile Include="Logic\SubtitleFormats\JsonType6.cs" />
|
||||||
<Compile Include="Logic\SubtitleFormats\JsonType5.cs" />
|
<Compile Include="Logic\SubtitleFormats\JsonType5.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user