Files

195 lines
6.9 KiB
Swift

//
// ResourceEditorViewController.swift
// SimpleVideoEditor
//
// Created by RenZhu Macro on 2020/7/8.
// Copyright © 2020 RenZhu Macro. All rights reserved.
//
import UIKit
import MetalVideoProcess
import AVFoundation
class ResourceItemEditView: UIViewController {
deinit {
}
public weak var resourceItem: ResourceItem?
@IBOutlet weak var timeRangeText: UILabel!
@IBOutlet weak var renderView: MetalVideoProcessRenderView!
@IBOutlet weak var startTimeSlider: UISlider!
@IBOutlet weak var durationSlider: UISlider!
@IBOutlet weak var positionSlider: UISlider!
var player: MetalVideoProcessPlayer?
var editor: MetalVideoEditor?
var assetDuration: CMTime = .zero
@IBOutlet weak var isMuteSwitch: UISwitch!
var isPipItem: Bool = false
var isImageResource: Bool = false
public func loadResourceItem(_ item: ResourceItem, isPipItem: Bool = false) {
self.isPipItem = isPipItem
self.resourceItem = item
self.isMuteSwitch.isOn = item.isMute
if let imageResource = item.resource as? ImageResource {
self.isImageResource = true
//picture
let mtlTexture = imageResource.sourceTexture(at: .zero)!
let texture = Texture(orientation: .landscapeLeft, texture: mtlTexture, timingStyle: .stillImage)
self.renderView.newTextureAvailable(texture, fromSourceIndex: 0, trackID: 0)
} else if let asset = (item.resource as? AVAssetTrackResource)?.asset {
assetDuration = asset.duration
self.editor = try? MetalVideoEditor(videoItems: [item])
guard let playerItem = self.editor?.buildPlayerItem() else {
return
}
self.player = try? MetalVideoProcessPlayer(playerItem: playerItem)
let orientation = orientationForTrack(asset: asset)
let transform = MetalVideoProcessTransformFilter()
switch orientation {
case .portrait:
break
case .landscapeLeft:
transform.rotate = 90.0
break
case .landscapeRight:
transform.rotate = -90.0
break
case .portraitUpsideDown:
transform.rotate = 180.0
break
default:
break
}
self.player?.addTarget(transform, atTargetIndex: nil, trackID: item.trackID, targetTrackId: 0)
transform --> self.renderView
} else {
return //unsupported
}
self.startTimeSlider.minimumValue = 0.0
//min value of a item is 0.1 seconds
self.durationSlider.minimumValue = 0.1
if self.isImageResource {
self.durationSlider.maximumValue = 100.0
assetDuration = CMTime(seconds: 100.0)
} else {
self.durationSlider.maximumValue = Float(assetDuration.seconds)
}
self.startTimeSlider.maximumValue = self.durationSlider.maximumValue - 0.1
self.startTimeSlider.value = Float(item.resource.selectedTimeRange.start.seconds)
self.durationSlider.value = Float(item.resource.selectedTimeRange.duration.seconds)
self.positionSlider.value = Float(item.startTime.seconds)
if self.isPipItem {
self.positionSlider.isEnabled = true
self.positionSlider.maximumValue = 100.0
self.positionSlider.value = Float(item.startTime.seconds)
}
timeRangeText.text = NSString(format: "s:%.2f d:%.2f p:%.2f",
self.startTimeSlider.value,
self.durationSlider.value,
self.positionSlider.value) as String
self.player?.seekTo(time: 0.0)
}
override func viewDidDisappear(_ animated: Bool) {
self.player?.suspend()
self.player?.dispose()
self.player = nil
self.editor = nil
}
@IBAction func positionValueChanged(_ sender: Any) {
self.resourceItem?.startTime = CMTime(seconds: self.positionSlider.value)
timeRangeText.text = NSString(format: "s:%.2f d:%.2f p:%.2f",
self.startTimeSlider.value,
self.durationSlider.value,
self.positionSlider.value) as String
}
@IBAction func startTimeValueChanged(_ sender: Any) {
let totalValue = self.startTimeSlider.value + self.durationSlider.value
if totalValue > Float(self.assetDuration.seconds) {
self.durationSlider.value = Float(self.assetDuration.seconds) - self.startTimeSlider.value
}
resourceItem?.resource.selectedTimeRange = CMTimeRange(start: CMTime(seconds: self.startTimeSlider.value),
duration: CMTime(seconds: self.durationSlider.value))
if self.isPipItem {
self.player?.seekTo(time: Float64(resourceItem?.resource.selectedTimeRange.start.seconds ?? 0.0))
} else {
self.player?.seekTo(time: Float64(self.startTimeSlider.value))
}
timeRangeText.text = NSString(format: "s:%.2f d:%.2f p:%.2f",
self.startTimeSlider.value,
self.durationSlider.value,
self.positionSlider.value) as String
}
@IBAction func DurationValueChanged(_ sender: Any) {
let totalValue = self.startTimeSlider.value + self.durationSlider.value
if totalValue > Float(self.assetDuration.seconds) {
self.startTimeSlider.value = Float(self.assetDuration.seconds) - self.durationSlider.value
}
resourceItem?.resource.selectedTimeRange = CMTimeRange(start: CMTime(seconds: self.startTimeSlider.value),
duration: CMTime(seconds: self.durationSlider.value))
timeRangeText.text = NSString(format: "s:%.2f d:%.2f p:%.2f",
self.startTimeSlider.value,
self.durationSlider.value,
self.positionSlider.value) as String
if self.isImageResource {
//No need to render the image with frameTime
return
}
self.player?.seekTo(time: Float64(self.startTimeSlider.value + self.durationSlider.value))
}
@IBAction func isMuteOn(_ sender: UISwitch) {
self.resourceItem?.isMute = sender.isOn
}
@IBAction func play(_ sender: Any) {
guard let playerItem = self.editor?.buildPlayerItem() else {
return
}
self.player?.updatePlayerItem(playerItem: playerItem)
self.player?.play()
}
@IBAction func pause(_ sender: Any) {
self.player?.pause()
}
}