AVAssetWriter & AVTimedMetadataGroup in AVMultiCamPiP

I'm trying to add metadata every second during video capture in the Swift sample App "AVMultiCamPiP". A simple string that changes every second with a write function triggered by a Timer. Can't get it to work, no matter how I arrange it, always ends up with the error "Cannot create a new metadata adaptor with an asset writer input that has already started writing".

This is the setup section:

		        
 // Add a metadata input

let assetWriterMetaDataInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: AVTimedMetadataGroup().copyFormatDescription())

assetWriterMetaDataInput.expectsMediaDataInRealTime = true

assetWriter.add(assetWriterMetaDataInput)

self.assetWriterMetaDataInput = assetWriterMetaDataInput

This is the timed metadata creation which gets triggered every second:

let newNoteMetadataItem = AVMutableMetadataItem()
newNoteMetadataItem.value = "Some string"  as (NSCopying & NSObjectProtocol)?

let metadataItemGroup = AVTimedMetadataGroup.init(items: [newNoteMetadataItem], timeRange: CMTimeRangeMake( start: CMClockGetTime( CMClockGetHostTimeClock() ), duration: CMTime.invalid ))

movieRecorder?.recordMetaData(meta: metadataItemGroup)

This function is supposed to add the metadata to the track:

    func recordMetaData(meta: AVTimedMetadataGroup) {
        guard isRecording,
            let assetWriter = assetWriter,
            assetWriter.status == .writing,
            let input = assetWriterMetaDataInput,
            input.isReadyForMoreMediaData else {
                return
        }

        let metadataAdaptor = AVAssetWriterInputMetadataAdaptor(assetWriterInput: input)
        metadataAdaptor.append(meta)

    }

I have an older code example in objc which works OK, but it uses "AVCaptureMetadataInput appendTimedMetadataGroup" and writes to an identifier called "quickTimeMetadataLocationNote". I'd like to do something similar in the above Swift code ...

All suggestions are appreciated !

Answered by DTS Engineer in 817482022

Hey @JosNL,

It crashes with the message "Cannot create a new metadata adaptor with an asset writer that does not carry a source format hint'" the moment I start appending an AVTimedMetadataGroup.

I see, taking a look at your input initialization code:

let assetWriterMetaDataInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: AVTimedMetadataGroup().copyFormatDescription())

That format description is nil. You should create a CMMetadataFormatDescription that describes the metadata you are going to be appending with your metadata adaptor, and then you should use that format description as the sourceFormatHint.

Best regards,

Greg

Hello @JosNL,

"Cannot create a new metadata adaptor with an asset writer input that has already started writing".

This error is saying that you have already called startWriting() on your asset writer when you try to create the metadata adaptor. Have you verified that this is not the case?

Best regards,

Greg

Hi Greg,

Thanks for taking the time to look at this.

I can't find the proper way to get a continuous writing metadata adaptor going, I am unable to initialise it before startWriting().

If I declare them together with the other AVAssetWriterInputs like this:

 private var assetWriterMetaDataInput: AVAssetWriterInput?
 private var metadataAdaptor: AVAssetWriterInputMetadataAdaptor?

And then try to set them up like this:


 // Add a metadata input

 let assetWriterMetaDataInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: AVTimedMetadataGroup().copyFormatDescription())
 assetWriterMetaDataInput.expectsMediaDataInRealTime = true
 assetWriter.add(assetWriterMetaDataInput)
                
 metadataAdaptor = AVAssetWriterInputMetadataAdaptor(assetWriterInput: assetWriterMetaDataInput)

It crashes with the message "Cannot create a new metadata adaptor with an asset writer that does not carry a source format hint'" the moment I start appending an AVTimedMetadataGroup.

If there are any examples out there I could look at, please let me know!

Thanks!

Accepted Answer

Hey @JosNL,

It crashes with the message "Cannot create a new metadata adaptor with an asset writer that does not carry a source format hint'" the moment I start appending an AVTimedMetadataGroup.

I see, taking a look at your input initialization code:

let assetWriterMetaDataInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: AVTimedMetadataGroup().copyFormatDescription())

That format description is nil. You should create a CMMetadataFormatDescription that describes the metadata you are going to be appending with your metadata adaptor, and then you should use that format description as the sourceFormatHint.

Best regards,

Greg

Many thanks Greg !!

For anyone else looking into this, the CMMetadataFormatDescription is a bit special and perhaps not very Swifty ;) Working example below:


// Add an metadata input
let metaSpec : NSDictionary = [
kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier as NSString:
AVMetadataIdentifier.quickTimeMetadataLocationNote,
kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType as NSString:
kCMMetadataBaseDataType_UTF8]

var metaFormat : CMFormatDescription? = nil

CMMetadataFormatDescriptionCreateWithMetadataSpecifications(allocator: kCFAllocatorDefault, metadataType: kCMMetadataFormatType_Boxed, metadataSpecifications: [metaSpec] as CFArray, formatDescriptionOut: &metaFormat)

let assetWriterMetaDataInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: metaFormat)
assetWriterMetaDataInput.expectsMediaDataInRealTime = true
assetWriter.add(assetWriterMetaDataInput)

Hey @JosNL,

No problem!

CMMetadataFormatDescription is a bit special and perhaps not very Swifty ;)

There is actually an initializer to use provided in the Swift overlay, which you might find to be more ergonomic here :)

var boxedMetadataSpecs: [String: CFPropertyList] = [:]
            boxedMetadataSpecs[kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier as String] = AVMetadataIdentifier.quickTimeMetadataLocationNote as CFPropertyList
            boxedMetadataSpecs[kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType as String] = kCMMetadataBaseDataType_UTF8
            
            let formatDesc = try! CMMetadataFormatDescription(boxedMetadataSpecifications: [boxedMetadataSpecs])

Best regards,

Greg

AVAssetWriter & AVTimedMetadataGroup in AVMultiCamPiP
 
 
Q