Adding GPS location EXIF tag to video recordings with AVAssetWriter

27 Views Asked by At

I'm trying to record a video from the Camera using AVAssetWriter.

The video recording works perfectly fine, but I cannot figure out how to add GPS location EXIF tags to the video files (mp4/mov).

I tried this:

func initMetadataWriter() throws {
  let locationSpec = [
    kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier: AVMetadataIdentifier.quickTimeMetadataLocationISO6709,
    kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType: kCMMetadataDataType_QuickTimeMetadataLocation_ISO6709,
  ] as [String: Any]
  let metadataSpecifications: NSArray = [locationSpec]
  var metadataFormatDescription: CMFormatDescription?
  CMMetadataFormatDescriptionCreateWithMetadataSpecifications(allocator: kCFAllocatorDefault,
                                                              metadataType: kCMMetadataFormatType_Boxed,
                                                              metadataSpecifications: metadataSpecifications,
                                                              formatDescriptionOut: &metadataFormatDescription)

  let metadataInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: metadataFormatDescription)
  guard assetWriter.canAdd(metadataInput) else {
    throw CameraError.location(.cannotWriteLocationToVideo)
  }
  assetWriter.add(metadataInput)
  metadataWriter = AVAssetWriterInputMetadataAdaptor(assetWriterInput: metadataInput)
}

private func createLocationMetadataItem(location: CLLocation) -> AVMetadataItem {
  let metadataItem = AVMutableMetadataItem()
  metadataItem.key = AVMetadataKey.commonKeyLocation as (NSCopying & NSObjectProtocol)?
  metadataItem.keySpace = AVMetadataKeySpace.common
  metadataItem.value = String(format: "%+.6f%+.6f/", location.coordinate.latitude, location.coordinate.longitude) as (NSCopying & NSObjectProtocol)?
  metadataItem.identifier = AVMetadataIdentifier.quickTimeMetadataLocationISO6709
  return metadataItem
}

/**
 Writes a Location tag to the video
 */
func writeLocationTag(location: CLLocation) throws {
  guard let metadataWriter else {
    throw CameraError.location(.cannotWriteLocationToVideo)
  }

  let metadataItem = createLocationMetadataItem(location: location)
  let metadataGroup = AVTimedMetadataGroup(items: [metadataItem],
                                           timeRange: CMTimeRange(start: CMTime.zero, end: CMTime.positiveInfinity))
  metadataWriter.append(metadataGroup)
}

Then this will be called like this:

// 1. Initialize all AVAssetWriters and adapters
let recordingSession = RecordingSession(...)
try recordingSession.initVideoWriter()
try recordingSession.initAudioWriter()
try recordingSession.initMetadataWriter() 

// 2. Start writing
recordingSession.start()

// 3. While video/audio frames are being written, also write the GPS Location metadata:
let location = locationManager.location!
try recordingSession.writeLocationTag(location: location)

But this crashes with the following error:

-[AVAssetWriterInputMetadataAdaptor appendTimedMetadataGroup:] Cannot write to file timed metadata group 0x283ebd150: No entry in format description 0x281f3ff70 for metadata item 0x283cece80 with identifier mdta/com.apple.quicktime.location.ISO6709, data type com.apple.metadata.datatype.UTF-8 and extended language tag (null).  If you created this format description using -[AVTimedMetadataGroup copyFormatDescription], make sure the instance of AVTimedMetadataGroup used to create the format description contains a representative sample of metadata items which includes an item with the same combination of identifier, dataType, and extended language tag as this one

Has anyone successfully written GPS location tags to video files with AVAssetWriter before?

My AVAssetWriters support both .mov and .mp4 (h264 and h265/hevc) videos.

Thanks!

0

There are 0 best solutions below