使用AVFoundation创建视频时添加章节轨道

时间:2017-08-15 22:30:35

标签: macos video avfoundation metadata

我正在从一堆静止图像创建视频(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播放器说结果是"而不是电影"。不确定我做错了什么。

1 个答案:

答案 0 :(得分:1)

我设法使用文本轨道来提供章节。我花了一个Apple开发人员技术支持事件,并被告知这是正确的方法。

设定:

我认为已创建AVAssetWriter,并为其分配了视频轨道的AVAssetWriterInput

这里最棘手的部分是创建文本格式描述。文档说CMTextFormatDescriptionCreateFromBigEndianTextDescriptionDataTextDescription结构视为输入,但忽略了该结构的定义。它位于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