我正在从一堆静止图像创建视频(QuickTime .mov格式,H.264编码),我想在此过程中添加章节轨道。视频创建正常,我没有检测到任何错误,但QuickTime Player没有显示任何章节。我知道this question但它并没有解决我的问题。
与最新版本不同,旧版QuickTime Player 7可以显示有关电影曲目的信息。当我打开带有工作章节的电影(使用旧的QuickTime代码创建)时,我会看到视频轨道和文本轨道,视频轨道知道文本轨道正在为视频提供章节。然而,如果我检查由我的新代码创建的电影,则存在元数据轨道以及视频轨道,但QuickTime不知道元数据轨道应该提供章节。我读过的东西让我相信一个人应该使用元数据来编写章节,但有没有人真正得到这个呢?文本跟踪会有效吗?
以下是我为元数据创建AVAssetWriterInput
的方法。
// Make dummy AVMetadataItem to get its format
AVMutableMetadataItem* dummyMetaItem = [AVMutableMetadataItem metadataItem];
dummyMetaItem.identifier = AVMetadataIdentifierQuickTimeUserDataChapter;
dummyMetaItem.dataType = (NSString*) kCMMetadataBaseDataType_UTF8;
dummyMetaItem.value = @"foo";
AVTimedMetadataGroup* dummyGroup = [[[AVTimedMetadataGroup alloc]
initWithItems: @[dummyMetaItem]
timeRange: CMTimeRangeMake( kCMTimeZero, kCMTimeInvalid )] autorelease];
CMMetadataFormatDescriptionRef metaFmt = [dummyGroup copyFormatDescription];
// Make the input
AVAssetWriterInput* metaWriterInput = [AVAssetWriterInput
assetWriterInputWithMediaType: AVMediaTypeMetadata
outputSettings: nil
sourceFormatHint: metaFmt];
CFRelease( metaFmt );
// Associate metadata input with video input
[videoInput addTrackAssociationWithTrackOfInput: metaWriterInput
type: AVTrackAssociationTypeChapterList];
// Associate metadata input with AVAssetWriter
[writer addInput: metaWriterInput];
// Create a metadata adaptor
AVAssetWriterInputMetadataAdaptor* metaAdaptor = [AVAssetWriterInputMetadataAdaptor
assetWriterInputMetadataAdaptorWithAssetWriterInput: metaWriterInput];
P.S。我尝试使用文本轨道(类型为AVAssetWriterInput
的{{1}}),而QuickTime播放器说结果是"而不是电影"。不确定我做错了什么。
答案 0 :(得分:1)
我设法使用文本轨道来提供章节。我花了一个Apple开发人员技术支持事件,并被告知这是正确的方法。
我认为已创建AVAssetWriter
,并为其分配了视频轨道的AVAssetWriterInput
。
这里最棘手的部分是创建文本格式描述。文档说CMTextFormatDescriptionCreateFromBigEndianTextDescriptionData
将TextDescription
结构视为输入,但忽略了该结构的定义。它位于Movies.h中,它位于QuickTime.framework中,不再是Mac OS SDK的一部分。谢谢,Apple。
// Create AVAssetWriterInput
AVAssetWriterInput* textWriterInput = [AVAssetWriterInput
assetWriterInputWithMediaType: AVMediaTypeText
outputSettings: nil ];
textWriterInput.marksOutputTrackAsEnabled = NO;
// Connect input to writer
[writer addInput: textWriterInput];
// Mark the text track as providing chapter for the video
[videoWriterInput addTrackAssociationWithTrackOfInput: textWriterInput
type: AVTrackAssociationTypeChapterList];
// Create the text format description, which we will need
// when creating each sample.
CMFormatDescriptionRef textFmt = NULL;
TextDescription textDesc;
memset( &textDesc, 0, sizeof(textDesc) );
textDesc.descSize = OSSwapHostToBigInt32( sizeof(textDesc) );
textDesc.dataFormat = OSSwapHostToBigInt32( 'text' );
CMTextFormatDescriptionCreateFromBigEndianTextDescriptionData( NULL,
(const uint8_t*)&textDesc, sizeof(textDesc), NULL, kCMMediaType_Text,
&textFmt );
CMSampleTimingInfo timing =
{
CMTimeMakeWithSeconds( endTime - startTime, timeScale ), // duration
CMTimeMakeWithSeconds( startTime, timeScale ),
kCMTimeInvalid
};
CMSampleBufferRef textSample = NULL;
CMPSampleBufferCreateWithText( NULL, (CFStringRef)theTitle, true, NULL, NULL,
textFmt, &timing, &textSample );
[textWriterInput appendSampleBuffer: textSample];
函数CMPSampleBufferCreateWithText
取自开源CoreMediaPlus。