剪映专业版for Mac导出.srt及.fcpxml字幕

剪映专业版for Mac导出.srt及.fcpxml字幕

剪映工程数据文件分析

工程数据保存路径

剪映专业版for Mac工程数据是保存在~/Movies/JianyingPro/目录下的,剪映的英文名叫“VideoFusion-macOS.app”。

~/Movies/JianyingPro/目录下的每个目录就是剪映的一个项目(也就是剪映里的:本地草稿→剪辑草稿),目录名就是项目名称,每个项目下都会有一个draft_info.json,该文件就是保存剪辑信息的文件,比如轨道信息、字幕信息等等。

以下是一个实例路径,其中“202109221413”是“com.lveditor.draft”下的其中一个项目

~/Movies/JianyingPro/User Data/Projects/com.lveditor.draft/202109221413/draft_info.json

网上有些文章分析的Windows的版本该文件名称是draft_content.json,我不知道Mac和Win本来就不同名称,还是因为他们写文章的时候是老版本的原因,但就算名称不同,也很容易看出来哪个文件是保存剪辑信息的。

由于我没有安装Win版本,所以没有分析Win版本该文件在哪儿,但看网上的文章,它同样是在User DataProjectscom.lveditor.draft下的,至于“User Data”是在哪,我觉得应该是在Win的用户目录下。

工程数据json

以下为draft_info.json的结构(我只列出第一层键值以及所需数据)

{
    "canvas_config": {},
    "color_space": 0,
    "config": {},
    "conver": null,
    "create_time": 0,
    "duration": 2360833333,
    "extra_info": null,
    "fps": 30,
    "id": "84558384-1857-4B67-94B4-0CE425440D42",
    "keyframes": {},
    "last_modified_platform": {},
    "materials": {
        "texts": [
            {
                "content":"哎我现在再去另一个桌面看一下啊"
            }
        ]
    },
    "mutable_config": null,
    "name": "",
    "new_version": "35.0.0",
    "platform": {},
    "relationships": [],
    "tracks": [
        {
            segments: [
                {
                    "target_timerange": {
                        "duration": 260166666,
                        "start": 74000000
                    }
                }
            ]
        }
    ],
    "update_time": 0,
    "version": 340000
}

可以看到,materials→texts里保存的是字幕信息,而tracks→segments里保存的是时间信息(时间属于轨道不属性字幕本身,所以时间是保存在轨道里的)。

我一个39分21秒时长的视频,draft_info.json文件按json格式显示,共有104862行(差不多10万5千行)。

字幕数据json

字幕是存储在materials→texts下,texts是一个数组,里面其中一个元素是一个对象,数据如下

{
    "alignment": 1,
    "background_alpha": 1.0,
    "background_color": "",
    "bold_width": 0.0,
    "border_color": "#ffffff",
    "border_width": 0.08,
    "content": "哎我现在再去另一个桌面看一下啊",
    "font_id": "",
    "font_name": "",
    "font_path": "/Applications/VideoFusion-macOS.app/Contents/Resources/Font/SystemFont/zh-hans.ttf",
    "font_resource_id": "",
    "font_size": 5.0,
    "font_title": "系统",
    "font_url": "",
    "has_shadow": false,
    "id": "2A535D84-73D8-4CD1-9C21-515A7F990D2E",
    "initial_scale": 1.0,
    "italic_degree": 0,
    "ktv_color": "",
    "layer_weight": 0,
    "letter_spacing": 0.0,
    "line_spacing": 0.02,
    "shadow_alpha": 0.8,
    "shadow_angle": -45.0,
    "shadow_color": "",
    "shadow_distance": 8.0,
    "shadow_point": {
        "x": 1.0182337649086284,
        "y": -1.0182337649086284
    },
    "shadow_smoothing": 0.99,
    "shape_clip_x": false,
    "shape_clip_y": false,
    "style_name": "黑字白边",
    "sub_type": 0,
    "text_alpha": 1.0,
    "text_color": "#000000",
    "text_to_audio_ids": [],
    "type": "subtitle",
    "typesetting": 0,
    "underline": false,
    "underline_offset": 0.22,
    "underline_width": 0.05,
    "use_effect_default_color": false
}

可以看到,每一句字幕,除了文字本身外,都记录了它的颜色、字体、样式、透明度、位置、对齐方式等等,其中文字的键是content,不过没有该字幕对应的时间信息,因为时间信息属于轨道,它是保存在轨道中的。

border_width 文字描边宽度,与界面上显示的数值为0.002的关系,即保存的数值除以0.002才是界面上的数值,比如保存的border_width是0.08,其实界面上数值是0.08/0.002=40;
border_color 描边颜色,为标准的十六进制颜色码,即#号开头的6位十六进制数,如#ffffff
text_alpha 文字透明度,为0-1之间的数0完全透明,1完全不透明;
text_color 文字颜色,为标准的十六进制颜色码,即#开头的6位十六进制数,如#000000

剪映字体选择“系统”

样式选预设样式中的黑字白边

字幕位置为自动识别字幕后的默认位置,即(0,-788)

Final Cut Pro选择PingFang SC Medium,字体大小55.5

文字颜色黑色,描边为白色,宽度为3

位置y轴设置为-414.83px

这样,Final Cut Pro中设置出来的字幕大小和样式,包括字体,几乎是完全重合的。

轨道数据json

之所以要分析轨道信息json,是因为字幕也是在轨道里的,而时间信息属于轨道,所以字幕出现的时间信息其实是在轨道里的(而不是在字幕里)。

轨道信息是在tracks键中,tracks键对应的值是一个数组,它的其中一个元素如下:

{
    "flag": 0,
    "id": "BE3366EB-C5AF-4913-90AA-E20CB33F172E",
    "segments": [
        ……
    ],
    "type": "text",
}

其实轨道又包含片段(每一个字幕或者视频被切开了都是一个片段),所以实际的字幕时间信息,是保存在具体的片段里的。

也就是说,轨道可能有多条,它可能是视频、音频、文本(即字幕),而且视频本身也可能有多条轨、音频也有可能有多条轨、文本(字幕)也有可能有多条轨。

视频轨的type是video,音频我没测试,但肯定是audio,字幕轨的type是text,由于我们只是导出字幕,所以我们只要过滤出type为text的轨道即可。

轨道里的片段数据json

每条轨道都有一个segments数组,该数组的每个元素都是一个片段(如一段视频,一段音频,一段字幕),segments数组的其中一个元素(即一个片段)如下

{
    "cartoon": false,
    "clip": {
        "alpha": 1.0,
        "flip": {
            "horizontal": false,
            "vertical": false
        },
        "rotation": 0.0,
        "scale": {
            "x": 1.0,
            "y": 1.0
        },
        "transform": {
            "x": 0.0,
            "y": -0.73
        }
    },
    "enable_adjust": true,
    "enable_lut": true,
    "extra_material_refs": [
        "7D4E7F05-4B4C-4124-9BEB-01F50EE6A466"
    ],
    "id": "723095B4-D057-4856-9CF7-83F5F6F13AFA",
    "intensifies_audio": false,
    "is_tone_modify": false,
    "keyframe_refs": [],
    "last_nonzero_volume": 1.0,
    "material_id": "2A535D84-73D8-4CD1-9C21-515A7F990D2E",
    "render_index": 15028,
    "reverse": false,
    "source_timerange": null,
    "speed": 1.0,
    "target_timerange": {
        "duration": 2100000,
        "start": 2093933333
    },
    "volume": 1.0
}

其中material_id正是对应materials→texts里的id,另外target_timerange键有两个值,一个是start,另一个是duration,分别表示,该字幕从哪个时间开始,以及持续多长时间,单位都是微秒,即startduration的值你要除以100万后才是秒(除以1000后是毫秒),这个就是我们最终需要的数据,只要把它跟texts里的文本相对应,就能组装出每段字幕的开始时间、持续时间以及字幕内容这样的数组。

注意,material_id有时候并不对应materials→texts里的id,而是对应text_templates里的某个元素的id,text_templatestexts是同级的,text_templates里的id是模板id,表示这个字幕是模板字幕,因为模板字幕里不同文字可能样式不同,而样式不同就需要分开来写,所以遇到这种情况我们就不能用material_id,而是用extra_material_refs,它里有可能有多个id,这多个id才是对应materials→texts里的id

片段里的clip数据json

clip主要用于保存字幕的透明度和位置信息

"clip": {
    "alpha": 1.0,
    "flip": {
        "horizontal": false,
        "vertical": false
    },
    "rotation": 0.0,
    "scale": {
        "x": 1.0,
        "y": 1.0
    },
    "transform": {
        "x": 1.0,
        "y": -1.0
    }
}
  • alpha:透明度,1.0完全不透明,0完全透明,透明度是0-1.0之间的小数;
  • flip:翻转,用于设置水平翻转和垂直翻转,注意,翻转和旋转是不一样的,比如一个平静的湖面,你看到的树的倒影就是水平翻转,而旋转180度看上去是倒过来了,但是左边的文字却旋转到了右边,但翻转的话,文字还是在原来位置,翻转也可以叫镜像,目前在剪映macOS版v2.1.0版中,虽然配置文件有这个参数,但是界面上并没有相关选项,应该是等待后面慢慢增加吧;
  • rotation:旋转,用于设置旋转角度;
  • scale:放大缩小文字,剪映的数据文件中保存的font_size为5.0,而界面上并没有设置字体大小的参数,目前是通过这个scale放大缩小来完成字体大小设置,保存的数字是界面上的数字除以100(毕竟界面上的数字是有%号的,实际上就是要除以100);
  • transform:位置,x为横坐标,y为纵坐标,由于不同分辨率的坐标值是不一样的,所以记录数据时,不记录具体的坐标值,而是记录坐标比例。对苹果电脑来说,由于是Retina屏幕,它有虚拟像素的说法,即把4个物理像素认为是一个逻辑像素,这样显示会更加精细,比如以我的MacBook Pro 15寸 2015年中版来说,我的屏幕分辨率是1440×900,然而它实际物理像素点却是2880×1800,也就是宽高各乘以2。所以,一个1920×1080的视频,我导入到我电脑上的剪映里面,它真实像素其实是宽高各乘以2,也就是3840×2160,那么,以画面正中心为原点,即(0,0)点,x轴往左为负,右为正,也就是3840分为两个1920,向左到最左边为-1920,向右到最右边为+1920,注意这个最左边和最右边,是指文字整体x轴长度的中心点与最左边或最右边的边重合,y轴方向同理,向上是+1080,向下是-1080。而transform的(x,y),记录的是文字位置与宽高的比值,比如实际坐标(1920,1080)会记录成(1920/1920,1080/1080),也就是(1.0,1.0),大于宽高或高度的,就是大于1,否则就是在0和1之间,保留17位小数,这也是够精确的,不过保存的数字才是最准确的,显示出来的只显示整数,比如默认是(0,-788),而根据保存的数据,是0.73×1080=-788.4,也就是小数点它在界面上直接四舍五入了。

srt字幕分析

srt字幕格式

srt字幕格式中文描述(–>两端各有一个空格)

字幕序号(正整数,一般从1开始)
开始时间 --> 结束时间
字幕内容(英文)
字幕内容(中文)
空白行(表示本字幕段的结束)

开始时间和结束时间格式:时时:分分:秒秒,毫毫毫(分隔毫秒的符号也可以是点号:时时:分分:秒秒.毫毫毫,不过貌似都是用逗号的多),由于1s=1000ms,所以毫毫毫取值范围是0-999,因为到了1000就进位了。

字幕内容可多行,一般典型的是两行,一行中文一行英文,当然遇到古诗可能直接多行。

srt字幕实例

实际例子如下

1
00:00:58,300 --> 00:01:04,240
福爾摩斯二世

2
00:01:51,350 --> 00:01:55,390
有一句古老的諺語是這樣說的

3
00:01:55,390 --> 00:02:00,990
不要嘗試同時做兩件事情  並期望都能做好

4
00:02:01,686 --> 00:02:06,896
這是個想同時做好兩件事的男孩的故事

5
00:02:06,984 --> 00:02:17,334
他在小鎮的劇院裡當電影放映員的同時

6
00:02:17,365 --> 00:02:23,085
還在學習如何成為一個偵探

.fcpxml v1.9分析

本文基于Final Cut Pro 10.5.2。

导出fcpxml

要分析.fcpxml文件,首先需要导出一些文件才能分析。

在任意资源库→任意事件下,新建一个工程,如下图所示

注意,不同帧率的fcpxml文件,它里面的数据是不同的(当然结构是相同的),我是把8种帧率的全部都创建了一遍,并且全部在里面创建了字幕,当然其实我是先创建一个,调好字幕后,把字幕复制到所有其它项目里(注意粘贴的时候那个时间指针要在最前面)

然后就可以点击文件导出XML...即可导出.fcpxml文件,可以导出1.8和1.9版本,我导出的是1.9版本(MetaData View是General),不过我感觉跟1.8没区别(可能我的项目只是测试比较简单的原因吧),我把8种.fcpxml文件都导出后,就可以分析它们的区别了。

外层基础结构

导出的.fcpxml基础结构如下,主要内容是在library标签里面,当然resources标签里也有一些

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fcpxml>

<fcpxml version="1.9">
    <resources>
        ……
    </resources>
    <library location="file:///Users/bruce/Movies/xxxx.fcpbundle/">
        ……
    </library>
</fcpxml>

resources标签结构

29.97p的

<resources>
    <format id="r1" name="FFVideoFormat1080p2997" frameDuration="1001/30000s" width="1920" height="1080" colorSpace="1-1-1 (Rec. 709)"/>
    <effect id="r2" name="Basic Title" uid=".../Titles.localized/Bumper:Opener.localized/Basic Title.localized/Basic Title.moti"/>
</resources>

30p的

<resources>
    <format id="r1" name="FFVideoFormat1080p30" frameDuration="100/3000s" width="1920" height="1080" colorSpace="1-1-1 (Rec. 709)"/>
    <effect id="r2" name="Basic Title" uid=".../Titles.localized/Bumper:Opener.localized/Basic Title.localized/Basic Title.moti"/>
</resources>

format是格式和effect是效果,它们都有id,分别是r1和r2,用r是因为它们都是resources,第一个字母就是r。

format其实是被sequence标签的format属性引用的,引用方式就是通过id,即format="r1",而effect是被title引用的,引用方式是ref="r2"

format的name,是FFVideoFormat+分辨率(如720p、1080p)+帧率(如30p、29.97p等),但有小数的,都要把小数点去掉,也就是29.97p会写成2997p,同理,23.98p就写成2398p。

library标签的结构

跟我之前讲过的一样,library(资源库)、event(事件)、project(项目)是包含的关系,即library下包含事件,事件下又包含项目。

而project下包含的sequence就是“序列”(在PR中有这个概念),sequence下的spine是脊柱的意思,在这里指骨干,意思是所有的东西都写在里面了。

spine下又有gap,真正的数据,其实都是写在gap里面的(事实上如果不是单纯字幕,而是字幕+视频,它有可能是没有gap标签,而是用其它标签代替的)

<library location="file:///Users/bruce/Movies/test.fcpbundle/">
    <event name="2021-10-01" uid="275C8680-DD70-4C68-89BD-4D03659D0223">
        <project name="test-30p" uid="F847E060-DB77-4F9E-AFBA-7C6B1A09E7D3" modDate="2021-10-03 19:50:08 +0800">
            <sequence duration="222400/3000s" format="r1" tcStart="0s" tcFormat="NDF" audioLayout="stereo" audioRate="48k">
                <spine>
                    <gap name="Gap" offset="0s" duration="222400/3000s" start="3600s">
                        ……
                    </gap>
                </spine>
            </sequence>
        </project>
    </event>
    <smart-collection name="Projects" match="all">
        <match-clip rule="is" type="project"/>
    </smart-collection>
    <smart-collection name="All Video" match="any">
        <match-media rule="is" type="videoOnly"/>
        <match-media rule="is" type="videoWithAudio"/>
    </smart-collection>
    <smart-collection name="Audio Only" match="all">
        <match-media rule="is" type="audioOnly"/>
    </smart-collection>
    <smart-collection name="Stills" match="all">
        <match-media rule="is" type="stills"/>
    </smart-collection>
    <smart-collection name="Favorites" match="all">
        <match-ratings value="favorites"/>
    </smart-collection>
    <smart-collection name="个人收藏" match="all">
        <match-ratings value="favorites"/>
    </smart-collection>
    <smart-collection name="静止图像" match="all">
        <match-media rule="is" type="stills"/>
    </smart-collection>
    <smart-collection name="所有视频" match="any">
        <match-media rule="is" type="videoOnly"/>
        <match-media rule="is" type="videoWithAudio"/>
    </smart-collection>
    <smart-collection name="仅音频" match="all">
        <match-media rule="is" type="audioOnly"/>
    </smart-collection>
    <smart-collection name="项目" match="all">
        <match-clip rule="is" type="project"/>
    </smart-collection>
</library>

这里event和project都有name属性,这两个name其实就是最终你在FCP里导入fcpxml文件后,自动生成的事件和项目的名称,所以这两个值我们自己指定就可以,你想让你的fcpxml导入后生成什么名字的事件和什么名字的项目,你自己决定,当然我是取了剪映里的项目名作为项目名。

也就是说,你导入字幕并不是直接导入到某个项目里面的,而是它会自动新建一个事件,再在该事件下新建一个项目,最后你需要从这个项目里复制这些字幕再粘贴到你要添加字幕的项目里才算是真正“导入”了字幕。

另外就是sequence和gap标签都有一个duration属性,这两个值是相同的,在我这里是duration="222400/3000s",duration是“持续时间”的意思,这里的duration表示整个字幕的时间,其实就是最后那个字幕的时间,注意,如果字幕有多个轨道,最后一个字幕未必是在最后一条轨道,所以它在texts里的排序未必是排在最后的。

比如下图中,“这是测试5”这个字幕的结束时间,其实就是duration值,也就是说,我们需要从剪映中获取到这个字幕的结束时间,并把它用于duration值,其实方法很简单,在循环轨道和片段的时候,把所有字幕的结束时间都放进一个数组里,排序,最大那个就是我们需要的

当然,duration是用分数形式表示的,因为无法整除,所以只能用分数形式表示,事实上,fcpxml里所有表示时间的属性,基本上都是用分数表示的,除非真的能整除,只要带小数,那就不要写成小数,一律用分数表示。

还有就是modDate,修改时间,这个我也是直接用当前时间,当然那个+08时区的我就没管它,因为剪映本来就是中国产品,我直接就定死了东八区。

而与event(事件)同级的那些smart-collection就是fcp左侧的那些智能集合(如下图所示)
Xnip2021-09-30_15-36-17.jpg

gap标签结构

gap标签下有多个title标签,分别表示多个字幕片段,我这里只列出前两个title标签

<gap name="Gap" offset="0s" duration="2693691/30000s" start="107999892/30000s">
    <title name="欢迎大家观看我的 macOS 系列 - Basic Title" lane="1" offset="10803600/3000s" ref="r2" duration="6800/3000s" start="3600s">
        <param name="Position" key="9999/999166631/999166633/1/100/101" value="6.0188 -468.581"/>
        <param name="Flatten" key="9999/999166631/999166633/2/351" value="1"/>
        <param name="Alignment" key="9999/999166631/999166633/2/354/999169573/401" value="1 (Center)"/>
        <param name="Size" key="9999/999166631/999166633/5/999166635/3" value="55.5"/>
        <text>
            <text-style ref="ts2">欢迎大家观看我的 macOS 系列</text-style>
        </text>
        <text-style-def id="ts2">
            <text-style font="PingFang SC" fontSize="55.5" fontFace="Medium" fontColor="0 0 0 1" strokeColor="1 0.999974 0.999991 1" strokeWidth="4" kerning="6.3" alignment="center"/>
        </text-style-def>
    </title>
<gap>    

剪映的字幕数据,其实最终就是一段字幕一个title,最终就是拼出这些title,当然,其它部分也有一些数据需要填充。

首先我们来看一下gap标签的duration和start值(offset不用看,一定是0,因为我们从时间轴的0开始的)。

gap的duration就不用说了,前面library标签的结构里已经讲过了,而start值要讲讲,这个值一定是3600,至于为什么要从3600开始我也不知道,不过因为一些原因,它可能是一个无限接近3600的一个数,但不会超过3600,3600秒就是一小时,而之所以说无限接近3600,是因为它有可能有小数,比如我这个例子是29.97p的,它的值就是:107999892/30000=3599.9964,为什么不直接写3600呢?请先理解下边的一些视频概念

fontColor和strokeColor的参数顺序为(r g b a),即(红 绿 蓝 透明度),注意这个rgb是rgb值与255的比值,如果是0,那0/255还是0,如果是255,那255/255=1,也就是说,这个值是0-1之间的小数,要保留6位小数。

一些视频概念

视频的本质:
视频本质是由一张张的图片拼成的,连续不断的播放图片,当每秒钟播放的图片数量够多时,由于人眼的视觉暂留,我们就会感觉图片里面的内容在动。这些一张一张的图片,在视频里有一个专业名词,叫“帧”,英文frame。

帧率
我们把每秒播放的图片张数(即帧数)叫帧率,英文framer,单位就是帧每秒,英文frame per second,简写成fps,当然更简单的写法是直接写成p,比如Final Cut Pro里新建项目,就会让你选择多少多秒p的帧率,注意这个p就是指fps,跟1080p那个p的意思完全不同,请不要混淆!1080p的p是指逐行扫描(prograssive的首字母,与此对应的是1080i,i是interlace,交错,隔行扫描,即显示了1 3 5行,再显示2 4 6行,而逐行扫描是直接1 2 3 4 5 6)。

帧时长
有些人可能会说,按这个说法,30p就是一秒钟播放30张图片,那29.97呢?一秒钟播放29.97张?这是不可能的呀,一张图片放出来了,那就整张图片显示在屏幕上了,你不可能把右边的一半在截掉对吧?其实这只不过是一个等效的说法,我们可以把它放大100倍,即100秒播放2997张,这样是不是就说的通了呢?是的,理论上就是这样的,这样的话,29.97p的视频,它每张图片的播放时间是100/2997,而30p的,每张图片的播放时间是1/30,这个100/2997和1/30就是每张图片在显示器上停留的时间了,我们把这个叫“帧时长”。

事实上,29.97p的视频,它的帧时长并不是用100/2997来表示的,而是用1001/30000来表示的,具体原因我也不太明白,但29.97帧其实是推理出来的,真正的来源是1001/30000,不过100/2997跟1001/30000在微秒级都是完全相同的数,只有在纳秒的时候,才有点差别,但对于视频来讲,到了微秒级已经完全够用了,不过有些在微秒的最后一位就不相同了,比如23.98p,但这不会影响实际使用,因为微秒的最后一位实在太短了。

100/2997s =   0.03336670003s
1001/30000s = 0.03336666667s

还有其它的23.98p、59.94p都是一个原理,它们的帧时长,它们的分母,都是帧率向上取整后,再乘以1000,而分子,都是1001,比如23.94向上取整是24,乘以1000就是24000,分子是1001,所以23.94p的帧时长为1001/24000,而59.94的帧时长为1001/60000。

解释无限接近3600秒的问题

好了,有了以上的知识我们已经可以解释前面留下的问题:为什么start有时候不直接写3600而是一个无限接近3600的小数?

因为时间必须停留在帧的头和尾(严格来说没有尾,因为一帧的尾部其实又是另一帧的头部),不能卡在帧的中间,因为播放视频的时候,播放到某张图片(也就是某一帧)时,它整张图片是一起出来的,不可能这张图片的左侧先出来,右侧后出来,所以整个帧的时间,其实就是这张图片(即这一帧)的头部那个时间。

这个值start="107999892/30000"是29.97p的参数,我们可以计算一下,这个时间有多少帧呢?是(107999892/30000)/(1001/30000)=107892帧,刚好整除,没有小数,因为一帧就是一帧,一张图片播放出来就是整张一起显示出来,不可能显示左侧的三分之一或者三分之二,所以帧数是不可能有小数的,如果我们直接写成3600,我们来除一下:3600/(1001/30000)=107892.1078921079,看,这就有小数了,我已经说过,帧是不可能有小数的,后面这0.1帧是没有用的,因为时间位于帧头的时候,整个帧(整张图片)已经全部显示出来了,不可能只显示左侧的十分之一张图片。

特别注意:fcpxml里面,所有跟时间有关的数据,除以当前的帧时长,都必须得到一个整数才可以,否则FCP里导入这个fcpxml的时候就会报错,当然最终其实也是能导入的,就是它会自动帮你舍弃小数部分。

一般来说,所有涉及到时间的属性,它都用分数形式表示,而且分母就是帧时长的分母,比如对于30p帧率,分母就是3000,29.97p分母是30000,25p分母就是2500。

得到帧时长倍数的时间很简单,就是把你的时间除以帧时长,然后向下取整,再乘回帧时长,就会得到一个是帧时长倍数的时间,这个时间比你原来的时间会少一点点,少的那一点一定是不够一帧的时长的。

自已写转换小工具

简介

有了以上的理论,我相信只要是会写代码的人,都能把这个转换工具给写出来了,毕竟我已经说的那么详细那么明白了,如果哪里还有不明白的可以评论跟我说一下(评论邮箱一定要真实邮箱,这样我回复你的时候,你是会收到邮件提醒的,否则收不到邮件提醒,你可能不知道我已经回复了,你总不可能隔一会儿去看一下吧?)。

目前网上能找到的工具都是二次转换的,也就是要先用一种工具导出.srt,再用另一种工具把.srt转成.fcpxml,而我是一步到位,不仅能直接把剪映项目的字幕直接转成.fcpxml,我还顺带转出一份.srt给你,用不到可以直接删掉,但万一你用的到呢?

安装我写的小工具

  • 1、下载并解压出来,解压出来之后,会有一个jy2fcp.php文件,它就是我写的小工具了,你把它放到访达里某个固定的文件夹(放到一个你不会哪天不小心就把它删掉的地方);
  • 2、打开你终端软件(在启动台里搜索“终端”),运行下边这句命令(不要直接复制,要修改,请往下看)
echo 'alias getfcpxml="php /path/to/jy2fcp.php"' >> ~/.bashrc

其中/path/to/jy2fcp.phpjy2fcp.php文件的路径,所以在运行这句命令前,要先把它替换成它在你电脑里的真实路径。

如何得到jy2fcp.php的路径:你直接把jy2fcp.php从你访达里拖到终端上,就可以得到它的路径。

运行命令:把替换好路径的命令粘贴到终端,按回车即可运行,运行完不会有任何提示,运行了就可以,请不要重复运行。


注意:如果更换过其它shell,比如zsh,请把前面命令中的~/.bashrc换成~/.zshrc(这个是额外情况,一般人不用考虑,要考虑的他肯定看的懂)。

使用我的小工具

退出终端之后,再次打开终端,在里面输入以下命令,回车即可按提示导出.fcpxml文件

getfcpxml

视频演示(Safari有可能无法观看,如果无法观看请换其它浏览器)

Final Cut Pro导入字幕

剪映识别字幕

首先把你要添加字幕的视频添加到剪映,点击:文本→智能字幕→开始识别,稍等一会儿,就会自动识别出字幕,当然如果你是唱歌视频,也可以点“识别歌词”
Xnip2021-10-07_01-10-41.jpg

识别完字幕之后,我建议直接在剪映里修改字幕错误,毕竟是语音识别,肯定有些地方是不对的,当然你也可以直接导出.fcpxml,然后导入Final Cut Pro里后再来修改,但是我发现在剪映里调整特别流畅,而在Final Cut Pro里特别卡,动不动就正在渲染,所以我还是建议在剪映里调整好,当然这个调整主要是指文字识别错误的修正以及字幕时间的修正,而字幕样式和字幕位置则不用在意,因为字幕样式和字幕位置不会存储到导出的.fcpxml里面,所以你调好了也没有用。

导出.fcpxml文件

在剪映里调整好字幕之后,打开终端工具(启动台搜索“终端”),然后输入getfcpxml,按回车,即可进入导出程序,按提示即可导出,如果你在Final Cut Pro中的视频项目是30fps帧率的,那一直按回车就行,如果不是30fps的,也只需要选择一次帧率,其它地方都是按回车就行。

导出字幕过程截图
image.jpg

导入.fcpxml字幕

在Final Cut Pro中点击:文件(File)→导入(Import)→XML…

选择前面导出的.fcpxml文件进行导入,导入之后,它会自动生成一个名为“导入字幕事件”的事件,在该事件下会自动创建一个项目,该项目的名称就是你剪映中的项目名称,双击该项目,或者右击项目→点击“打开项目”(Open Project)来打开该字幕项目

打开字幕项目之后,随便点击一下时间线,然后cmd+A全选,再按cmd+C复制
image.jpg

注意:复制的时候,一定要同时选中下边的灰色条,cmd+A就能全选,千万不要认为这个灰色的条没用,就不复制它
image.jpg
因为如果不复制它,那么你的字幕将会顶到时间轴指针上(由于我们把时间轴指针放在时间轴开头,所以实际上你的字幕开头将会顶到视频的起始时间,也就是00:00:00.000处,然而这在大多数时候都是不对的,因为不可能我刚按下录制视频按键,我就开始说话了,说话时间肯定会稍微迟一点,比如过个5秒才开始说话,很明显第一个字幕应该在视频开始播放5秒后才出现,而那个灰色条就是用来做这个定位的,所以一定不能去掉那个点位的灰色条。


然后再打开你要添加字幕的项目(注意它肯定是在另一个事件里,你要先点击一下那个事件才能看的到你的项目),把时间轴指针定位到时间轴最前面,然后cmd+V粘贴即可
image.jpg

注意:粘贴的时候,时间轴指针一定要在最前面,因为粘贴的位置是从时间轴指针的位置开始的,如果它不在最前面,到时字幕就不是从最前面开始,导致对不上视频。

粘贴完之后,用cmd+-缩小一下时间轴,可以看到最后有一个灰色条,这个条是复制字幕的时候带过来的,把它删掉即可(这个条有时候可能没有,如果有就删掉,没有就不用管)
image.jpg

批量设置样式

由于导入的字幕没有样式,虽然粘贴进来了,但是样式却都是默认样式,不过我们可以批量设置样式。

首先对某一段字幕进行设置样式,设置完之后(保持选中它),点击右上角的“文本检查器”(Text Inspector)→点击“保存所有格式和外观属性”→给你的自定义样式起一个名字→保存

当你把.fcpxml的字幕粘贴进来之后,点击时间轴左上角的“索引”(Index),然后点击下边的“字幕”(Titles)就可以筛选出全部字幕,然后随便选中其中一个字幕,再按cmd+A全选字幕,再点击右上角的文本检查器→选择刚才保存的字幕样式,就可以把字幕样式应用到所有字幕(位置是无法应用到所有字幕的,只有外观样式才可以)
16332821774077.jpg

删除自定义样式

右击程序坞中的访达→前面文件夹,然后会弹出窗口,你把下面的路径复制进去,回车就能打开文件夹

~/Library/Application Support/Motion/Library/Text Styles/

打开文件夹之后,你可以看到,每个保存的样式有三个文件,比如我保存的样式叫“测试1”,则这三个文件分别为

测试1.molo
测试1.png
测试1_menu.png

要删除这个自定义样式,直接把这三个都删掉就行,不过你选择的时候,它还是会有,属于缓存,选了它也不会管用,要关掉Final Cut Pro再打开,但是再看它还是有可能会有,如果还是有,你可以设置一下其它样式,它就会没有了。

详见:在 Final Cut Pro 中应用预置文本样式


参考:
视频格式比例等讲解(从00:31:08看起)
Creating FCPXML Documents

打赏
订阅评论
提醒
guest

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请发表评论。x
()
x

扫码在手机查看
iPhone请用自带相机扫
安卓用UC/QQ浏览器扫

剪映专业版for Mac导出.srt及.fcpxml字幕