Почему мое приложение для кодирования изображений на основе QTKit такое медленное? - PullRequest
7 голосов
/ 17 мая 2011

в приложении какао, которое я сейчас кодирую, я получаю снимки с изображения из рендерера Quartz Composer (объекты NSImage) и хочу кодировать их в QTMovie с разрешением 720 * 480, 25 кадров в секунду и кодеком H264используя метод addImage:Вот соответствующий фрагмент кода:

qRenderer = [[QCRenderer alloc] initOffScreenWithSize:NSMakeSize(720,480) colorSpace:CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB) composition:[QCComposition compositionWithFile:qcPatchPath]]; // define an "offscreen" Quartz composition renderer with the right image size


imageAttrs = [NSDictionary dictionaryWithObjectsAndKeys: @"avc1", // use the H264 codec
              QTAddImageCodecType, nil];

qtMovie = [[QTMovie alloc] initToWritableFile: outputVideoFile error:NULL]; // initialize the output QT movie object

long fps = 25;
frameNum = 0;

NSTimeInterval renderingTime = 0;
NSTimeInterval frameInc = (1./fps);
NSTimeInterval myMovieDuration = 70;
NSImage * myImage;
while (renderingTime <= myMovieDuration){
    if(![qRenderer renderAtTime: renderingTime arguments:NULL])
        NSLog(@"Rendering failed at time %.3fs", renderingTime);
    myImage = [qRenderer snapshotImage];
    [qtMovie addImage:myImage forDuration: QTMakeTimeWithTimeInterval(frameInc) withAttributes:imageAttrs];
    [myImage release];
    frameNum ++;
    renderingTime = frameNum * frameInc;
}
[qtMovie updateMovieFile];
[qRenderer release];
[qtMovie release]; 

Это работает, однако мое приложение не может сделать это в режиме реального времени на моем новом MacBook Pro, хотя я знаю, что QuickTime Broadcaster может кодировать изображения в режиме реального временив H264 с еще более высоким качеством, чем тот, который я использую, на том же компьютере.

Так почему?В чем здесь проблема?Это проблема управления аппаратным обеспечением (многоядерные потоки, графический процессор, ...) или я что-то упустил?Позвольте мне предвосхитить, что я новичок (2 недели практики) в мире разработки Apple, как в библиотеках Objective-C, Cocoa, X-code, Quicktime, Quartz Composer, и т. Д.

Спасибо за любую помощь

1 Ответ

5 голосов
/ 22 января 2013

AVFoundation - более эффективный способ визуализации анимации QuartzComposer в видеопоток H.264.


size_t width = 640;
size_t height = 480;

const char *outputFile = "/tmp/Arabesque.mp4";

QCComposition *composition = [QCComposition compositionWithFile:@"/System/Library/Screen Savers/Arabesque.qtz"];
QCRenderer *renderer = [[QCRenderer alloc] initOffScreenWithSize:NSMakeSize(width, height)
                                                      colorSpace:CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB) composition:composition];

unlink(outputFile);
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:@(outputFile)] fileType:AVFileTypeMPEG4 error:NULL];

NSDictionary *videoSettings = @{ AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : @(width), AVVideoHeightKey : @(height) };
AVAssetWriterInput* writerInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];

[videoWriter addInput:writerInput];
[writerInput release];

AVAssetWriterInputPixelBufferAdaptor *pixelBufferAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:NULL];

int framesPerSecond = 30;
int totalDuration = 30;
int totalFrameCount = framesPerSecond * totalDuration;

[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];

__block long frameNumber = 0;

dispatch_queue_t workQueue = dispatch_queue_create("com.example.work-queue", DISPATCH_QUEUE_SERIAL);

NSLog(@"Starting.");
[writerInput requestMediaDataWhenReadyOnQueue:workQueue usingBlock:^{
    while ([writerInput isReadyForMoreMediaData]) {
        NSTimeInterval frameTime = (float)frameNumber / framesPerSecond;
        if (![renderer renderAtTime:frameTime arguments:NULL]) {
            NSLog(@"Rendering failed at time %.3fs", frameTime);
            break;
        }

        CVPixelBufferRef frame = (CVPixelBufferRef)[renderer createSnapshotImageOfType:@"CVPixelBuffer"];
        [pixelBufferAdaptor appendPixelBuffer:frame withPresentationTime:CMTimeMake(frameNumber, framesPerSecond)];
        CFRelease(frame);

        frameNumber++;
        if (frameNumber >= totalFrameCount) {
            [writerInput markAsFinished];
            [videoWriter finishWriting];
            [videoWriter release];
            [renderer release];
            NSLog(@"Rendered %ld frames.", frameNumber);
            break;
        }

    }
}];

В моем тестировании это примерно вдвое быстрее, чем ваш опубликованный код, использующий QTKit. Самым большим улучшением является то, что кодирование H.264 передается в графический процессор, а не выполняется программно. Из быстрого взгляда на профиль видно, что остающиеся узкие места - это рендеринг самой композиции и считывание визуализированных данных обратно из графического процессора в буфер пикселей. Очевидно, что сложность вашей композиции будет иметь некоторое влияние на это.

Может быть возможно дополнительно оптимизировать это, используя способность QCRenderer предоставлять снимки как CVOpenGLBufferRef s, которые могут сохранять данные кадра на графическом процессоре, а не считывать их обратно, чтобы передать их кодеру. Хотя я не слишком заглядывал в это.

...