加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

iphone – 视频错误的UIImage的NSArray在输出中有失真

发布时间:2020-12-14 19:26:55 所属栏目:百科 来源:网络整理
导读:我对编程比较陌生,虽然我对正常的功能很满意,但我对视频编辑还是全新的 所以我设法在网上找到一些代码来完成下面显示的工作: - (void)writeImagesAsMovie:(NSArray *)array {NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSU
我对编程比较陌生,虽然我对正常的功能很满意,但我对视频编辑还是全新的

所以我设法在网上找到一些代码来完成下面显示的工作:

- (void)writeImagesAsMovie:(NSArray *)array {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDirectory,YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *saveLocation = [documentDirectory stringByAppendingString:@"/temp.mov"];

if ([[NSFileManager defaultManager] fileExistsAtPath:saveLocation]) {
    [[NSFileManager defaultManager] removeItemAtPath:saveLocation error:NULL];
}

UIImage *first = [array objectAtIndex:0];

CGSize frameSize = first.size;

NSError *error = nil;
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
                              [NSURL fileURLWithPath:saveLocation] fileType:AVFileTypeQuickTimeMovie
                                                          error:&error];

if(error) {
    NSLog(@"error creating AssetWriter: %@",[error description]);
}
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               AVVideoCodecH264,AVVideoCodecKey,[NSNumber numberWithInt:frameSize.width],AVVideoWidthKey,[NSNumber numberWithInt:frameSize.height],AVVideoHeightKey,nil];



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

NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.width] forKey:(NSString*)kCVPixelBufferWidthKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:frameSize.height] forKey:(NSString*)kCVPixelBufferHeightKey];

AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                 assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                 sourcePixelBufferAttributes:attributes];

[videoWriter addInput:writerInput];

// fixes all errors
writerInput.expectsMediaDataInRealTime = YES;

//Start a session:
[videoWriter startWriting];

[videoWriter startSessionAtSourceTime:kCMTimeZero];

CVPixelBufferRef buffer = NULL;
buffer = [self pixelBufferFromCGImage:[first CGImage]];
BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];

if (result == NO) //failes on 3GS,but works on iphone 4
    NSLog(@"failed to append buffer");

if(buffer) {
    CVBufferRelease(buffer);
}



//int reverseSort = NO;
NSArray *newArray = array;



int fps = 10;


int i = 0;
for (UIImage *image in newArray)
{
    [NSThread sleepForTimeInterval:0.02];
    if (adaptor.assetWriterInput.readyForMoreMediaData) {

        i++;
        CMTime frameTime = CMTimeMake(1,fps);
        CMTime lastTime = CMTimeMake(i,fps);
        CMTime presentTime = CMTimeAdd(lastTime,frameTime);

        UIImage *imgFrame = image;//[UIImage imageWithContentsOfFile:filePath] ;
        buffer = [self pixelBufferFromCGImage:[imgFrame CGImage]];
        BOOL result = [adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];

        if (result == NO) //failes on 3GS,but works on iphone 4
        {
            NSLog(@"failed to append buffer");
            NSLog(@"The error is %@",[videoWriter error]);
            [NSThread sleepForTimeInterval:0.5];
        }

        if(buffer) {
            CVBufferRelease(buffer);
        }


    } else {
        NSLog(@"error");
        i--;
    }
}

//Finish the session:
[writerInput markAsFinished];
[videoWriter finishWriting];
CVPixelBufferPoolRelease(adaptor.pixelBufferPool);

NSLog(@"Movie created successfully");
}

- (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image
{


    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES],kCVPixelBufferCGImageCompatibilityKey,[NSNumber numberWithBool:YES],kCVPixelBufferCGBitmapContextCompatibilityKey,nil];
    CVPixelBufferRef pxbuffer = NULL;

    CVPixelBufferCreate(kCFAllocatorDefault,CGImageGetWidth(image),CGImageGetHeight(image),kCVPixelFormatType_32ARGB,(__bridge CFDictionaryRef) options,&pxbuffer);

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

    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata,8,4*CGImageGetWidth(image),rgbColorSpace,kCGImageAlphaNoneSkipFirst);

    CGContextConcatCTM(context,CGAffineTransformMakeRotation(0));

    //    CGAffineTransform flipVertical = CGAffineTransformMake(
    //                                                           1,-1,CGImageGetHeight(image)
    //                                                           );
    //    CGContextConcatCTM(context,flipVertical);



    //    CGAffineTransform flipHorizontal = CGAffineTransformMake(
    //                                                             -1.0,0.0,1.0,0.0
    //                                                             );
    //
    //    CGContextConcatCTM(context,flipHorizontal);


    CGContextDrawImage(context,CGRectMake(0,CGImageGetHeight(image)),image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);

    CVPixelBufferUnlockBaseAddress(pxbuffer,0);

    return pxbuffer;
}

但我遇到的问题是视频的输出有些损坏(尽管它有如下所示的有趣线条,但确实会播放)

我会非常感激任何帮助

非常感谢

托马斯

解决方法

我一直看到H264视频编码硬件存在问题,它可以破坏与已知宽高比不匹配的输入.例如,我的测试显示,如果一个视频维度小于128像素,则视频将不会编码.

我所看到的工作是128×128,192×128,240×160,480×320等.

见这page on aspect ratios

附:您可能希望使用AVAssetWriterInputPixelBufferAdaptor,因为它包含可以通过CVPixelBufferPoolCreatePixelBuffer()使用的像素缓冲池.另外,你需要断言(adaptor.pixelBufferPool);在调用startSessionAtSourceTime之后,确保您的适配器可以写入writer.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读