AVSampleBufferDisplayLayer without a frame is displayed

After a week of struggling, I decided to ask for help:

I've tried two approaches:

  • Just by inserting a sample (since this is a direct stream, frames appear intermittently):

    - (void)drawSample:(CMSampleBufferRef)sample {
    
        CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sample, YES);
        CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
        CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);
    
        if (CMSampleBufferIsValid(sample)) {
            NSLog(@"Valid sample: %@", sample);
        }
        else {
            NSLog(@"Invalid sample: %@", sample);
        }
    
        [self.videoLayer enqueueSampleBuffer:sample];
        [self.videoLayer setNeedsDisplay];
    
        if (self.colorIndex > 255) {
            self.colorIndex = 0;
        }
    
        self.videoLayer.backgroundColor = [UIColor colorWithWhite:self.colorIndex / 255.0f alpha:1.0f].CGColor;
    
        self.colorIndex += 1;
    }
    
          

With this approach, no frames are displayed (I added code for changing the background color for debugging purposes, which works fine).


  1. The second approach was to display the frames as if they came from an unlimited source (although still using the same direct stream).

    - (void)drawSample:(CMSampleBufferRef)sample {
    
        CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sample, YES);
        CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
        CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);
    
    
        if (CMSampleBufferIsValid(sample)) {
            NSLog(@"Valid sample");
        }
        else {
            NSLog(@"Invalid sample: %@", sample);
        }
    
        [self.videoLayer requestMediaDataWhenReadyOnQueue:self.dispatchQueue usingBlock: ^{
            while( [_videoLayer isReadyForMoreMediaData] )
            {
                if (CMSampleBufferIsValid(sample)) {
                    [_videoLayer enqueueSampleBuffer:sample];
                    CFRelease(sample);
                }
                else {
                    NSLog(@"Invalid sample inside block: %@", sample);
                }
    
            }
            NSLog(@"Layer isn't ready");
        }];
    }
    
          

Does not work. With this approach, I have 2 problems:

  • If I add CFRelease(sample);

    inside a block, the app crashes. When Zombie objects are enabled, I get the error:

    [Not A Type release]: message sent to deallocated instance 0x7fc6426a2120
    
          

    Should I store CMSampleBufferRef objects in a container and retrieve inside the AVSampleBufferDisplayLayer request media block?

  • If I don't add CFRelease(sample);

    inside the block, only the first frame will be shown and the application will eventually crash due to a memory warning (obviously).

Any idea what I am doing wrong?

NOTE. I watched the video "Direct Access Media Encoding and Decoding" from WWDC 2014 and I seem to be doing it right. I created a video format description, replaced the start code with a NAL length code, and successfully created a CMSampleBuffer.

+3


source to share





All Articles