TL;DR - ИЗМЕНИТЬ EDIT
Я создаю тестовое приложение в Swift, где я хочу сшить несколько видео вместе из каталога документов приложений, используя AVMutableComposition
.
У меня был успех в этом, в какой-то степени, все мои видео сшиты вместе, и все показывает правильный размер и пейзаж.
Моя проблема заключается в том, что все видео отображаются в ориентации последнего видео в компиляции.
Я знаю, что для исправления этого мне нужно будет добавить инструкции слоя для каждого добавляемого трека, однако я не могу понять, что это правильно, и ответы, которые я нашел, вся компиляция, похоже, выходит в портретной ориентации с пейзажным видео просто масштабируется, чтобы вписаться в портретный вид, поэтому, когда я поворачиваю свой телефон на боку, чтобы просмотреть пейзажные видеоролики, они все еще малы, поскольку они масштабируются до размера портрета.
Это не тот результат, который я ищу, я хочу ожидаемую функциональность, т.е. если видеоролик является ландшафтом, он показывает масштабирование в портретном режиме, но если телефон повернут, я хочу, чтобы ландшафтное видео заполняло экран (как это было бы при простом просмотре пейзажного видео на фотографиях) и то же самое для портрета, так что при просмотре в портрете он отображается в полноэкранном режиме и, когда он поворачивается в сторону, видео масштабируется до размера ландшафта (например, при просмотре портретного видео на фотографиях).
В общем, желаемый результат, который я хочу, заключается в том, что при просмотре компиляции с пейзажными и портретными видеороликами я могу просмотреть всю компиляцию с моим телефоном на боку, а пейзажные видео - в полноэкранном режиме, а портрет масштабируется или при просмотре то же видео на портрете, что портретные видеоролики - полный экран, а пейзажные видео масштабируются до размера.
Со всеми ответами я обнаружил, что это не так, и все они, казалось, имели очень неожиданное поведение при импорте видео с фотографий, чтобы добавить к компиляции, и такое же случайное поведение при добавлении видео, снятых с лицевой стороны камера (ясно, что мои текущие видеоролики, импортированные из библиотеки, и видеоролики "selfie" появляются с правильным размером без этих проблем).
Я ищу способ повернуть/масштабировать эти видео, чтобы они всегда показывались в правильной ориентации и масштабах, в зависимости от того, какой путь вокруг пользователя держит их телефон.
EDIT: теперь я знаю, что у меня не может быть как пейзажной, так и портретной ориентации в одном видео, поэтому ожидаемый результат, который я ищу, будет состоять в том, чтобы иметь окончательное видео в пейзаже ориентации. я выяснил, как сделать все ориентации и масштабы, чтобы получить все одинаково, но мой вывод - портретное видео, если кто-то может помочь мне изменить это, поэтому мой результат - это пейзаж, который будет оценен.
Ниже приведена моя функция для получения инструкции для каждого видео:
func videoTransformForTrack(asset: AVAsset) -> CGAffineTransform
{
var return_value:CGAffineTransform?
let assetTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0]
let transform = assetTrack.preferredTransform
let assetInfo = orientationFromTransform(transform)
var scaleToFitRatio = UIScreen.mainScreen().bounds.width / assetTrack.naturalSize.width
if assetInfo.isPortrait
{
scaleToFitRatio = UIScreen.mainScreen().bounds.width / assetTrack.naturalSize.height
let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio)
return_value = CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor)
}
else
{
let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio)
var concat = CGAffineTransformConcat(CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor), CGAffineTransformMakeTranslation(0, UIScreen.mainScreen().bounds.width / 2))
if assetInfo.orientation == .Down
{
let fixUpsideDown = CGAffineTransformMakeRotation(CGFloat(M_PI))
let windowBounds = UIScreen.mainScreen().bounds
let yFix = assetTrack.naturalSize.height + windowBounds.height
let centerFix = CGAffineTransformMakeTranslation(assetTrack.naturalSize.width, yFix)
concat = CGAffineTransformConcat(CGAffineTransformConcat(fixUpsideDown, centerFix), scaleFactor)
}
return_value = concat
}
return return_value!
}
И экспортер:
// Create AVMutableComposition to contain all AVMutableComposition tracks
let mix_composition = AVMutableComposition()
var total_time = kCMTimeZero
// Loop over videos and create tracks, keep incrementing total duration
let video_track = mix_composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
var instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: video_track)
for video in videos
{
let shortened_duration = CMTimeSubtract(video.duration, CMTimeMake(1,10));
let videoAssetTrack = video.tracksWithMediaType(AVMediaTypeVideo)[0]
do
{
try video_track.insertTimeRange(CMTimeRangeMake(kCMTimeZero, shortened_duration),
ofTrack: videoAssetTrack ,
atTime: total_time)
video_track.preferredTransform = videoAssetTrack.preferredTransform
}
catch _
{
}
instruction.setTransform(videoTransformForTrack(video), atTime: total_time)
// Add video duration to total time
total_time = CMTimeAdd(total_time, shortened_duration)
}
// Create main instrcution for video composition
let main_instruction = AVMutableVideoCompositionInstruction()
main_instruction.timeRange = CMTimeRangeMake(kCMTimeZero, total_time)
main_instruction.layerInstructions = [instruction]
main_composition.instructions = [main_instruction]
main_composition.frameDuration = CMTimeMake(1, 30)
main_composition.renderSize = CGSize(width: UIScreen.mainScreen().bounds.width, height: UIScreen.mainScreen().bounds.height)
let exporter = AVAssetExportSession(asset: mix_composition, presetName: AVAssetExportPreset640x480)
exporter!.outputURL = final_url
exporter!.outputFileType = AVFileTypeMPEG4
exporter!.shouldOptimizeForNetworkUse = true
exporter!.videoComposition = main_composition
// 6 - Perform the Export
exporter!.exportAsynchronouslyWithCompletionHandler()
{
// Assign return values based on success of export
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.exportDidFinish(exporter!)
})
}
Извините за длинное объяснение, я просто хотел удостовериться, что был очень ясен с тем, что я просил, потому что другие ответы не сработали для меня.