问题描述
我需要在mp4容器中读取和注入XMP元数据.
I need to read and inject XMP metadatas in an mp4 container.
我知道这可以在带有"mp4parser"库的android上实现,但是我找不到适用于iOS的等效项.
I know this is possible on android with the "mp4parser" library, but I couldn't find an equivalent for iOS.
对于读取部分,是否可以从相机胶卷中读取每个镜头以快速检查其360 XMP元数据?
For the read part, is it possible to read every footage from the camera roll to inspect their 360 XMP metadatas quickly ?
在撰写本文时,我正在尝试使用Adobe的XMP工具包.我的文件夹中有mp4视频,我想向其中注入一些360元数据.
For the writing, I'm trying to use Adobe's XMP toolkit. I have an mp4 video in a folder, and I want to inject into it some 360 metadatas.
注入元数据后(我想它可以正常工作),我将视频导出到相机胶卷,但看起来视频已转换为m4v,并且丢失了我编写的所有元数据.是预期的,还是我的代码错误?
After injecting the metadatas (I suppose it works), I export the video to the camera roll, but it looks like the video is converted to m4v and it lost every metadata I've written. Is it expected, or is my code wrong ?
这是代码:
MetadataManager.mm
MetadataManager.mm
#import "MetadataManager.h"
#define IOS_ENV 1
#include <string>
#define TXMP_STRING_TYPE std::string
#define XMP_INCLUDE_XMPFILES 1
#include "XMP.incl_cpp"
#include "XMP.hpp"
#include <iostream>
#include <fstream>
using namespace std;
@implementation MetadataManager {
}
+ (void)write360Metadatas:(NSString *)filePath {
if (!SXMPMeta::Initialize())
exit(1);
if (!SXMPFiles::Initialize())
exit(1);
SXMPFiles myFile;
XMP_OptionBits opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUseSmartHandler;
std::string status = "";
std::string filePathStd = std::string([filePath UTF8String]);
// First, try to open the file
bool ok = myFile.OpenFile(filePathStd, kXMP_UnknownFile, opts);
if( ! ok ){
status += "No smart handler available for " + filePathStd + "\n";
status += "Trying packet scanning.\n";
// Now try using packet scanning
opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUsePacketScanning;
ok = myFile.OpenFile(filePathStd, kXMP_UnknownFile, opts);
}
if(ok){
SXMPMeta meta;
myFile.GetXMP( &meta );
displayPropertyValues(&meta);
injectMetadatas(&meta);
// Check we can put the XMP packet back into the file
if(myFile.CanPutXMP(meta))
{
// If so then update the file with the modified XMP
myFile.PutXMP(meta);
}
// Close the SXMPFile. This *must* be called. The XMP is not
// actually written and the disk file is not closed until this call is made.
myFile.CloseFile();
}
}
SXMPMeta createXMPFromRDF()
{
const char * rdf =
"<rdf:SphericalVideo xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'"
" xmlns:GSpherical='http://ns.google.com/videos/1.0/spherical/'>"
"<GSpherical:Spherical>true</GSpherical:Spherical>"
"<GSpherical:Stitched>true</GSpherical:Stitched>"
"<GSpherical:StitchingSoftware>Spherical Metadata Tool</GSpherical:StitchingSoftware>"
"<GSpherical:ProjectionType>equirectangular</GSpherical:ProjectionType>"
"</rdf:SphericalVideo>";
SXMPMeta meta;
// Loop over the rdf string and create the XMP object
// 10 characters at a time
int i;
for (i = 0; i < (long)strlen(rdf) - 10; i += 10 )
{
meta.ParseFromBuffer ( &rdf[i], 10, kXMP_ParseMoreBuffers );
}
// The last call has no kXMP_ParseMoreBuffers options, signifying
// this is the last input buffer
meta.ParseFromBuffer ( &rdf[i], (XMP_StringLen) strlen(rdf) - i );
return meta;
}
void injectMetadatas(SXMPMeta * meta)
{
// Add an item onto the dc:creator array
// Note the options used, kXMP_PropArrayIsOrdered, if the array does not exist it will be created
meta->AppendArrayItem(kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, "Author Name", 0);
meta->AppendArrayItem(kXMP_NS_DC, "creator", kXMP_PropArrayIsOrdered, "Another Author Name", 0);
// Now update alt-text properties
meta->SetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", "An English title");
meta->SetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", "Un titre Francais");
// Display the properties again to show changes
cout << "After update:" << endl;
displayPropertyValues(meta);
// Create a new XMP object from an RDF string
SXMPMeta rdfMeta = createXMPFromRDF();
// Append the newly created properties onto the original XMP object
// This will:
// a) Add ANY new TOP LEVEL properties in the source (rdfMeta) to the destination (meta)
// b) Replace any top level properties in the source with the matching properties from the destination
SXMPUtils::ApplyTemplate(meta, rdfMeta, kXMPTemplate_AddNewProperties | kXMPTemplate_ReplaceExistingProperties | kXMPTemplate_IncludeInternalProperties);
// Display the properties again to show changes
cout << "After Appending Properties:" << endl;
displayPropertyValues(meta);
}
void displayPropertyValues(SXMPMeta * meta)
{
// Read a simple property
string simpleValue; //Stores the value for the property
meta->GetProperty(kXMP_NS_XMP, "CreatorTool", &simpleValue, 0);
cout << "meta:CreatorTool = " << simpleValue << endl;
// Get the first and second element in the dc:creator array
string elementValue;
meta->GetArrayItem(kXMP_NS_DC, "creator", 1, &elementValue, 0);
if(elementValue != "")
{
cout << "dc:creator[1] = " << elementValue << endl;
meta->GetArrayItem(kXMP_NS_DC, "creator", 2, &elementValue, 0);
cout << "dc:creator[2] = " << elementValue << endl;
}
// Get the the entire dc:subject array
string propValue;
int arrSize = meta->CountArrayItems(kXMP_NS_DC, "subject");
for(int i = 1; i <= arrSize;i++)
{
meta->GetArrayItem(kXMP_NS_DC, "subject", i, &propValue, 0);
cout << "dc:subject[" << i << "] = " << propValue << endl;
}
// Get the dc:title for English and French
string itemValue;
string actualLang;
meta->GetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", 0, &itemValue, 0);
cout << "dc:title in English = " << itemValue << endl;
meta->GetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", 0, &itemValue, 0);
cout << "dc:title in French = " << itemValue << endl;
// Get dc:MetadataDate
XMP_DateTime myDate;
if(meta->GetProperty_Date(kXMP_NS_XMP, "MetadataDate", &myDate, 0))
{
// Convert the date struct into a convenient string and display it
string myDateStr;
SXMPUtils::ConvertFromDate(myDate, &myDateStr);
cout << "meta:MetadataDate = " << myDateStr << endl;
}
cout << "----------------------------------------" << endl;
}
@end
感谢您的任何帮助.
推荐答案
我终于成功了,使用了空间媒体"的c ++端口而不是Adobe的xmp工具包.
I've finally succeeded, using the c++ port of "spatial-media" instead of Adobe's xmp toolkit.
这篇关于iOS-读/写mp4视频的XMP元数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!