iOS圖片,視訊上傳&視訊內容旋轉

c4ibD3發表於2017-05-17

#前言
我最近在接手一個智慧盒子的iOS應用,上面有一個功能是這樣的。把你本地的照片和視訊可以甩屏到你繫結的盒子上。
我的上一位前輩做的時候必須要求再同一個區域網,但是當我做的時候要求不同的區域網也要實現這樣的一個功能,優化使用者的使用感受。


#那麼 我們下面就進入正題。

#內容一:圖片上傳
我做的圖片上傳是用的AF,原理就是把你想上傳的照片取出來,如果有檔案大小的要求就先做相應的圖片壓縮。
然後用AFHTTPSessionManager 類去做的上傳,下面就是程式碼:

AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
    [session.requestSerializer willChangeValueForKey:@"timeoutInterval"];
    session.requestSerializer.timeoutInterval = 60.f;
    [session.requestSerializer didChangeValueForKey:@"timeoutInterval"];
    session.responseSerializer = [AFHTTPResponseSerializer serializer];

    NSString *imageTitle =_imageSource[pageIndex].title;
    imageTitle = [imageTitle substringToIndex:imageTitle.length-4];


    NSDictionary *params = @{
                          @"fileType":@"jpg",
                          @"fileName":imageTitle
                          };
    [session POST:@"你上傳的介面地址" parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        for (NSString *key in dict.allKeys) {
            [formData appendPartWithFileData:[dict objectForKey:key] name:@"myFile" fileName:[NSString stringWithFormat:@"%@.jpg",key] mimeType:@"image/jpeg"];
        }

    } progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

    }];複製程式碼

這裡主要就是和你們的後臺確認好相應的引數設定就好了。


#內容二:視訊上傳
視訊上傳和圖片上傳其實是類似的,只不過就是引數的設定不一樣而已。也是用上面的方法。關鍵也是設定好引數。
在這裡我想說的是,有的時候視訊太大要做相應的壓縮處理。因為我之前對視訊這面接觸的比較少,也上網找了一些資料然後看到這樣的一個方法:

- (void)lowQuailtyWithInputURL:(NSURL*)inputURL
                      outputURL:(NSURL*)outputURL
                   blockHandler:(void (^)(AVAssetExportSession*))handler
{
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
    AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset     presetName:AVAssetExportPresetMediumQuality];
    session.outputURL = outputURL;
    session.outputFileType = AVFileTypeQuickTimeMovie;
    [session exportAsynchronouslyWithCompletionHandler:^(void)
     {
        handler(session);
     }];
}複製程式碼

通過這個方法就可以對視訊進行相應的壓縮處理。


#下面就是視訊內容的旋轉問題了。
一開始我聽到了這個需求的時候我的腦子裡真的是瞬間萬馬飛奔啊!! 這是什麼鬼需求啊!鬼知道我經歷了什麼?
我想,那我就上網找一下吧!我找了一下,還真的有這麼樣的技術部落格。但是一上來就是把他的程式碼網上一貼。我先大概的瀏覽了一下那程式碼的長度。寫的我實在是沒有耐心去仔細的看到底是怎麼實現的。我就關掉了。可是後來一看,也沒有別的什麼部落格供我參考了。在我走投無路的時候,我看到了這麼一個部落格,說是Apple自己就有Demo,我就抱著好奇的態度去看了看。下載了那個Demo仔細的研究了一下。果然就好使了。 那麼,接下來就說一下。

再旋轉視訊之前我們先要確認一下,這個視訊是要旋轉多少度。

 AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
    NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
    NSInteger degress;
    if([tracks count] > 0) {
        AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
        CGAffineTransform t = videoTrack.preferredTransform;//這裡的矩陣有旋轉角度,轉換一下即可
        if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
            // Portrait
            degress = 90;
        }else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
            // PortraitUpsideDown
            degress = 270;
        }else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
            // LandscapeRight
            degress = 0;
        }else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
            // LandscapeLeft
            degress = 180;
        }
    }複製程式碼

這樣我們就可以通過degress來確認旋轉的角度了。
那麼我們接下來就開始旋轉視訊

AVMutableVideoCompositionInstruction *instruction = nil;
    AVMutableVideoCompositionLayerInstruction *layerInstruction = nil;
    CGAffineTransform t1;
    CGAffineTransform t2;
    AVAssetTrack *assetVideoTrack = nil;
    AVAssetTrack *assetAudioTrack = nil;
    // Check if the asset contains video and audio tracks
    if ([[asset tracksWithMediaType:AVMediaTypeVideo] count] != 0) {
        assetVideoTrack = [asset tracksWithMediaType:AVMediaTypeVideo][0];
    }
    if ([[asset tracksWithMediaType:AVMediaTypeAudio] count] != 0) {
        assetAudioTrack = [asset tracksWithMediaType:AVMediaTypeAudio][0];
    }
    CMTime insertionPoint = kCMTimeZero;
    NSError *error = nil;
    // Step 1
    // Create a composition with the given asset and insert audio and video tracks into it from the asset
    if (!mutableComposition) {
        // Check whether a composition has already been created, i.e, some other tool has already been applied
        // Create a new composition
        mutableComposition = [AVMutableComposition composition];
        // Insert the video and audio tracks from AVAsset
        if (assetVideoTrack != nil) {
            AVMutableCompositionTrack *compositionVideoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
            [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:assetVideoTrack atTime:insertionPoint error:&error];
        }
        if (assetAudioTrack != nil) {
            AVMutableCompositionTrack *compositionAudioTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
            [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:assetAudioTrack atTime:insertionPoint error:&error];
        }
    }
//    // Step 2
//    // Translate the composition to compensate the movement caused by rotation (since rotation would cause it to move out of frame)
//    t1 = CGAffineTransformMakeTranslation(assetVideoTrack.naturalSize.height, 0.0);
//    // Rotate transformation
//    t2 = CGAffineTransformRotate(t1, degreesToRadians(90));
    if (degress == 0) {
        t1 = CGAffineTransformMakeTranslation(0.0, 0.0);
        t2 = CGAffineTransformRotate(t1, degreesToRadians(0));
    }else if (degress == 90){
        t1 = CGAffineTransformMakeTranslation(assetVideoTrack.naturalSize.height, 0.0);
        t2 = CGAffineTransformRotate(t1, degreesToRadians(90));
    }else if (degress == 180){
        t1 = CGAffineTransformMakeTranslation(assetVideoTrack.naturalSize.width, assetVideoTrack.naturalSize.height);
        t2 = CGAffineTransformRotate(t1, degreesToRadians(180));
    }else if (degress == 270){
        t1 = CGAffineTransformMakeTranslation(0,assetVideoTrack.naturalSize.height*1.78);
        t2 = CGAffineTransformRotate(t1, degreesToRadians(-90));
    }
    // Step 3
    // Set the appropriate render sizes and rotational transforms
    if (!mutableVideoComposition) {
        // Create a new video composition
        mutableVideoComposition = [AVMutableVideoComposition videoComposition];
        if (degress == 0 || degress == 180) {
            mutableVideoComposition.renderSize = CGSizeMake(assetVideoTrack.naturalSize.width,assetVideoTrack.naturalSize.height);
        }else{
            mutableVideoComposition.renderSize = CGSizeMake(assetVideoTrack.naturalSize.height,assetVideoTrack.naturalSize.width);
        }
        mutableVideoComposition.frameDuration = CMTimeMake(1, 30);
        // The rotate transform is set on a layer instruction
        instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
        instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mutableComposition duration]);
        layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:(mutableComposition.tracks)[0]];
        [layerInstruction setTransform:t2 atTime:kCMTimeZero];
    } else {
        mutableVideoComposition.renderSize = CGSizeMake(mutableVideoComposition.renderSize.height, mutableVideoComposition.renderSize.width);
        // Extract the existing layer instruction on the mutableVideoComposition
        instruction = (mutableVideoComposition.instructions)[0];
        layerInstruction = (instruction.layerInstructions)[0];
        // Check if a transform already exists on this layer instruction, this is done to add the current transform on top of previous edits
        CGAffineTransform existingTransform;
        if (![layerInstruction getTransformRampForTime:[mutableComposition duration] startTransform:&existingTransform endTransform:NULL timeRange:NULL]) {
            [layerInstruction setTransform:t2 atTime:kCMTimeZero];
        } else {
            // Note: the point of origin for rotation is the upper left corner of the composition, t3 is to compensate for origin
            CGAffineTransform t3 = CGAffineTransformMakeTranslation(-1*assetVideoTrack.naturalSize.height/2, 0.0);
            CGAffineTransform newTransform = CGAffineTransformConcat(existingTransform, CGAffineTransformConcat(t2, t3));
            [layerInstruction setTransform:newTransform atTime:kCMTimeZero];
        }
    }
    // Step 4
    // Add the transform instructions to the video composition
    instruction.layerInstructions = @[layerInstruction];
    mutableVideoComposition.instructions = @[instruction];複製程式碼

到這個時候呢視訊的旋轉已經完成了。
上面我們不是寫了一個視訊壓縮的方法嗎?把這個時候生成的mutableVideoComposition賦值給session.videoComposition = mutableVideoComposition;就好了。這樣就是先旋轉視訊然後直接壓縮完成我們的需求。

相關文章