Как добавить динамический таймер поверх сохраненного видеоIOS

Программируем под IOS
Ответить
Anonymous
 Как добавить динамический таймер поверх сохраненного видео

Сообщение Anonymous »

У меня есть код, в котором я добавляю метку таймера в качестве подпросмотра в своем представлении, но эта метка таймера, очевидно, остается только для просмотра, а не в видео, которое записывается и сохраняется. Я пробовал несколько вещей, но все было зря, есть ли у кого-нибудь идеи, как это можно сделать?

Код: Выделить всё

class ViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {
let captureSession = AVCaptureSession()
let videoOutput = AVCaptureMovieFileOutput()
var previewLayer: AVCaptureVideoPreviewLayer!
var timer: Timer?
var startTime: TimeInterval = 0
var isRecording = false
var recordButton: UIButton!
var timerLabel: UILabel!
let player = AVQueuePlayer()

override func viewDidLoad() {
super.viewDidLoad()
checkCameraAuthorization()
checkPhotoLibraryAuthorization()
checkMicrophoneAuthoization()

setupCamera()
setupUI()

// Set up audio session for volume control
do {
try AVAudioSession.sharedInstance().setCategory(.playback)
} catch {
print("Error setting up audio session: \(error.localizedDescription)")
}
}

func setupCamera() {
// Setup capture session
captureSession.sessionPreset = .high

// Add input device
guard let camera = AVCaptureDevice.default(for: .video),
let input = try? AVCaptureDeviceInput(device: camera) else { return }
captureSession.addInput(input)

// Add audio input device
guard let microphone = AVCaptureDevice.default(for: .audio),
let audioInput = try? AVCaptureDeviceInput(device: microphone) else {
print("Failed to create audio input.")
return
}
captureSession.addInput(audioInput)

// Add output
captureSession.addOutput(videoOutput)

// Setup preview layer
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.videoGravity = .resizeAspectFill
previewLayer.frame = view.bounds
view.layer.addSublayer(previewLayer)

// Start the session
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
self?.captureSession.startRunning()
}
}

func setupUI() {
// Record button
recordButton = UIButton(type: .custom)
recordButton.frame = CGRect(x: (view.bounds.width - 60) / 2, y: view.bounds.height - 100, width: 60, height: 60)
recordButton.backgroundColor = .white
recordButton.layer.cornerRadius = 30
recordButton.addTarget(self, action: #selector(toggleRecording), for: .touchUpInside)
view.addSubview(recordButton)

// Timer label
timerLabel = UILabel()
timerLabel.frame = CGRect(x: 0, y: 100, width: view.bounds.width, height: 20)
timerLabel.textAlignment = .center
timerLabel.font = UIFont.boldSystemFont(ofSize: 14)
timerLabel.textColor = .white
view.addSubview(timerLabel)
}

@objc func toggleRecording() {
if !isRecording {
// Start recording
startRecording()
} else {
// Stop recording
stopRecording()
}

// Toggle recording state
isRecording = !isRecording
}

func startRecording() {
// Start recording
let timestamp = Date().timeIntervalSince1970
let filename = "video_\(Int(timestamp)).mov"
let outputPath = NSTemporaryDirectory() + filename
let outputURL = URL(fileURLWithPath: outputPath)

if videoOutput.isRecording {
print("Already recording.")
return
}
let dispatchGroup = DispatchGroup()

dispatchGroup.enter() // Enter the dispatch group before starting the recording

// Start recording
DispatchQueue.global().async {
self.videoOutput.startRecording(to: outputURL, recordingDelegate: self)
print("Video is recording")
dispatchGroup.leave() // Leave the dispatch group after starting the recording
}

// Play custom sound
playCustomSound()

// Start timer
startTime = Date().timeIntervalSince1970
timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector:  #selector(updateElapsedTime), userInfo: nil, repeats: true)

// Update button color
recordButton.backgroundColor = .red

// Wait for all tasks to finish
dispatchGroup.notify(queue: .main) {
// All tasks are finished
}

}

func stopRecording() {
// Get output URL before stopping the recording
// let outputURL = videoOutput.outputFileURL

// Stop recording
videoOutput.stopRecording()

print("Recording has been stopped.")

// Stop timer
timer?.invalidate()

// Update button color
recordButton.backgroundColor = .white

}

func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputFileURL)
}) { _, error in
if let error = error {
print(error)
}
}
}

func playCustomSound() {
DispatchQueue.global(qos: .background).async { [weak self] in
guard let url = Bundle.main.url(forResource: "startsound", withExtension: "m4a") else {
print("Sound file not found.")
return
}
do {
let item = AVPlayerItem(url: url)
self?.player.removeAllItems()
self?.player.insert(item, after: nil)
self?.player.play()
print("Audio playback started.")
}
}
}

@objc func updateElapsedTime() {
let elapsedTime = Date().timeIntervalSince1970 - startTime

let milliseconds = Int(elapsedTime * 1000) % 1000
let seconds = Int(elapsedTime) % 60
let minutes = (Int(elapsedTime) / 60) % 60

let formattedTime = String(format: "%02d:%02d.%03d", minutes, seconds, milliseconds)
timerLabel.font = UIFont.boldSystemFont(ofSize: 30)
timerLabel.text = "\(formattedTime)"
}

func checkPhotoLibraryAuthorization() {
let status = PHPhotoLibrary.authorizationStatus()
switch status {
case .authorized:
// User has authorized access to the photo library.
print("Photo library access authorized.")
case .notDetermined:
// Request photo library access.
PHPhotoLibrary.requestAuthorization { status in
if status == .authorized {
print("Photo library access granted.")
} else {
print("Photo library access denied.")
}
}
case .denied, .restricted:
// Photo library access is denied or restricted.
print("Photo library access denied or restricted.")
case .limited: // Handle the .limited case
print("Photo library access limited.")
@unknown default:
print("Unknown authorization status.")
}
}

func checkCameraAuthorization() {
let status = AVCaptureDevice.authorizationStatus(for: .video)
switch status {
case .authorized:
// User has authorized access to the camera.
print("Camera access authorized.")
case .notDetermined:
// Request camera access.
AVCaptureDevice.requestAccess(for: .video) { granted in
if granted {
print("Camera access granted.")
} else {
print("Camera access denied.")
}
}
case .denied, .restricted:
// Camera access is denied or restricted.
print("Camera access denied or restricted.")
@unknown default:
print("Unknown authorization status.")
}
}

func checkMicrophoneAuthoization() {
let status = AVCaptureDevice.authorizationStatus(for:  .audio)
switch status {
case .authorized:
// User has authorized access to the microphone.
print("Microphone access authorized.")
case .notDetermined:
// Request microphone access.
AVCaptureDevice.requestAccess(for: .audio) { granted in
if granted {
print("Microphone access granted.")
} else {
print("Microphone access denied.")
}
}
case .denied, .restricted:
// Microphone access is denied or restricted.
print("Microphone access denied or restricted.")
@unknown default:
print("Unknown authorization status.")
}
}
}

Я уже пробовал это сделать, добавив в фреймы, но это вообще не работает.


Подробнее здесь: https://stackoverflow.com/questions/784 ... aved-video
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»