Кодирование сеанса сжатия H.264 с помощью CGDisplayStream

Я пытаюсь создать сеанс сжатия H.264 с данными с моего экрана. Я создал экземпляр CGDisplayStreamRef следующим образом:

displayStream = CGDisplayStreamCreateWithDispatchQueue(0, 100, 100, k32BGRAPixelFormat, nil, self.screenCaptureQueue, ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) {
    //Call encoding session here
});

Ниже показано, как в настоящее время у меня настроена функция кодирования:

- (void) encode:(CMSampleBufferRef )sampleBuffer {
    CVImageBufferRef imageBuffer = (CVImageBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
    CMTime presentationTimeStamp = CMTimeMake(frameID++, 1000);
    VTEncodeInfoFlags flags;
    OSStatus statusCode = VTCompressionSessionEncodeFrame(EncodingSession,
                                                          imageBuffer,
                                                          presentationTimeStamp,
                                                          kCMTimeInvalid,
                                                          NULL, NULL, &flags);
    if (statusCode != noErr) {
        NSLog(@"H264: VTCompressionSessionEncodeFrame failed with %d", (int)statusCode);

        VTCompressionSessionInvalidate(EncodingSession);
        CFRelease(EncodingSession);
        EncodingSession = NULL;
        return;
    }
    NSLog(@"H264: VTCompressionSessionEncodeFrame Success");
}

Я пытаюсь понять, как я могу преобразовать данные с моего экрана в CMSampleBufferRef, чтобы я мог правильно вызвать свою функцию кодирования. До сих пор я не смог определить, возможно ли это или правильный подход к тому, что я пытаюсь сделать. У кого-нибудь есть предложения?

EDIT: я преобразовал IOSurface в CMBlockBuffer, но еще не понял, как преобразовать его в CMSampleBufferRef:

void *mem = IOSurfaceGetBaseAddress(frameSurface);
size_t bytesPerRow = IOSurfaceGetBytesPerRow(frameSurface);
size_t height = IOSurfaceGetHeight(frameSurface);
size_t totalBytes = bytesPerRow * height;

CMBlockBufferRef blockBuffer;

CMBlockBufferCreateWithMemoryBlock(kCFAllocatorNull, mem, totalBytes, kCFAllocatorNull, NULL, 0, totalBytes, 0, &blockBuffer);

ИЗМЕНИТЬ 2

Еще немного прогресса:

CMSampleBufferRef *sampleBuffer;

OSStatus sampleStatus = CMSampleBufferCreate(
                             NULL, blockBuffer, TRUE, NULL, NULL,
                             NULL, 1, 1, NULL,
                             0, NULL, sampleBuffer);

[self encode:*sampleBuffer];

person narner    schedule 10.03.2017    source источник


Ответы (1)


Возможно, я немного опоздал, но тем не менее, это может быть полезно для других:

CGDisplayStreamCreateWithDispatchQueue(CGMainDisplayID(), 100, 100, k32BGRAPixelFormat, nil, self.screenCaptureQueue, ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) {
    // The created pixel buffer retains the surface object.
    CVPixelBufferRef pixelBuffer;
    CVPixelBufferCreateWithIOSurface(NULL, frameSurface, NULL, &pixelBuffer);

    // Create the video-type-specific description for the pixel buffer.
    CMVideoFormatDescriptionRef videoFormatDescription;
    CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixelBuffer, &videoFormatDescription);

    // All the necessary parts for creating a `CMSampleBuffer` are ready.
    CMSampleBufferRef sampleBuffer;
    CMSampleTimingInfo timingInfo;
    CMSampleBufferCreateReadyWithImageBuffer(NULL, pixelBuffer, videoFormatDescription, &timingInfo, &sampleBuffer);

    // Do the stuff

    // Release the resources to let the frame surface be reused in the queue
    // `kCGDisplayStreamQueueDepth` is responsible for the size of the queue 
    CFRelease(sampleBuffer);
    CFRelease(pixelBuffer);
});
person Dmytro Hutsuliak    schedule 17.05.2017