5

AVSampleBufferDisplayLayer でいくつかの CMSampleBuffer を表示したいのですが、最初のサンプルを表示した後にフリーズします。

AVCaptureVideoDataOutputSampleBuffer デリゲートからサンプルバッファーを取得します。

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    CFRetain(sampleBuffer);
    [self imageToBuffer:sampleBuffer];
    CFRelease(sampleBuffer);
}

それらをベクトルに入れます

-(void) imageToBuffer: (CMSampleBufferRef )source{
//buffers is defined as: std::vector<CMSampleBufferRef> buffers;
        CMSampleBufferRef newRef;
        CMSampleBufferCreateCopy(kCFAllocatorDefault, source, &newRef);
        buffers.push_back(newRef);
}

次に、AVSampleBufferDisplayLayer (別の ViewController) を介してそれらを表示してみてください

AVSampleBufferDisplayLayer * displayLayer = [[AVSampleBufferDisplayLayer alloc] init];

    displayLayer.bounds = self.view.bounds;
    displayLayer.position = CGPointMake(CGRectGetMidX(self.displayOnMe.bounds), CGRectGetMidY(self.displayOnMe.bounds));
    displayLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    displayLayer.backgroundColor = [[UIColor greenColor] CGColor];

    [self.view.layer addSublayer:displayLayer];
    self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    dispatch_queue_t queue = dispatch_queue_create("My queue", DISPATCH_QUEUE_SERIAL);
    [displayLayer setNeedsDisplay];
    [displayLayer requestMediaDataWhenReadyOnQueue:queue
                                        usingBlock:^{
                                            while ([displayLayer isReadyForMoreMediaData]) {

                                                if (samplesKey < buffers.size()) {
                                                    CMSampleBufferRef buf = buffers[samplesKey];
                                                    [displayLayer enqueueSampleBuffer:buffers[samplesKey]];
                                                    samplesKey++;

                                                }else
                                                {
                                                    [displayLayer stopRequestingMediaData];
                                                    break;
                                                }
                                            }

                                        }];

しかし、最初のサンプルがフリーズし、何もしないことを示しています。

そして、私のビデオデータ出力設定は次のとおりです。

//set up our output
self.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
dispatch_queue_t queue = dispatch_queue_create("VideoQueue", DISPATCH_QUEUE_SERIAL);
[_videoDataOutput setSampleBufferDelegate:self queue:queue];
[_videoDataOutput setVideoSettings:[NSDictionary dictionaryWithObjectsAndKeys:
                                                [NSNumber numberWithInt:kCVPixelFormatType_32BGRA],(id)kCVPixelBufferPixelFormatTypeKey,
                                                nil]]; 
4

1 に答える 1

5

同じコンテキストでこの問題に遭遇し、AVCaptureVideoDataOutput から出力を取得して AVSampleDisplay レイヤーに表示しようとしました。

フレームが表示順に出てくる場合、修正は非常に簡単です。CMSampleBufferRef ですぐに表示フラグを設定するだけです。

デリゲートから返されたサンプル バッファを取得してから...

CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);

CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);

フレームが (表示順ではなく) エンコーダー順で出力される場合、CMSampleBuffer のタイムスタンプは、最初のフレームのタイムスタンプが時間 0 に等しくなるようにゼロ バイアスおよびリスタンプする必要があります。

 double pts = CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer));

 // ptsStart is equal to the first frames presentationTimeStamp so playback starts from time 0.
 CMTime presentationTimeStamp = CMTimeMake((pts-ptsStart)*1000000,1000000);

 CMSampleBufferSetOutputPresentationTimeStamp(sampleBuffer, presentationTimeStamp);

アップデート:

ゼロ バイアス方式を使用しても一部のビデオがまだスムーズに再生されない状況に遭遇し、さらに調査しました。プレイする最初のフレームからのPTSを使用するのが正解のようです。

私の答えはここにありますが、ここにも投稿します。

AVSampleBufferDisplayLayer がサンプル バッファをレンダリングする速度を設定します

タイムベースは、デコードする最初のフレームのプレゼンテーション タイム スタンプ (pts) に設定する必要があります。後続のすべてのポイントから最初のポイントを減算し、タイムベースを 0 に設定することで、最初のフレームのポイントを 0 にインデックス付けしていました。何らかの理由で、特定のビデオでは機能しませんでした。

次のようなものが必要です ( decode の呼び出しの前に呼び出されます):

CMTimebaseRef controlTimebase;
CMTimebaseCreateWithMasterClock( CFAllocatorGetDefault(), CMClockGetHostTimeClock(), &controlTimebase );

displayLayer.controlTimebase = controlTimebase;

// Set the timebase to the initial pts here
CMTimebaseSetTime(displayLayer.controlTimebase, CMTimeMake(ptsInitial, 1));
CMTimebaseSetRate(displayLayer.controlTimebase, 1.0);

CMSampleBuffer の PTS を設定します...

CMSampleBufferSetOutputPresentationTimeStamp(sampleBuffer, presentationTimeStamp);

そしておそらく、表示がすぐに設定されていないことを確認してください....

CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanFalse);

これは、WWDC 2014 セッション 513 で非常に簡単に説明されています。

于 2015-11-09T19:53:15.117 に答える