AVFoundation与spatial-media写全景MP4
2016-11-10 本文已影响344人
熊皮皮
使用AVAssetWriter虽然可方便地输出MP4文件,不过,对于需要打上全景标识(Spherical Video,由谷歌定义)的场合,却是无能为力。然而,无全景标识的全景视频上传到Youtube或Facebook被当成普通平面视频,则相应的视频播放页面为平面投影,此时用户看到的是全景展开图,显然不符合预期。
针对AVFoundation写全景标识这一需求,经查阅文档,发现AVAssetWriter只支持写预定义的元数据,由metadata属性管理。
@property(nonatomic, copy) NSArray<AVMetadataItem *> *metadata;
AVMetadataItem可接受的元数据键值由AV Foundation Metadata Key Constants表示,它对此作了分类处理,如下所示:
- Key Spaces
ID3 metadata identifiers. - Metadata Format Constants
Constants for specifying metadata formats. - Common Metadata Keys
Common metadata and common keys for metadata. - ID3 Metadata Keys
ID3 metadata keys. - iTunes Metadata Keys
iTunes metadata keys. - QuickTime User Data Keys
QuickTime user data keys. - QuickTime Metadata Keys
QuickTime metadata keys.
以Key Spaces为例,有下列键值可使用:
- AVMetadataKeySpaceCommon
The common key space. Keys in this space represent standard versions of keys that are found in most or all other key spaces. - AVMetadataKeySpaceID3
- AVMetadataKeySpaceiTunes
The iTunes key space. - AVMetadataKeySpaceQuickTimeUserData
The QuickTime user data key space. - AVMetadataKeySpaceQuickTimeMetadata
The QuickTime metadata key space.
查看所有元数据键值可发现,Google定义的Spherical Video并不在MP4或iTunes支持范围内。那么,如何给AVAssetWriter输出的全景MP4文件写入谷歌要求的Spherical Video相关标识呢?谷歌只提供了一个python脚本,我们在应用中直接使用它还是略为麻烦。在此,使用C++移植版spatial-media实现此功能,示例代码如下所示。注意,此库在iOS需要修正些编译错误。
SpatialMedia::Parser parser;
parser.m_strInFile = "input file";
parser.m_strOutFile = "output file";
if ("" == parser.getInFile()) {
cout << "Please provide an input file." << endl;
exit(-1);
}
Utils utils;
if (parser.getInject()) {
if ("" == parser.getOutFile()) {
cout << "Injecting metadata requires both input and output file." << endl;
exit(-2);
}
Metadata md;
std::string &strVideoXML = utils.generate_spherical_xml(parser.getStereoMode(), parser.getCrop());
md.setVideoXML(strVideoXML);
if (parser.getSpatialAudio())
md.setAudio(&g_DefAudioMetadata);
if (strVideoXML.length() > 1)
utils.inject_metadata(parser.getInFile(), parser.getOutFile(), &md);
else
cout << "Failed to generate metadata." << endl;
}