swift: как удалить часть аудио? - PullRequest
0 голосов
/ 26 декабря 2018

Я создаю простой инструмент для редактирования аудио, чтобы обрезать и удалить из аудио.Я реализовал функцию обрезки, и она работает нормально.Однако я искал и пытался реализовать функцию удаления, и вот мой код:

func deleteExportAsset(_ asset: AVAsset, fileName: String, completeAudioTime: CGFloat) -> URL {
    print("\(#function)")

    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let trimmedSoundFileURL = documentsDirectory.appendingPathComponent(fileName)
    print("saving to \(trimmedSoundFileURL.absoluteString)")

    if FileManager.default.fileExists(atPath: trimmedSoundFileURL.absoluteString) {
        print("sound exists, removing \(trimmedSoundFileURL.absoluteString)")
        do {
            if try trimmedSoundFileURL.checkResourceIsReachable() {
                print("is reachable")
            }

            try FileManager.default.removeItem(atPath: trimmedSoundFileURL.absoluteString)
        } catch {
            print("could not remove \(trimmedSoundFileURL)")
            print(error.localizedDescription)
        }

    }

    print("creating export session for \(asset)")

    if let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) {
        exporter.outputFileType = AVFileType.m4a
        exporter.outputURL = trimmedSoundFileURL

        let timeRange1 = CMTimeRangeFromTimeToTime(CMTime(seconds: 0, preferredTimescale: 100), CMTime(seconds: endTimeOfRange1, preferredTimescale: 100))
        let timeRange2 = CMTimeRangeFromTimeToTime(CMTime(seconds: startTimeOfRange2)), preferredTimescale: 100), CMTime(seconds: Double(completeAudioTime), preferredTimescale: 100))
        exporter.timeRange = CMTimeRangeGetUnion(timeRange1, timeRange2)

        // do it
        exporter.exportAsynchronously(completionHandler: {
            print("export complete \(exporter.status)")

            switch exporter.status {
            case  AVAssetExportSessionStatus.failed:

                if let e = exporter.error {
                    print("export failed \(e)")
                }


            case AVAssetExportSessionStatus.cancelled:
                print("export cancelled \(String(describing: exporter.error))")
            default:
                print("export complete")
            }
        })
    } else {
        print("cannot create AVAssetExportSession for asset \(asset)")
    }

    return trimmedSoundFileURL
}

, что я делаю здесь, создает 2 диапазона.Range1 от 0 -> time1 и Range2 от time2-> endOfAudio.(Я хочу удалить из time1 -> time2)

тогда я создаю объединение между 2 диапазонами.однако с аудио ничего не происходит.Он сохраняется точно так же, как и до этой функции.

1 Ответ

0 голосов
/ 28 декабря 2018

CMTimeRangeGetUnion возвращает еще один CMTimeRange, который является просто (началом) времени и продолжительностью.Так что нет ничего, что могло бы удержать два временных диапазона, необходимые для того, чтобы делать то, что вы ожидаете.Кроме того, AVAssetExportSession не имеет API, который берет список временных диапазонов для экспорта.

Но есть способ сделать это.Идея состоит в том, чтобы создать редактируемую копию актива, удалить временной диапазон, а затем экспортировать редактируемую копию.AVMutableComposition делает это:

// assuming 'asset', 'endTimeOfRange1' and 'startTimeOfRange2' from the question:

// create empty mutable composition
let composition: AVMutableComposition = AVMutableComposition()
// copy all of original asset into the mutable composition, effectively creating an editable copy
try composition.insertTimeRange( CMTimeRangeMake( kCMTimeZero, asset.duration), of: asset, at: kCMTimeZero)

// now edit as required, e.g. delete a time range
let startTime = CMTime(seconds: endTimeOfRange1, preferredTimescale: 100)
let endTime = CMTime(seconds: startTimeOfRange2, preferredTimescale: 100)
composition.removeTimeRange( CMTimeRangeFromTimeToTime( startTime, endTime))

// since AVMutableComposition is an AVAsset subclass, it can be exported with AVAssetExportSession (or played with an AVPlayer(Item))
if let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) 
{
    // configure session and exportAsynchronously as above. 
    // You don't have to set the timeRange of the exportSession
}

Обратите внимание, что копирование из ресурса в композицию изменяет только некоторые структуры в памяти, определяя, какие сэмплы идут на временной шкале, но фактически не перемещает сэмплы медиа.вокруг.Это не сделано до экспорта;в результате, редактирование (относительно) быстрое, и вам нужно сохранять исходный файл как минимум до завершения экспорта.

...