7

私が現在コーディングしているココア アプリケーションでは、Quartz Composer レンダラー (NSImage オブジェクト) からスナップショット イメージを取得しており、addImage を使用して 720*480 サイズ、25 fps、および H264 コーデックで QTMovie にエンコードしたいと考えています。 : 方法。対応するコードは次のとおりです。

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 でリアルタイムで画像をエンコードでき、同じコンピューターで私が使用するものよりもさらに高い品質であることがわかっています。 .

なぜ ?ここで何が問題なのですか?これはハードウェア管理の問題 (マルチコア スレッディング、GPU など) ですか、それとも何か不足していますか? 序文として、私は Apple 開発の世界で、Objective-C、cocoa、X コード、Quicktime、Quartz Composer ライブラリなどの新人 (2 週間の練習) であることを前置きさせてください。

助けてくれてありがとう

4

1 に答える 1

5

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 を使用するコードの約 2 倍の速さです。最大の改善は、H.264 エンコーディングがソフトウェアで実行されるのではなく、GPU に渡されたことによるものと思われます。プロファイルをざっと見てみると、残りのボトルネックはコンポジション自体のレンダリングと、レンダリングされたデータを GPU からピクセル バッファーに読み込むことであることがわかります。明らかに、構成の複雑さがこれに何らかの影響を与えます。

QCRendererスナップショットを として提供する の機能を使用することで、これをさらに最適化できる可能性があります。これによりCVOpenGLBufferRef、フレームのデータを読み取ってエンコーダーに渡すのではなく、GPU に保持することができます。しかし、私はそれについてあまり詳しく見ていませんでした。

于 2013-01-22T11:55:03.540 に答える