【问题标题】:AVAssetWriter Outputting Large File (even when applying compression settings)AVAssetWriter 输出大文件(即使应用压缩设置)
【发布时间】:2015-03-15 06:56:31
【问题描述】:

我正在开发一个个人 iOS 项目,该项目需要通过 4G 连接将全屏视频(长度为 15 秒)上传到后端。虽然我可以很好地拍摄视频,但文件的输出大小为 30MB,这让我觉得在压缩方面我做错了什么严重。下面是我用来设置 AssetWriter 的代码:

-(void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections
{
    NSLog(@"Started Recording! *******************");
    self.movieWriter = [AVAssetWriter assetWriterWithURL:fileURL fileType:AVFileTypeMPEG4 error:nil];
    [self.movieWriter setShouldOptimizeForNetworkUse:YES];

    NSDictionary *videoCleanApertureSettings = @{
                                                 AVVideoCleanApertureWidthKey: [NSNumber numberWithFloat:self.view.frame.size.width],
                                                 AVVideoCleanApertureHeightKey: [NSNumber numberWithFloat:self.view.frame.size.height],
                                                 AVVideoCleanApertureHorizontalOffsetKey: [NSNumber numberWithInt:10],
                                                 AVVideoCleanApertureVerticalOffsetKey: [NSNumber numberWithInt:10],
                                                 };

    NSDictionary *videoCompressionSettings = @{
                                          AVVideoAverageBitRateKey: [NSNumber numberWithFloat:5000000.0],
                                          AVVideoMaxKeyFrameIntervalKey: [NSNumber numberWithInteger:1],
                                          AVVideoProfileLevelKey: AVVideoProfileLevelH264Baseline30,
                                          AVVideoCleanApertureKey: videoCleanApertureSettings,
                                          };

    NSDictionary *videoSettings = @{AVVideoCodecKey: AVVideoCodecH264,
                                    AVVideoWidthKey: [NSNumber numberWithFloat:self.view.frame.size.width],
                                    AVVideoHeightKey: [NSNumber numberWithFloat:self.view.frame.size.height],
                                    AVVideoCompressionPropertiesKey: videoCompressionSettings,
                                    };

    self.movieWriterVideoInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
    self.movieWriterVideoInput.expectsMediaDataInRealTime = YES;
    [self.movieWriter addInput:self.movieWriterVideoInput];

    NSDictionary *audioSettings = @{AVFormatIDKey: [NSNumber numberWithInteger:kAudioFormatMPEG4AAC],
                                    AVSampleRateKey: [NSNumber numberWithFloat:44100.0],
                                    AVNumberOfChannelsKey: [NSNumber numberWithInteger:1],
                                    };

    self.movieWriterAudioInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:audioSettings];
    self.movieWriterAudioInput.expectsMediaDataInRealTime = YES;
    [self.movieWriter addInput:self.movieWriterAudioInput];


    [self.movieWriter startWriting];
}

-(void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
    NSLog(@"Done Recording!");
    [self.movieWriterVideoInput markAsFinished];
    [self.movieWriterAudioInput markAsFinished];
    [self.movieWriter finishWritingWithCompletionHandler:^{
        AVURLAsset *compressedVideoAsset = [[AVURLAsset alloc] initWithURL:self.movieWriter.outputURL options:nil];
        //Upload video to server

    }];
}

对于实际会话的设置,我使用以下代码:

            //Indicate that some changes will be made to the session
            [self.captureSession beginConfiguration];
            self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;

            AVCaptureInput* currentCameraInput = [self.captureSession.inputs objectAtIndex:0];
            for (AVCaptureInput *captureInput in self.captureSession.inputs) {
                [self.captureSession removeInput:captureInput];
            }


            //Get currently selected camera and use for input
            AVCaptureDevice *videoCamera = nil;
            if(((AVCaptureDeviceInput*)currentCameraInput).device.position == AVCaptureDevicePositionBack)
            {
                videoCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
            }
            else
            {
                videoCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
            }

            //Add input to session
            AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:videoCamera error:nil];
            [self.captureSession addInput:newVideoInput];

            //Add mic input to the session
            AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
            AVCaptureInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil];
            [self.captureSession addInput:audioInput];

            //Add movie output to session
            for (AVCaptureOutput *output in self.captureSession.outputs) {
                [self.captureSession removeOutput:output];
            }

            self.movieOutput = [AVCaptureMovieFileOutput new];
            int32_t preferredTimeScale = 30; //Frames per second
            self.movieOutput.maxRecordedDuration = CMTimeMakeWithSeconds(15, preferredTimeScale); //Setting the max video length
            [self.captureSession addOutput:self.movieOutput];

            //Commit all the configuration changes at once
            [self.captureSession commitConfiguration];

我知道如果我将 AVCaptureSessionPresetHigh 更改为不同的预设,我可以减小最终视频的文件大小,但不幸的是看起来像 AVCaptureSessionPresetiFrame1280x720 是唯一一个提供了我尝试捕获的完整帧(这使我的输出大小约为 20MB,对于 4G 上传来说仍然太大)。

我花了很多时间在 Stack Overflow 上搜索和搜索其他帖子,但我似乎无法弄清楚我这辈子做错了什么,任何帮助都将不胜感激.

【问题讨论】:

    标签: ios objective-c video compression avassetwriter


    【解决方案1】:

    您需要博士学位才​​能使用 AVAssetWriter - 这很重要:https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/05_Export.html#//apple_ref/doc/uid/TP40010188-CH9-SW1

    有一个很棒的库可以完全按照您的意愿进行操作,它只是 AVAssetExportSession 的替代品,具有更重要的功能,例如更改比特率:https://github.com/rs/SDAVAssetExportSession

    使用方法如下:

    -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
    {
    
      SDAVAssetExportSession *encoder = [SDAVAssetExportSession.alloc initWithAsset:[AVAsset assetWithURL:[info objectForKey:UIImagePickerControllerMediaURL]]];
      NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
      NSString *documentsDirectory = [paths objectAtIndex:0];
      self.myPathDocs =  [documentsDirectory stringByAppendingPathComponent:
                          [NSString stringWithFormat:@"lowerBitRate-%d.mov",arc4random() % 1000]];
      NSURL *url = [NSURL fileURLWithPath:self.myPathDocs];
      encoder.outputURL=url;
      encoder.outputFileType = AVFileTypeMPEG4;
      encoder.shouldOptimizeForNetworkUse = YES;
    
      encoder.videoSettings = @
      {
      AVVideoCodecKey: AVVideoCodecH264,
      AVVideoCompressionPropertiesKey: @
        {
        AVVideoAverageBitRateKey: @2300000, // Lower bit rate here
        AVVideoProfileLevelKey: AVVideoProfileLevelH264High40,
        },
      };
      encoder.audioSettings = @
      {
      AVFormatIDKey: @(kAudioFormatMPEG4AAC),
      AVNumberOfChannelsKey: @2,
      AVSampleRateKey: @44100,
      AVEncoderBitRateKey: @128000,
      };
    
      [encoder exportAsynchronouslyWithCompletionHandler:^
      {
        int status = encoder.status;
    
        if (status == AVAssetExportSessionStatusCompleted)
        {
          AVAssetTrack *videoTrack = nil;
          AVURLAsset *asset = [AVAsset assetWithURL:encoder.outputURL];
          NSArray *videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo];
          videoTrack = [videoTracks objectAtIndex:0];
          float frameRate = [videoTrack nominalFrameRate];
          float bps = [videoTrack estimatedDataRate];
          NSLog(@"Frame rate == %f",frameRate);
          NSLog(@"bps rate == %f",bps/(1024.0 * 1024.0));
          NSLog(@"Video export succeeded");
          // encoder.outputURL <- this is what you want!!
        }
        else if (status == AVAssetExportSessionStatusCancelled)
        {
          NSLog(@"Video export cancelled");
        }
        else
        {
          NSLog(@"Video export failed with error: %@ (%d)", encoder.error.localizedDescription, encoder.error.code);
        }
      }];
    }
    

    【讨论】:

    • 谢谢你!超级有用的图书馆。
    • 当然 :) 我为此苦苦挣扎了很长时间!
    • 感谢分享!这对我行得通。它估计一个 3 兆字节的 10 秒视频。
    猜你喜欢
    • 2022-11-02
    • 1970-01-01
    • 2011-04-08
    • 1970-01-01
    • 2016-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多