Движение недоступно ios 26 живое фотоIOS

Программируем под IOS
Ответить
Anonymous
 Движение недоступно ios 26 живое фото

Сообщение Anonymous »

Я пытаюсь установить Live Photo в качестве живых обоев на iOS. Я сохранил Live Photo в своей библиотеке фотографий, но когда я пытаюсь установить его в качестве обоев, параметр «Эффект Live Photo» становится серым.
Я пробую все сценарии для получения правильного видео; 3 секунды 1 секунда

Я загрузил видео из приложения livewallapaper и использую его, потому что считаю, что мое видео неверно. Все еще не работает.
import Foundation
import UIKit
import Photos
import React
import AVFoundation
import MobileCoreServices

@objc(LivePhotoModule)
class LivePhotoModule: NSObject {

// MARK: - React Native Bridge Method
@objc
func saveLivePhoto(_ videoUri: String, albumName: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {

let fileURL = URL(fileURLWithPath: videoUri)
guard FileManager.default.fileExists(atPath: fileURL.path) else {
return reject("E_FILE", "Video dosyası bulunamadı", nil)
}

// İzin İste
PHPhotoLibrary.requestAuthorization { status in
guard status == .authorized || status == .limited else {
return reject("E_PERM", "Galeri izni verilmedi", nil)
}

// İşlemi Başlat
self.generateLivePhoto(from: fileURL) { (pairedImageURL, pairedVideoURL) in
guard let imageURL = pairedImageURL, let videoURL = pairedVideoURL else {
return reject("E_GEN", "Live Photo oluşturulamadı", nil)
}

// Galeriye Kaydet
self.saveToLibrary(imageURL: imageURL, videoURL: videoURL, albumName: albumName, resolve: resolve, reject: reject)
}
}
}

// MARK: - Generation Logic (Based on GitHub Reference)
private func generateLivePhoto(from videoURL: URL, completion: @escaping (URL?, URL?) -> Void) {
let assetIdentifier = UUID().uuidString
let cacheDirectory = FileManager.default.temporaryDirectory

// 1. Videodan Kapak Resmi Üret (Tam ortasından - 0.5)
guard let keyPhotoURL = self.generateKeyPhoto(from: videoURL, atPercent: 0.5) else {
print("Kapak resmi üretilemedi")
completion(nil, nil)
return
}

// 2. Resme Metadata Ekle
let finalImageURL = cacheDirectory.appendingPathComponent(assetIdentifier).appendingPathExtension("jpg")
guard let savedImageURL = self.addAssetID(assetIdentifier, toImage: keyPhotoURL, saveTo: finalImageURL) else {
completion(nil, nil)
return
}

// 3. Videoya Metadata ve Still Image Time Ekle
let finalVideoURL = cacheDirectory.appendingPathComponent(assetIdentifier).appendingPathExtension("mov")
self.addAssetID(assetIdentifier, toVideo: videoURL, saveTo: finalVideoURL) { (outputURL) in
completion(savedImageURL, outputURL)
}
}

// MARK: - Image Helpers
private func generateKeyPhoto(from videoURL: URL, atPercent percent: Float) -> URL? {
let asset = AVURLAsset(url: videoURL)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
imageGenerator.requestedTimeToleranceBefore = .zero
imageGenerator.requestedTimeToleranceAfter = .zero

let time = asset.duration
let targetTimeValue = Int64(Float(time.value) * percent)
let targetTime = CMTimeMake(value: targetTimeValue, timescale: time.timescale)

do {
let cgImage = try imageGenerator.copyCGImage(at: targetTime, actualTime: nil)
let image = UIImage(cgImage: cgImage)

let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString).appendingPathExtension("jpg")
if let data = image.jpegData(compressionQuality: 1.0) {
try data.write(to: tempURL)
return tempURL
}
} catch {
print("Frame yakalama hatası: \(error)")
}
return nil
}

private func addAssetID(_ assetIdentifier: String, toImage imageURL: URL, saveTo destinationURL: URL) -> URL? {
guard let imageDestination = CGImageDestinationCreateWithURL(destinationURL as CFURL, kUTTypeJPEG, 1, nil),
let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, nil),
var imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [AnyHashable : Any] else { return nil }

let makerNote = ["17": assetIdentifier]
imageProperties[kCGImagePropertyMakerAppleDictionary] = makerNote

CGImageDestinationAddImageFromSource(imageDestination, imageSource, 0, imageProperties as CFDictionary)
CGImageDestinationFinalize(imageDestination)
return destinationURL
}

// MARK: - Video Helpers (The Complex Part)
private func addAssetID(_ assetIdentifier: String, toVideo videoURL: URL, saveTo destinationURL: URL, completion: @escaping (URL?) -> Void) {

let videoAsset = AVURLAsset(url: videoURL)
guard let videoTrack = videoAsset.tracks(withMediaType: .video).first else { return completion(nil) }

do {
let assetWriter = try AVAssetWriter(outputURL: destinationURL, fileType: .mov)
let videoReader = try AVAssetReader(asset: videoAsset)

// Reader Output
let readerOutputSettings = [kCVPixelBufferPixelFormatTypeKey as String: NSNumber(value: kCVPixelFormatType_32BGRA)]
let videoReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: readerOutputSettings)
videoReader.add(videoReaderOutput)

// Writer Input
let writerOutputSettings: [String: Any] = [
AVVideoCodecKey: AVVideoCodecType.h264,
AVVideoWidthKey: videoTrack.naturalSize.width,
AVVideoHeightKey: videoTrack.naturalSize.height,
]
let videoWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: writerOutputSettings)
videoWriterInput.transform = videoTrack.preferredTransform
videoWriterInput.expectsMediaDataInRealTime = true
assetWriter.add(videoWriterInput)

// Metadata: Asset ID
let idItem = AVMutableMetadataItem()
idItem.key = "com.apple.quicktime.content.identifier" as (NSCopying & NSObjectProtocol)
idItem.keySpace = AVMetadataKeySpace.quickTimeMetadata
idItem.value = assetIdentifier as (NSCopying & NSObjectProtocol)
idItem.dataType = "com.apple.metadata.datatype.UTF-8"
assetWriter.metadata = [idItem]

// Metadata: Still Image Time (KRİTİK KISIM)
let spec: NSDictionary = [
kCMMetadataFormatDescriptionMetadataSpecificationKey_Identifier as NSString: "mdta/com.apple.quicktime.still-image-time",
kCMMetadataFormatDescriptionMetadataSpecificationKey_DataType as NSString: "com.apple.metadata.datatype.int8"
]
var desc: CMFormatDescription? = nil
CMMetadataFormatDescriptionCreateWithMetadataSpecifications(allocator: kCFAllocatorDefault, metadataType: kCMMetadataFormatType_Boxed, metadataSpecifications: [spec] as CFArray, formatDescriptionOut: &desc)

let metaInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: desc)
let adaptor = AVAssetWriterInputMetadataAdaptor(assetWriterInput: metaInput)
assetWriter.add(metaInput)

// Start
assetWriter.startWriting()
videoReader.startReading()
assetWriter.startSession(atSourceTime: .zero)

// Still Image Time Verisini Yaz
let stillTimePercent: Float = 0.5
let duration = videoAsset.duration
let frameCount = Int(CMTimeGetSeconds(duration) * Float64(videoTrack.nominalFrameRate))
let frameDuration = Int64(Float(duration.value) / Float(frameCount))
let targetTimeValue = Int64(Float(duration.value) * stillTimePercent)
let stillTime = CMTimeMake(value: targetTimeValue, timescale: duration.timescale)
let stillTimeRange = CMTimeRangeMake(start: stillTime, duration: CMTimeMake(value: frameDuration, timescale: duration.timescale))

let stillItem = AVMutableMetadataItem()
stillItem.key = "com.apple.quicktime.still-image-time" as (NSCopying & NSObjectProtocol)
stillItem.keySpace = AVMetadataKeySpace.quickTimeMetadata
stillItem.value = 0 as (NSCopying & NSObjectProtocol)
stillItem.dataType = "com.apple.metadata.datatype.int8"

let timedGroup = AVTimedMetadataGroup(items: [stillItem], timeRange: stillTimeRange)
adaptor.append(timedGroup)

// Video Yazma Döngüsü
let queue = DispatchQueue(label: "rwQueue")
videoWriterInput.requestMediaDataWhenReady(on: queue) {
while videoWriterInput.isReadyForMoreMediaData {
if let buffer = videoReaderOutput.copyNextSampleBuffer() {
videoWriterInput.append(buffer)
} else {
videoWriterInput.markAsFinished()
metaInput.markAsFinished()

assetWriter.finishWriting {
DispatchQueue.main.async {
if assetWriter.status == .completed {
completion(destinationURL)
} else {
print("Writer error: \(String(describing: assetWriter.error))")
completion(nil)
}
}
}
videoReader.cancelReading()
break
}
}
}

} catch {
print("Setup hatası: \(error)")
completion(nil)
}
}

// MARK: - Save to Library
private func saveToLibrary(imageURL: URL, videoURL: URL, albumName: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
PHPhotoLibrary.shared().performChanges({
let req = PHAssetCreationRequest.forAsset()
let opts = PHAssetResourceCreationOptions()
opts.shouldMoveFile = true

req.addResource(with: .photo, fileURL: imageURL, options: opts)
req.addResource(with: .pairedVideo, fileURL: videoURL, options: opts)
}) { success, error in
if success {
resolve("Live Photo Saved!")
} else {
reject("E_SAVE", error?.localizedDescription ?? "Bilinmeyen hata", nil)
}
}
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... live-photo
Ответить

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

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

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

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

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