Кодирование сеанса сжатия 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
так что я могу правильно вызвать мою функцию кодирования. До сих пор я не смог определить, возможно ли это, или правильный подход к тому, что я пытаюсь сделать. У кого-нибудь есть предложения?
РЕДАКТИРОВАТЬ: я получил мой 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];
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);
});