Почему мое приложение для кодирования изображений на основе QTKit работает так медленно?

#cocoa #macos #qtkit #quartz-composer

#cocoa #macos #qtkit #quartz-composer

Вопрос:

в приложении cocoa, которое я в настоящее время кодирую, я получаю моментальные изображения из средства визуализации 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. Вы уверены, что хотите 720×480 со скоростью 25 кадров в секунду? Разве это не должно быть 720×480 при 29,97 кадрах в секунду или 720×576 при 25 кадрах в секунду? Я сомневаюсь, что это исправит вашу проблему со скоростью, но это кажется странным форматом.

Ответ №1:

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 файлов, которые могут сохранять данные кадра на графическом процессоре, а не считывать их обратно для передачи кодировщику. Впрочем, я не стал заходить слишком далеко в этом вопросе.