Вращающееся видео с AVMutableVideoCompositionLayerInstruction
Я снимаю видео на iPhone 4 с фронтальной камерой и комбинирую видео с некоторыми другими медиа-активами. Я бы хотел, чтобы это видео было ориентировано на портрет - ориентация по умолчанию для всего видео пейзажа, и в некоторых случаях вам нужно управлять этим вручную.
Я использую AVFoundation и, в частности, AVAssetExportSession с AVMutableVideoComposition. Основываясь на видео WWDC, ясно, что я должен сам "фиксировать" ориентацию, когда я совмещаю видео в новую композицию.
Итак, я создал AVMutableVideoCompositionLayerInstruction, подключенный к моему AVMutableVideoCompositionInstruction, и я использую метод setTransform: atTime: для установки преобразования, предназначенного для поворота видео:
AVMutableVideoCompositionLayerInstruction *passThroughLayer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
CGAffineTransform portraitRotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
[passThroughLayer setTransform:portraitRotationTransform atTime:kCMTimeZero];
Проблема заключается в том, что когда я просматриваю видео, которое экспортируется, на экране не отображается ни одно фактическое содержимое. Если я уменьшу угол поворота на 45 градусов, я вижу часть видео на экране - это почти так, как если бы он не вращался в центральной точке. Я включаю изображения ниже, чтобы сделать это более понятным, о чем я говорю.
Естественный размер видео возвращается как 480x360. Я попытался изменить это на 360x480, и это не влияет на основную проблему.
0 Степень вращения:
![enter image description here]()
45 градусов вращения:
![enter image description here]()
Вращение на 90 градусов только зеленое.
В любом случае, я надеюсь, кто-то, кто сделал это раньше, может указать мне в правильном направлении. Я не могу найти какие-либо документы по некоторым более продвинутым темам в композициях и экспорте AVFoundation.
Ответы
Ответ 1
Попробуйте следующее:
AVMutableVideoCompositionLayerInstruction *passThroughLayer = AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
CGAffineTransform rotateTranslate = CGAffineTransformTranslate(rotateTransform,320,0);
[passThroughLayer setTransform:rotateTranslate atTime:kCMTimeZero];
По существу идея состоит в создании матрицы вращения и перевода. Вы поворачиваете его в правильную ориентацию, а затем переводите в вид. Я не видел никакого способа указать точку центра, пока я просматривал API.
Ответ 2
Основываясь на ответах. Я нашел очень хороший способ отладки и выяснения, что пошло не так с вашими преобразованиями. Используя доступные методы рампы, вы можете анимировать преобразования, упрощая просмотр того, что делает ваше преобразование.
В большинстве случаев я обнаружил, что у меня есть преобразования, которые, казалось, ничего не делали, пока я не понял, что только использование свойства preferredTransform видеодорожки в одиночку может привести к тому, что видеопоток будет перемещен из экрана рендеринга.
AVMutableVideoCompositionLayerInstruction *videoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[videoLayerInstruction setTransformRampFromStartTransform:CGAffineTransformIdentity
toEndTransform:videoTrack.preferredTransform
timeRange:CMTimeRangeMake(projectClipStart, projectClipDuration)];
В конце концов, я обнаружил, что в некоторых случаях мне нужно было применить перевод, чтобы вернуть повернутое видео в экран рендеринга.
CGAffineTransformConcat(videoTrack.preferredTransform, CGAffineTransformMakeTranslation(0, renderSize.height))
Примечание. Ваши значения перевода могут отличаться.
Ответ 3
AVAssetTrack *videoAssetTrack= [[videoAsset tracksWithMediaType:AVMediaTypeVideo] lastObject];
AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:&error];
videoCompositionTrack.preferredTransform = videoAssetTrack.preferredTransform;
Ответ 4
Также может быть актуальным, но есть ошибка в предпочтительномTransform, устанавливаемом при использовании фронтальной камеры. см. здесь, например, где ребята из проекта SDAVAssetExportSession закодировали обход:
https://github.com/rs/SDAVAssetExportSession/pull/70
Ответ 5
Я нашел решение в проекте плагина Flutter.
- (CGAffineTransform)fixTransform:(AVAssetTrack*)videoTrack {
CGAffineTransform transform = videoTrack.preferredTransform;
if (transform.tx == 0 && transform.ty == 0) {
NSInteger rotationDegrees = (NSInteger)round(radiansToDegrees(atan2(transform.b, transform.a)));
NSLog(@"TX and TY are 0. Rotation: %ld. Natural width,height: %f, %f", (long)rotationDegrees,
videoTrack.naturalSize.width, videoTrack.naturalSize.height);
if (rotationDegrees == 90) {
NSLog(@"Setting transform tx");
transform.tx = videoTrack.naturalSize.height;
transform.ty = 0;
} else if (rotationDegrees == 270) {
NSLog(@"Setting transform ty");
transform.tx = 0;
transform.ty = videoTrack.naturalSize.width;
}
}
return transform;
}
// set layerInstruction
[firstVideoLayerInstruction setTransform:[self fixTransform:firstVideoAssetTrack] atTime:kCMTimeZero];
Flutter VideoPlayerPlugin