Отключить видео + преобразовать видео с помощью одной операции экспорта AVAssetExportSession

У меня есть следующий код для исправления трансформации видео

    - (AVVideoComposition *)squareVideoCompositionFor:(AVAsset *)asset {

    AVAssetTrack *track = [asset tracksWithMediaType:AVMediaTypeVideo].firstObject;

    CGFloat length = MAX(track.naturalSize.width, track.naturalSize.height);

    CGSize size = track.naturalSize;

    CGFloat scale = 0;

    CGAffineTransform transform = track.preferredTransform;

    if (transform.a == 0 && transform.b == 1 && transform.c == -1 && transform.d == 0) {
        scale = -1;
    }
    else if (transform.a == 0 && transform.b == -1 && transform.c == 1 && transform.d == 0) {
        scale = -1;
    }
    else if (transform.a == 1 && transform.b == 0 && transform.c == 0 && transform.d == 1) {
        scale = 1;
    }
    else if (transform.a == -1 && transform.b == 0 && transform.c == 0 && transform.d == -1) {
        scale = -1;
    }

    transform = CGAffineTransformTranslate(transform, scale * -(size.width - length) / 2, scale * -(size.height - length) / 2);




    AVMutableVideoCompositionLayerInstruction *transformer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:track];
    [transformer setTransform:transform atTime:kCMTimeZero];

//    CGAffineTransform finalTransform = t2;
//    [transformer setTransform:finalTransform atTime:kCMTimeZero];

    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, kCMTimePositiveInfinity);
    instruction.layerInstructions = @[transformer];


    AVMutableVideoComposition *composition = [AVMutableVideoComposition videoComposition];
    composition.frameDuration = CMTimeMake(1, 30);
    composition.renderSize =  CGSizeMake(length, length);
    composition.instructions = @[instruction];
    composition.renderScale = 1.0;


    return composition;
    }

И следующий код для отключения звука

- (AVMutableComposition *) removeAudioFromVideoFileFor:(AVAsset *)asset  {
    AVMutableComposition *composition_Mix = [AVMutableComposition composition];
    AVMutableCompositionTrack *compositionVideoTrack = [composition_Mix addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

    BOOL ok = NO;

    AVAssetTrack * sourceVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

    CMTimeRange x = CMTimeRangeMake(kCMTimeZero, [asset duration]);
    NSError *error;
    ok = [compositionVideoTrack insertTimeRange:x ofTrack:sourceVideoTrack atTime:kCMTimeZero error:&error];

    return composition_Mix;
}

Вот как я вызываю функцию

    AVAsset *asset = [AVAsset assetWithURL:inputURL];

    AVMutableComposition *composition = [self  removeAudioFromVideoFileFor:asset];

    AVAssetExportSession *session = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetHighestQuality];
    session.videoComposition = [self squareVideoCompositionFor:asset];
    session.outputURL = outputURL;
    session.outputFileType = AVFileTypeMPEG4;
    session.shouldOptimizeForNetworkUse = true;
    session.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);

Но он показывает ошибку, если я использовал и composition, и [self squareVideoCompositionFor:asset].

Домен ошибки = AVFoundationErrorDomain Code = -11841 «Операция остановлена» UserInfo = {NSLocalizedDescription = Операция остановлена, NSLocalizedFailureReason = Не удалось создать видео.}

Если я опущу один, он работает нормально, значит, One AVAssetExportSession может либо отключить звук из видео, либо из squareVideo.

Есть ли способ добиться того и другого, используя единый прогресс экспорта AVAssetExportSession?


person Prashant Tukadiya    schedule 30.10.2017    source источник


Ответы (1)


Ваш код выглядит хорошо, но я внес изменения в ваш код, чтобы он заработал.

inputURL и outputURL должны иметь префикс file:// или https:// (так как это URL-адрес, в вашем случае он должен начинаться с file://)

Если ваш недействителен, вы не получите желаемого результата.

//FOR OUTPUT URL
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
path = [path stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

//the output video will be written to file final.mp4
NSURL *outputURL = [NSURL fileURLWithPath:path];
outputURL = [outputURL URLByAppendingPathComponent:@"final.mp4"];
NSLog(@"outputURL = %@", outputURL);


//FOR INPUT URL
//This is the path of the bundle resource that is going to be used
NSURL *inputURL = [[NSBundle mainBundle] URLForResource:@"video" withExtension:@"mp4"];
NSLog(@"inputURL = %@", inputURL);

Экспорт композиции

//this will export the composition with the specified configuration
[session exportAsynchronouslyWithCompletionHandler:^{
    NSLog(@"Success");
}];

Когда вы увидите сообщение «Успех» в консоли, проверьте каталог документов вашего приложения. Видео будет записано на outptURL.

ПРИМЕЧАНИЕ. ИСПОЛЬЗУЙТЕ CMD + SHIFT + G и укажите URL-адрес вывода. Вы будете перенаправлены в папку с документами вашего приложения (только для симулятора). Для устройства вам необходимо загрузить контейнер приложения и просмотреть содержимое пакета.

Полный КОД

Методы removeAudioFromVideoFileFor: и squareVideoCompositionFor: выглядят неплохо. просто нужно изменить следующее.

Здесь «видео» - это имя файла ресурсов в комплекте приложений.

- (void)viewDidLoad {
[super viewDidLoad];


   NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
   path = [path stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
  NSURL *outputURL = [NSURL fileURLWithPath:path];
outputURL = [outputURL URLByAppendingPathComponent:@"final.mp4"];
  NSLog(@"outputURL = %@", outputURL);


  NSURL *inputURL = [[NSBundle mainBundle] URLForResource:@"video" withExtension:@"mp4"];
  NSLog(@"inputURL = %@", inputURL);

  AVAsset *asset = [AVAsset assetWithURL:inputURL];

  AVMutableComposition *composition = [self removeAudioFromVideoFileFor: asset];

  AVAssetExportSession *session = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetHighestQuality];
  session.videoComposition = [self squareVideoCompositionFor:asset];
  session.outputURL = outputURL;
  session.outputFileType = AVFileTypeMPEG4;
  session.shouldOptimizeForNetworkUse = true;
  session.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);

  [session exportAsynchronouslyWithCompletionHandler:^{
     NSLog(@"Success:");
  }];
}

Надеюсь, это поможет

person Mahendra    schedule 14.06.2019
comment
Спасибо за ответ, я посмотрю на это и дам вам знать, если возникнут какие-либо вопросы. - person Sagar Chauhan; 14.06.2019