17 changed files with 360 additions and 86 deletions
-
4kplayer.xcodeproj/project.pbxproj
-
8kplayer/AppDelegate.swift
-
39kplayer/core/ItemModel.swift
-
31kplayer/core/MediaItem.swift
-
1kplayer/core/MediaModel.swift
-
78kplayer/core/NetworkManager.swift
-
2kplayer/core/ThumbnailCache.swift
-
9kplayer/detail/DetailViewController.swift
-
37kplayer/detail/VideoController.swift
-
49kplayer/master/MasterViewController.swift
-
59kplayer/master/NetworkDelegate.swift
-
16kplayer/photo/PhotoController.swift
-
2kplayer/readme.md
-
27kplayer/util/FileHelper.swift
-
4kplayer/util/UploadOperation.swift
-
64kplayer/util/VideoHelper.swift
-
16kplayer/util/stringutil.swift
@ -0,0 +1,64 @@ |
|||||
|
// |
||||
|
// Created by Marco Schmickler on 30.04.21. |
||||
|
// Copyright (c) 2021 Marco Schmickler. All rights reserved. |
||||
|
// |
||||
|
|
||||
|
import Foundation |
||||
|
import AVFoundation |
||||
|
|
||||
|
class VideoHelper { |
||||
|
public static func export(item: AVPlayerItem, clipStart: Double, clipDuration: Double, file: URL, completion: @escaping (URL?) -> ()) { |
||||
|
guard item.asset.isExportable else { |
||||
|
completion(nil) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
let composition = AVMutableComposition() |
||||
|
let compositionVideoTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid)) |
||||
|
let compositionAudioTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: CMPersistentTrackID(kCMPersistentTrackID_Invalid)) |
||||
|
|
||||
|
let sourceVideoTrack = item.asset.tracks(withMediaType: AVMediaType.video).first! |
||||
|
let sourceAudioTrack = item.asset.tracks(withMediaType: AVMediaType.audio).first! |
||||
|
let start = CMTime(seconds: clipStart, preferredTimescale: 1); |
||||
|
let dur = CMTime(seconds: clipDuration, preferredTimescale: 100); |
||||
|
do { |
||||
|
|
||||
|
try compositionVideoTrack!.insertTimeRange(CMTimeRangeMake(start: start, duration: dur), of: sourceVideoTrack, at: start) |
||||
|
try compositionAudioTrack!.insertTimeRange(CMTimeRangeMake(start: start, duration: dur), of: sourceAudioTrack, at: start) |
||||
|
} catch(_) { |
||||
|
completion(nil) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
let compatiblePresets = AVAssetExportSession.exportPresets(compatibleWith: composition) |
||||
|
var preset: String = AVAssetExportPresetPassthrough |
||||
|
// if compatiblePresets.contains(AVAssetExportPreset3840x2160) { preset = AVAssetExportPreset3840x2160 } |
||||
|
|
||||
|
guard |
||||
|
let exportSession = AVAssetExportSession(asset: composition, presetName: preset), |
||||
|
exportSession.supportedFileTypes.contains(AVFileType.mp4) else { |
||||
|
completion(nil) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
exportSession.outputURL = file |
||||
|
exportSession.outputFileType = AVFileType.mp4 |
||||
|
let startTime = CMTime(seconds: 0.0, preferredTimescale: 100); |
||||
|
let timeRange = CMTimeRangeMake(start: start, duration: dur) |
||||
|
exportSession.timeRange = timeRange |
||||
|
|
||||
|
print("Write file \(file)") |
||||
|
do { |
||||
|
try FileManager.default.removeItem(at: file) |
||||
|
} catch { |
||||
|
} |
||||
|
exportSession.exportAsynchronously { |
||||
|
print("ready \(exportSession.error)") |
||||
|
// let data = try? Data(contentsOf: tempFileUrl) |
||||
|
// _ = try? FileManager.default.removeItem(at: tempFileUrl) |
||||
|
let r = FileManager.default.fileExists(atPath: file.absoluteString) |
||||
|
print (r) |
||||
|
completion(file) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue