题 iPhone:以编程方式压缩录制的视频以进行共享?


在录制视频之前,我在调用摄像机视图时实现了叠加视图。

pickerController.cameraOverlayView =myOverlay;

视频录制并在录制视频和通过电子邮件等共享后将视频保存到相册中。一切正常。

如果我将视频质量用作“高质量”,那么录制的视频已变得庞大。例如,如果我以高质量录制视频30秒,录制的视频大约为30 - 40 mb。

pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;

如何在共享前压缩高质量录制视频进行编程,就像Apple使用内置录像机一样?

请指导我解决这个问题。

谢谢!

更新:

这就是我最近的尝试,但仍然没有成功:我想压缩拍摄的录制视频来到didFinishPickingMediaWithInfo并存储在相同的相册实际视频路径本身,而不是其他任何地方。我测试相同的视频被压缩到非常小的尺寸,当我从照片库中选择时,但是从相机拍摄的同一视频并通过didFinishPickingMediaWithInfo来到未压缩,尽管我使用下面的AVAssetExportSession代码。

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];


if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{

    NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
    NSString *urlPath = [videoURL path];

    if ([[urlPath lastPathComponent] isEqualToString:@"capturedvideo.MOV"])
    {
        if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (urlPath))
        {
            [self copyTempVideoToMediaLibrary :urlPath];


        }
        else
        {
            NSLog(@"Video Capture Error: Captured video cannot be saved...didFinishPickingMediaWithInfo()");                
        }
    }       
    else
    {
        NSLog(@"Processing soon to saved photos album...else loop of lastPathComponent..didFinishPickingMediaWithInfo()");
    }
}    
[self dismissModalViewControllerAnimated:YES];
}

- (void)copyTempVideoToMediaLibrary :(NSString *)videoURL {

        dispatch_queue_t mainQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(mainQueue, ^{

    ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease];

    ALAssetsLibraryWriteVideoCompletionBlock completionBlock = ^(NSURL *assetURL, NSError *error) {
        NSLog(@"Saved URL: %@", assetURL);
        NSLog(@"Error: %@", error);

        if (assetURL != nil) {

            AVURLAsset *theAsset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:videoURL] options:nil];

            NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:theAsset];

            AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:theAsset presetName:AVAssetExportPresetLowQuality];

            [exportSession setOutputURL:[NSURL URLWithString:videoURL]];
            [exportSession setOutputFileType:AVFileTypeQuickTimeMovie];

            [exportSession exportAsynchronouslyWithCompletionHandler:^ {
                switch ([exportSession status]) {
                    case AVAssetExportSessionStatusFailed:
                        NSLog(@"Export session faied with error: %@", [exportSession error]);
                        break;
                    default:
                        //[self mediaIsReady];
                        break;
                }
            }];
        }
    };

    [library writeVideoAtPathToSavedPhotosAlbum:[NSURL URLWithString:videoURL] completionBlock:completionBlock];
});
}

41
2018-04-16 14:58


起源


降低videoQuality和压缩它有什么区别?或者你的意思是压缩像拉链? - Koh Jing Yu


答案:


如果您想压缩视频以进行远程共享并保持iPhone上本地存储的原始质量,您应该查看 AVAssetExportSession 要么 AVAssetWriter

还要了解iOS的管理方式 资产

- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL 
                                   outputURL:(NSURL*)outputURL 
                                     handler:(void (^)(AVAssetExportSession*))handler
{
    [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
    exportSession.outputURL = outputURL;
    exportSession.outputFileType = AVFileTypeQuickTimeMovie;
    [exportSession exportAsynchronouslyWithCompletionHandler:^(void) 
    {
        handler(exportSession);
        [exportSession release];
    }];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

{   
    NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
    NSURL *outputURL = [NSURL fileURLWithPath:@"/Users/josh/Desktop/output.mov"];
    [self convertVideoToLowQuailtyWithInputURL:videoURL outputURL:outputURL handler:^(AVAssetExportSession *exportSession)
     {
         if (exportSession.status == AVAssetExportSessionStatusCompleted)
         {
             printf("completed\n");
         }
         else
         {
             printf("error\n");

         }
     }];

}

65
2018-05-02 04:02



非常感谢Jojaba! - Getsy
嗨,Jojaba,我仍然在努力。我使用UIImagePickerController来拍摄视频/从照片库中选择,从照片库中获取视频正在压缩视频(显示消息也称为压缩...),当点击“选择”时很好,但如果我允许从相机拍摄视频然后单击“使用”不会压缩拍摄的视频。单击“使用”时是否可以压缩视频?当我使用UIImagePickerController API时默认情况下它是如何工作的? - Getsy
嗨,我发现如果我们降低质量,那么实际的高清录制视频(720p)质量会降低,而不是真正的高清视频。我的要求是,如何保持视频具有相同的尺寸(720p),但在上传(发送)到我的服务器之前减小视频的大小。 - Getsy
你使用过照片应用吗?如果您使用“在Youtube上共享”按钮,Apple似乎能够压缩720p视频,生成的文件保持相对较高的质量,文件大小较小。他们是如何做到的呢? - zakdances
@etayluz根据我的经验,AVAssetWriter用于视频和音频的专业复用。例如,如果您拥有h264中的视频和原始16bit-LE PCM中的音频,则可以压缩音频AAC,然后使用AVAssetWriter将h264 + AAC组合成MPEG4或Quicktime兼容文件。另一方面,AVAssetExportSession有助于获取已格式化的MPEG4 / Quicktime文件并重新压缩以降低比特率。 - tidwall


我想这个视频已经被h264编解码器压缩了。但您可以尝试使用AVFoundation从相机捕获视频文件。但我怀疑你最终会得到相同的文件大小。

以下是iPhone 4上录制的具有不同质量预设的10秒视频文件的一些统计数据。

high (1280х720) = ~14MB = ~11Mbit/s
640 (640х480) = ~4MB = ~3.2Mbit/s
medium (360х480) = ~1MB = ~820Kbit/s
low (144х192) = ~208KB = ~170Kbit/s

12
2018-04-22 22:42



多谢告诉我这个消息。就在这里,你可以看到问题......对于10秒的视频,14MB是大的。产生的下降到480p会显着降低质量 - zakdances
注意:这不适用于较新的iPhone型号 - 即iPhone 5,5s等。 - Alex Spencer


pickerController.videoQuality = UIImagePickerControllerQualityTypeMedium;

这些是您可以选择的所有值。

UIImagePickerControllerQualityTypeHigh    = 0,
UIImagePickerControllerQualityType640x480 = 3,
UIImagePickerControllerQualityTypeMedium  = 1,  // default value
UIImagePickerControllerQualityTypeLow     = 2

11
2018-05-02 00:51



不确定是否有其他人有此问题,但当我更改选择器质量(如上所示)时,它不会更改我的文件大小= \ - Ibdakine


试试这几行:

    [[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
    AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
    AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset: urlAsset presetName:AVAssetExportPresetLowQuality];
    session.outputURL = outputURL;
    session.outputFileType = AVFileTypeQuickTimeMovie;
    [session exportAsynchronouslyWithCompletionHandler:^(void) 
    {
        handler(session);

    }];

4
2017-11-27 09:42





使用swift以编程方式压缩视频

并且不要忘记添加 - 导入AssetsLibrary

func convertVideoWithMediumQuality(inputURL : NSURL){

            let VideoFilePath = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("mergeVideo\(arc4random()%1000)d").URLByAppendingPathExtension("mp4").absoluteString
            if NSFileManager.defaultManager().fileExistsAtPath(VideoFilePath) {
                do {
                    try NSFileManager.defaultManager().removeItemAtPath(VideoFilePath)
                } catch { }
            } 

            let savePathUrl =  NSURL(string: VideoFilePath)!

            let sourceAsset = AVURLAsset(URL: inputURL, options: nil)

            let assetExport: AVAssetExportSession = AVAssetExportSession(asset: sourceAsset, presetName: AVAssetExportPresetMediumQuality)!
            assetExport.outputFileType = AVFileTypeQuickTimeMovie
            assetExport.outputURL = savePathUrl
            assetExport.exportAsynchronouslyWithCompletionHandler { () -> Void in

                switch assetExport.status {
                case AVAssetExportSessionStatus.Completed:
                    dispatch_async(dispatch_get_main_queue(), {
                        do {
                            let videoData = try NSData(contentsOfURL: savePathUrl, options: NSDataReadingOptions())
                            print("MB - \(videoData.length / (1024 * 1024))")
                        } catch {
                            print(error)
                        }

                    })
                case  AVAssetExportSessionStatus.Failed:
                    self.hideActivityIndicator(self.view)
                    print("failed \(assetExport.error)")
                case AVAssetExportSessionStatus.Cancelled:
                    self.hideActivityIndicator(self.view)
                    print("cancelled \(assetExport.error)")
                default:
                    self.hideActivityIndicator(self.view)
                    print("complete")
                }
            }

        }

4
2018-04-28 13:53



谢谢!!这至少对我来说非常合适 - b3rge
凉。为什么要使用随机文件名呢?这看起来很可疑。如果您多次调用此函数并希望避免名称冲突,则使用随机文件名并不总是有效并导致问题。如果您一次只调用一个,则不需要随机文件名。我建议使用更确定的命名方案(计数器等) - n13


我发现了一个很好的定制课程(SDAVAssetExportSession)进行视频压缩。你可以从这里下载它 链接

下载后将SDAVAssetExportSession.h和SDAVAssetExportSession.m文件添加到项目中,然后下面的代码将有助于进行压缩。 在下面的代码中,您可以通过指定分辨率和比特率来压缩视频 

#import "SDAVAssetExportSession.h"


- (void)compressVideoWithInputVideoUrl:(NSURL *) inputVideoUrl
{
    /* Create Output File Url */

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *finalVideoURLString = [documentsDirectory stringByAppendingPathComponent:@"compressedVideo.mp4"];
    NSURL *outputVideoUrl = ([[NSURL URLWithString:finalVideoURLString] isFileURL] == 1)?([NSURL URLWithString:finalVideoURLString]):([NSURL fileURLWithPath:finalVideoURLString]); // Url Should be a file Url, so here we check and convert it into a file Url


    SDAVAssetExportSession *compressionEncoder = [SDAVAssetExportSession.alloc initWithAsset:[AVAsset assetWithURL:inputVideoUrl]]; // provide inputVideo Url Here
    compressionEncoder.outputFileType = AVFileTypeMPEG4;
    compressionEncoder.outputURL = outputVideoUrl; //Provide output video Url here
    compressionEncoder.videoSettings = @
    {
    AVVideoCodecKey: AVVideoCodecH264,
    AVVideoWidthKey: @800,   //Set your resolution width here
    AVVideoHeightKey: @600,  //set your resolution height here
    AVVideoCompressionPropertiesKey: @
        {
        AVVideoAverageBitRateKey: @45000, // Give your bitrate here for lower size give low values
        AVVideoProfileLevelKey: AVVideoProfileLevelH264High40,
        },
    };
    compressionEncoder.audioSettings = @
    {
    AVFormatIDKey: @(kAudioFormatMPEG4AAC),
    AVNumberOfChannelsKey: @2,
    AVSampleRateKey: @44100,
    AVEncoderBitRateKey: @128000,
    };

    [compressionEncoder exportAsynchronouslyWithCompletionHandler:^
     {
         if (compressionEncoder.status == AVAssetExportSessionStatusCompleted)
         {
            NSLog(@"Compression Export Completed Successfully");
         }
         else if (compressionEncoder.status == AVAssetExportSessionStatusCancelled)
         {
             NSLog(@"Compression Export Canceled");
         }
         else
         {
              NSLog(@"Compression Failed");

         }
     }];

}

要取消压缩,请使用下面的代码行

 [compressionEncoder cancelExport]; //Video compression cancel

2
2017-10-27 11:38



我得到错误 - [AVAssetWriter startSessionAtSourceTime:]无效参数不满足:使用sdavexportsession时CMTIME_IS_NUMERIC(startTime) - starterMac