Запись тегов ID3 ​​через AVMetaDataItem

Я записываю теги ID3 в файл, используя AVMetaDataItem

var soundFileMetadata = [AVMetadataItem]()

soundFileMetadata.append(createMetadata(AVMetadataiTunesMetadataKeyArtist, "MyArtist")!)
soundFileMetadata.append(createMetadata(AVMetadataiTunesMetadataKeySongName, "MySong")!)
soundFileMetadata.append(createMetadata(AVMetadataiTunesMetadataKeyAlbum, "MyAlbum")!)
soundFileMetadata.append(createMetadata(AVMetadataiTunesMetadataKeyUserGenre, "MyGenre")!)
soundFileMetadata.append(createMetadata(AVMetadataiTunesMetadataKeyComposer, "MyComposer")!)

Вот удобный метод createMetadata:

func createMetadata(tagKey: String, _ tagValue: AnyObject?,
                    keySpace:String = AVMetadataKeySpaceiTunes) -> AVMutableMetadataItem? {
    if let tagValue = tagValue {       
        let tag = AVMutableMetadataItem()
        tag.keySpace = keySpace
        tag.key = tagKey
        tag.value = (tagValue as? String) ?? (tagValue as? Int)
        return tag
    }
    return nil
}

Затем я попытался написать также тег года, но безуспешно:

let comps = NSDateComponents()
comps.year = 2010;

let yearTag = AVMutableMetadataItem()
yearTag.keySpace = AVMetadataKeySpaceID3
yearTag.key = AVMetadataID3MetadataKeyYear
yearTag.value = NSCalendar.currentCalendar().dateFromComponents(comps)

soundFileMetadata.append(yearTag)

В этом случае я получаю эту ошибку:

FigMetadataCreateConverter signalled err=-12482 (kFigMetadataConverterError_UnsupportedFormat) (Unsupported format conversion) at /SourceCache/CoreMedia/CoreMedia-1562.238/Prototypes/Metadata/Converters/FigMetadataConverterCommon.c line 118

Обратите внимание, что это простая ошибка, напечатанная в консоли, а не исключение!

Также запись его как String, как Int или даже Float приводит меня к той же ошибке. То же самое касается счетчика дорожек/дисков, тегов номеров дорожек/дисков.

Первый вопрос: как их написать?

У меня также есть еще один вопрос.

В настоящее время у меня есть AVAudioRecorder, я не нашел способа записать теги непосредственно в выходной файл рекордера, поэтому я фиксирую файл рекордера, открываю его с помощью AVURLAsset и реэкспортирую с помощью AVAssetExportSession:

self.recorder.stop()

let urlAsset = AVURLAsset(URL: srcSoundFileURL)
let assetExportSession: AVAssetExportSession! = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetPassthrough)

assetExportSession.outputFileType = AVFileTypeAppleM4A
assetExportSession.outputURL = tmpSoundFileURL
assetExportSession.metadata = soundFileMetadata

assetExportSession.exportAsynchronouslyWithCompletionHandler({ 
         ....

})

Второй вопрос: есть ли способ избежать этого двойного действия?


person Teejay    schedule 07.11.2015    source источник
comment
Ваш код похоже, работает для меня на игровой площадке Xcode 7.1+.   -  person Eric Aya    schedule 09.11.2015
comment
@ЭрикД. Уверены ли вы? Обратите внимание, что у меня он не вылетает, но и не записывает тег в файл! Вы проверяли файл после его записи?   -  person Teejay    schedule 09.11.2015
comment
Единственное, в чем я уверен, так это в том, что вы показали фрагмент кода, в котором говорится, что он генерирует ошибку, но этот код работал для меня в Playground, поэтому я хотел поделиться им на всякий случай. :) Теперь из вашего комментария я понимаю, что это не то, что вы на самом деле имели в виду, поэтому вы, вероятно, хотите отредактировать свой вопрос, чтобы отразить это более четко.   -  person Eric Aya    schedule 09.11.2015
comment
@ЭрикД. Да, я должен, и я буду. Дело в том, что я не получаю исключение, просто сообщение в консоли (и тег не пишется). Не могли бы вы проверить, был ли файл записан с тегом в вашем случае?   -  person Teejay    schedule 09.11.2015
comment
Я не тестировал реальный файл, я просто проверил правильность вашего фрагмента кода, потому что я думал, что сообщение об ошибке, которое вы показываете, было из Xcode. Теперь я понял, что это не ошибка времени компиляции, а ошибка времени выполнения. Я буду исследовать дальше, когда найду немного времени.   -  person Eric Aya    schedule 09.11.2015
comment
@ЭрикД. Спасибо, жду от вас вестей. Исправил вопрос.   -  person Teejay    schedule 10.11.2015
comment
Вы правы, я удалил свой ответ, год тоже не был помечен должным образом, я только что проверил. Я думал, что все в порядке при печати метатегов из консоли Xcode, я, должно быть, неправильно понял. Извините за фальстарт. :/   -  person Eric Aya    schedule 10.11.2015
comment
Опубликовал решение для тега года.   -  person Eric Aya    schedule 10.11.2015


Ответы (1)


Мне удалось добавить тег года с вашим кодом с несколькими изменениями:

let yearTag = AVMutableMetadataItem()
yearTag.keySpace = AVMetadataKeySpaceiTunes
yearTag.key = AVMetadataiTunesMetadataKeyReleaseDate
yearTag.value = "2123"

Я не мог заставить его работать с ключами ID3, поэтому я подумал, что проблема может быть в этом, и действительно, он работает с этими ключами iTunes. Кроме того, значение должно быть строкой (или NSString), а не объектом даты.

введите здесь описание изображения

person Eric Aya    schedule 10.11.2015
comment
Для меня это было бы приемлемо, даже с iTunes KeySpace! - person Teejay; 10.11.2015
comment
Просто для справки: с ID3 KeySpace ничего не работает среди строк, целых чисел, чисел с плавающей запятой или дат. - person Teejay; 10.11.2015
comment
Извините, но я не понимаю ваш первый комментарий, пожалуйста, объясните. Вы имеете в виду, что уже сделали это, но вы просите что-то еще? Я потерялся. :п - person Eric Aya; 10.11.2015
comment
Я имел в виду, что это решение приемлемо для меня, даже если оно использует другой KeySpace (KeySpaceiTunes вместо KeySpaceID3). Это хорошо для меня! - person Teejay; 10.11.2015
comment
Ох, хорошо. Похоже, я немного тормознул сразу после обеда... ;) У меня пока нет доказательств, но я думаю, что вы все равно не сможете использовать ID3 с файлами M4A. Я просто нахожу странным, что AVAssetExportSession терпит неудачу вместо того, чтобы генерировать правильное сообщение об ошибке или исключение. - person Eric Aya; 10.11.2015
comment
Честно говоря, я не помню, почему я раньше решил использовать другой KeySpace только для тега года :) - person Teejay; 10.11.2015
comment
Знаете ли вы о каком-либо решении второго вопроса? а может его и нет... - person Teejay; 10.11.2015
comment
По моему опыту, AVAssetExportSession — правильный способ делать то, что вы делаете. Я думаю, вы могли бы использовать AVAssetWriter, но в вашем случае я не понимаю, почему было бы необходимо добавлять сложность для того же результата. - person Eric Aya; 10.11.2015
comment
Я спросил об этом, потому что заметил, что второй файл - с тегами - немного меньше, около 100 КБ, чем тот, с которого начался AVAssetExportSession (то есть тот, который был передан в AVURLAsset). Поэтому я задавался вопросом/беспокоился о каком-то нежелательном сжатии, но я явно не могу это подтвердить. - person Teejay; 10.11.2015
comment
Я полагаю, что разница заключается в инкапсуляции, а не в кодировании. Пока мы используем AVAssetExportPresetPassthrough, мы в безопасности. - person Eric Aya; 10.11.2015
comment
Да, я это себе представлял, хотя мне все еще кажется странным, что файл, сгенерированный AVAssetExportSession, меньше, чем файл, сгенерированный AVAudioRecorder. Оба класса от Apple :) - person Teejay; 10.11.2015
comment
Я попробую BeyondCompare два файла. - person Teejay; 10.11.2015