【问题标题】:iPhone:Programmatically compressing recorded video to share?iPhone:以编程方式压缩录制的视频以共享?
【发布时间】:2011-04-16 14:58:25
【问题描述】:

我在录制视频之前调用相机视图时实现了覆盖视图。

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];
});
}

【问题讨论】:

  • 降低 videoQuality 和压缩它有什么区别?或者你的意思是像压缩一样压缩?

标签: iphone


【解决方案1】:

我找到了一个出色的自定义类 (SDAVAssetExportSession) 来进行视频压缩。你可以从这个link下载它。

下载后将 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

【讨论】:

  • 使用 sdavexportsession 时出现错误,因为 -[AVAssetWriter startSessionAtSourceTime:] 无效参数不满足:CMTIME_IS_NUMERIC(startTime)
【解决方案2】:
pickerController.videoQuality = UIImagePickerControllerQualityTypeMedium;

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

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

【讨论】:

  • 不确定其他人是否有此问题,但当我更改选择器质量(如上所示)时,它不会改变我的文件大小 =\
【解决方案3】:

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

这里是在 iPhone 4 上使用不同质量的 pressets 录制的 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

【讨论】:

  • 感谢您提供此信息。在这里你可以看到问题... 14MB 对于 10 秒的视频来说太大了。结果下降到 480p 会显着降低质量
  • 注意:这不适用于较新的 iPhone 型号——即 iPhone 5,5s 等。
【解决方案4】:

使用 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")
                }
            }

        }

【讨论】:

  • 酷。为什么要使用随机文件名?这看起来很可疑。如果您多次调用它并希望避免名称冲突,则使用随机文件名并不总是有效并会导致问题。如果您一次只调用这个,则不需要随机文件名。我建议使用更具确定性的命名方案(计数器等)
  • 这一行主要是视频压缩大小的句柄 letassetExport: AVAssetExportSession = AVAssetExportSession(asset: sourceAsset, presetName: AVAssetExportPresetMediumQuality)!
【解决方案5】:

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

还阅读了 iOS 如何管理 Assets

- (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");

         }
     }];

}

【讨论】:

  • 嗨,Jojaba,我还在为此苦苦挣扎。我使用 UIImagePickerController 从照片库中获取视频/选择,当单击“选择”时,从照片库中获取视频正在压缩视频(显示消息也为压缩..),但是如果我允许从相机中获取视频然后单击在“使用”上不压缩拍摄的视频。单击“使用”时是否可以压缩视频?当我使用 UIImagePickerController API 时,它是如何默认不工作的?
  • 嗨,谢谢。我已经尝试过同样的事情,但没有成功。请检查我上面更新的代码,让我知道我做错了什么。请帮忙。
  • 您好,我发现如果我们降低质量,那么实际的高清录制视频(720p)质量会降低,这不是实际的高清视频。我的要求是,在上传(发送)到我的服务器之前,如何保持视频具有相同的尺寸(720p)但减小视频的大小。
  • 您使用过照片应用吗?如果您使用“在 Youtube 上共享”按钮,Apple 似乎能够压缩 720p 视频,生成的文件保持相对较高的质量并且文件大小更小。他们是怎么做到的?
  • @etayluz 根据我的经验,AVAssetWriter 用于专门的视频和音频混合。例如,如果您有 h264 格式的视频和原始 16 位 LE PCM 格式的音频,您可以压缩音频 AAC,然后使用 AVAssetWriter 将 h264+AAC 组合成一个 MPEG4 或 Quicktime 兼容文件。另一方面,AVAssetExportSession 有助于获取已格式化的 MPEG4 / Quicktime 文件并重新压缩以降低比特率。
【解决方案6】:

试试这几行:

    [[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);

    }];

【讨论】:

    【解决方案7】:

    我破解了这个。

    使用exportSession.fileLengthLimit = 1048576 * 10 //10 MB

    10MB 是硬编码数字。根据你需要的码率使用。

    【讨论】:

      猜你喜欢
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 2017-12-07
      • 1970-01-01
      相关资源
      最近更新 更多