【问题标题】:iPhone - AVAssetWriter - Error creating movie from photos at 1920×1080 pixelsiPhone - AVAssetWriter - 从 1920×1080 像素的照片创建电影时出错
【发布时间】:2012-12-07 13:55:09
【问题描述】:

我正在尝试从一些图片创建电影。它适用于高清图片 ({720, 1280}) 或更低分辨率。但是当我尝试用全高清图片 {1080, 1920} 创建电影时,视频被打乱了。这是一个链接,可以查看它的外观 http://www.youtube.com/watch?v=BfYldb8e_18 。你有什么想法我可能做错了吗?

- (void) createMovieWithOptions:(NSDictionary *) options
{
@autoreleasepool {
    NSString *path = [options valueForKey:@"path"];
    CGSize size =  [(NSValue *)[options valueForKey:@"size"] CGSizeValue];
    NSArray *imageArray = [options valueForKey:@"pictures"];
    NSInteger recordingFPS = [[options valueForKey:@"fps"] integerValue];
    BOOL success=YES;
    NSError *error = nil;

    AVAssetWriter *assetWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path]
                                                           fileType:AVFileTypeQuickTimeMovie
                                                              error:&error];
    NSParameterAssert(assetWriter);

    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                   AVVideoCodecH264, AVVideoCodecKey,
                                   [NSNumber numberWithFloat:size.width], AVVideoWidthKey,
                                   [NSNumber numberWithFloat:size.height], AVVideoHeightKey,
                                   nil];

    AVAssetWriterInput *videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
                                                                              outputSettings:videoSettings];

    // Configure settings for the pixel buffer adaptor.
    NSDictionary* bufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                      [NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil];

    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput
                                                                                                                     sourcePixelBufferAttributes:bufferAttributes];

    NSParameterAssert(videoWriterInput);
    NSParameterAssert([assetWriter canAddInput:videoWriterInput]);

    videoWriterInput.expectsMediaDataInRealTime = NO;
    [assetWriter addInput:videoWriterInput];

    //Start a session:
    [assetWriter startWriting];
    [assetWriter startSessionAtSourceTime:kCMTimeZero];

    CVPixelBufferRef buffer = NULL;

    //convert uiimage to CGImage.

    int frameCount = 0;
    float progress = 0;
    float progressFromFrames = _progressView.progress; //only for create iflipbook movie

    for(UIImage * img in imageArray)
    {
        if([[NSThread currentThread] isCancelled])
        {
            [NSThread exit];
        }

        [condCreateMovie lock];
        if(isCreateMoviePaused)
        {
            [condCreateMovie wait];
        }

        uint64_t totalFreeSpace=[Utils getFreeDiskspace];
        if(((totalFreeSpace/1024ll)/1024ll)<50)
        {
            success=NO;
            break;
        }

        //        @autoreleasepool {
        NSLog(@"size:%@",NSStringFromCGSize(img.size));

        buffer = [[MovieWritter sharedMovieWritter] pixelBufferFromCGImage:[img CGImage] andSize:size];

        BOOL append_ok = NO;
        int j = 0;
        while (!append_ok && j < 60)
        {
            if(adaptor.assetWriterInput.readyForMoreMediaData)
            {
                CMTime frameTime = CMTimeMake(frameCount, recordingFPS);
                append_ok = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime];

                CVPixelBufferRelease(buffer);

                [NSThread sleepForTimeInterval:0.1];


                if(isCreatingiFlipBookFromImported)
                    progress = (float)frameCount/(float)[imageArray count]/2.0 + progressFromFrames;
                else
                    progress = (float)frameCount/(float)[imageArray count];

                [[NSNotificationCenter defaultCenter] postNotificationName:@"movieCreationProgress" object:[NSNumber numberWithFloat:progress]];
            }
            else
            {
                [NSThread sleepForTimeInterval:0.5];
            }
            j++;
        }
        if (!append_ok)
        {
            NSLog(@"error appending image %d times %d\n", frameCount, j);
        }
        frameCount++;

        [condCreateMovie unlock];
    }

    //Finish the session:
    [videoWriterInput markAsFinished];
    [assetWriter finishWriting];

    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                          [NSNumber numberWithBool:success], @"success",
                          path, @"path", nil];

    [[NSNotificationCenter defaultCenter] postNotificationName:@"movieCreationFinished" object:dict];
}
}

*编辑。这是 [[MovieWritter sharedMovieWritter] pixelBufferFromCGImage:]

的代码
- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image andSize:(CGSize) size
{
@autoreleasepool {
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                             [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                             nil];
    CVPixelBufferRef pxbuffer = NULL;

    CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width,
                                          size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options,
                                          &pxbuffer);
    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    NSParameterAssert(pxdata != NULL);

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata, size.width,
                                                 size.height, 8, 4*size.width, rgbColorSpace,
                                                 kCGImageAlphaNoneSkipFirst);
    NSParameterAssert(context);
    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
                                           CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

     return pxbuffer;
}
}

【问题讨论】:

  • 请发布代码:[MovieWritter sharedMovieWritter] pixelBufferFromCGImage: too.

标签: iphone ios mobile avassetwriter avasset


【解决方案1】:

我遇到了同样的问题,this answer 解决了:视频大小必须是 16 的倍数。

【讨论】:

  • 非常感谢!几天来一直在努力解决各种问题。一个荒谬的要求,但 Apple 充满了这些。
【解决方案2】:

很确定这是硬件限制或错误。请提交雷达。

【讨论】:

  • 我自己也遇到过这个问题,是的,这是 90% 的硬件限制,因为在模拟器中按预期工作。
【解决方案3】:

像这样的东西来获取像素缓冲区怎么样

    //you could use a cgiimageref here instead
    CFDataRef imageData= CGDataProviderCopyData(CGImageGetDataProvider(imageView.image.CGImage));
    NSLog (@"copied image data");
    cvErr = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
                                         FRAME_WIDTH,
                                         FRAME_HEIGHT,
                                         kCVPixelFormatType_32BGRA,
                                         (void*)CFDataGetBytePtr(imageData),
                                         CGImageGetBytesPerRow(imageView.image.CGImage),
                                         NULL,
                                         NULL,
                                         NULL,
                                         &pixelBuffer);
    NSLog (@"CVPixelBufferCreateWithBytes returned %d", cvErr);

    CFAbsoluteTime thisFrameWallClockTime = CFAbsoluteTimeGetCurrent();  
    CFTimeInterval elapsedTime = thisFrameWallClockTime - firstFrameWallClockTime;  
    NSLog (@"elapsedTime: %f", elapsedTime);
    CMTime presentationTime =  CMTimeMake(elapsedTime * TIME_SCALE, TIME_SCALE);

    // write the sample
    BOOL appended = [assetWriterPixelBufferAdaptor  appendPixelBuffer:pixelBuffer withPresentationTime:presentationTime];
    CVPixelBufferRelease(pixelBuffer);
    CFRelease(imageData);
    if (appended) {
        NSLog (@"appended sample at time %lf", CMTimeGetSeconds(presentationTime));
    } else {
        NSLog (@"failed to append");
        [self stopRecording];
        self.startStopButton.selected = NO;
    }

【讨论】:

    【解决方案4】:

    您可能还想设置捕捉设置预设,虽然高通常是合适的并且是默认设置 */ 使用 sessionPreset 属性定义捕获设置预设的常量。

    NSString *const AVCaptureSessionPresetPhoto;

    NSString *const AVCaptureSessionPresetHigh;

    NSString *const AVCaptureSessionPresetMedium;

    NSString *const AVCaptureSessionPresetLow;

    NSString *const AVCaptureSessionPreset352x288;

    NSString *const AVCaptureSessionPreset640x480;

    NSString *const AVCaptureSessionPreset1280x720;

    NSString *const AVCaptureSessionPreset1920x1080;

    NSString *const AVCaptureSessionPresetiFrame960x540;

    NSString *const AVCaptureSessionPresetiFrame1280x720; */

    //这样设置

    self.captureSession.sessionPreset = AVCaptureSessionPreset1920x1080;

    //或者像这样定义avcapturesession时

    [self.captureSession setSessionPreset:AVCaptureSessionPreset1920x1080];

    【讨论】:

    • 这是最不相关的。当我们将全高清图像提供给 AVAssetWriterInputPixelBufferAdaptor 时,我和我的同事需要解决这个问题。可以从相机胶卷中拍摄图像……我们正在调整它们的大小以适应全高清分辨率。我们还从相机缓冲区捕获帧,但使用 AVAssetWriterInputPixelBufferAdaptor 仍然无法正常工作。也许这是 AVAssetWriterInputPixelBufferAdaptor 的错误或限制。
    • 我在没有设置预设之前遇到了一些问题,所以我提到了它,态度不好不会给你更快的帮助。像素格式是否错误尝试将 kCVPixelFormatType_32ARGB 更改为 kCVPixelFormatType_32BGRA,就像我展示的示例中一样
    • 像素格式在这里无关。 appendPixelBuffer ... 方法也返回一个 YES 响应。我们检查了大小、设置和所有内容,但仍然无法正常工作。
    • 好吧,从您的 youtube 上看,您的图像看起来非常失真,而且由于我没有看到您的代码有任何问题,所以我会开始查看您的输入,格式问题首先是合乎逻辑的选择。你说它在较低的分辨率下工作得很好,但这令人费解。而且我认为这不会像使用 int 那样简单,因为高度或宽度需要浮点数。
    • 这个怎么样,这个你考虑的纵横比。在您使用相同的纵横比进行测试的地方降低格式。 stackoverflow.com/questions/7327847/…
    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 2015-11-13
    • 1970-01-01
    • 2012-03-04
    • 2012-08-06
    • 2015-06-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多