Request an IDR frame and reset the decoder if the decoder breaks

This commit is contained in:
Cameron Gutman
2015-01-09 18:02:18 -05:00
parent c1a1dbe881
commit f7fdd7cb45
3 changed files with 67 additions and 29 deletions
+15 -13
View File
@@ -48,22 +48,24 @@ void DrSetup(int width, int height, int fps, void* context, int drFlags)
{ {
} }
void DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
{ {
int offset = 0;
unsigned char* data = (unsigned char*) malloc(decodeUnit->fullLength); unsigned char* data = (unsigned char*) malloc(decodeUnit->fullLength);
if (data != NULL) { if (data == NULL) {
int offset = 0; // A frame was lost due to OOM condition
return DR_NEED_IDR;
PLENTRY entry = decodeUnit->bufferList;
while (entry != NULL) {
memcpy(&data[offset], entry->data, entry->length);
offset += entry->length;
entry = entry->next;
}
// This function will take our buffer
[renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
} }
PLENTRY entry = decodeUnit->bufferList;
while (entry != NULL) {
memcpy(&data[offset], entry->data, entry->length);
offset += entry->length;
entry = entry->next;
}
// This function will take our buffer
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
} }
void DrStart(void) void DrStart(void)
+1 -1
View File
@@ -16,6 +16,6 @@
- (void)updateBufferForRange:(CMBlockBufferRef)existingBuffer data:(unsigned char *)data offset:(int)offset length:(int)nalLength; - (void)updateBufferForRange:(CMBlockBufferRef)existingBuffer data:(unsigned char *)data offset:(int)offset length:(int)nalLength;
- (void)submitDecodeBuffer:(unsigned char *)data length:(int)length; - (int)submitDecodeBuffer:(unsigned char *)data length:(int)length;
@end @end
+51 -15
View File
@@ -8,7 +8,11 @@
#import "VideoDecoderRenderer.h" #import "VideoDecoderRenderer.h"
#include "Limelight.h"
@implementation VideoDecoderRenderer { @implementation VideoDecoderRenderer {
UIView *_view;
AVSampleBufferDisplayLayer* displayLayer; AVSampleBufferDisplayLayer* displayLayer;
Boolean waitingForSps, waitingForPps; Boolean waitingForSps, waitingForPps;
@@ -16,20 +20,39 @@
CMVideoFormatDescriptionRef formatDesc; CMVideoFormatDescriptionRef formatDesc;
} }
- (void)reinitializeDisplayLayer
{
if (displayLayer != nil) {
[displayLayer removeFromSuperlayer];
}
displayLayer = [[AVSampleBufferDisplayLayer alloc] init];
displayLayer.bounds = _view.bounds;
displayLayer.backgroundColor = [UIColor blackColor].CGColor;
displayLayer.position = CGPointMake(CGRectGetMidX(_view.bounds), CGRectGetMidY(_view.bounds));
displayLayer.videoGravity = AVLayerVideoGravityResizeAspect;
[_view.layer addSublayer:displayLayer];
// We need some parameter sets before we can properly start decoding frames
waitingForSps = true;
spsData = nil;
waitingForPps = true;
ppsData = nil;
if (formatDesc != nil) {
CFRelease(formatDesc);
formatDesc = nil;
}
}
- (id)initWithView:(UIView*)view - (id)initWithView:(UIView*)view
{ {
self = [super init]; self = [super init];
displayLayer = [[AVSampleBufferDisplayLayer alloc] init]; _view = view;
displayLayer.bounds = view.bounds;
displayLayer.backgroundColor = [UIColor blackColor].CGColor;
displayLayer.position = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds));
displayLayer.videoGravity = AVLayerVideoGravityResizeAspect;
[view.layer addSublayer:displayLayer];
// We need some parameter sets before we can properly start decoding frames [self reinitializeDisplayLayer];
waitingForSps = true;
waitingForPps = true;
return self; return self;
} }
@@ -107,11 +130,22 @@
} }
// This function must free data // This function must free data
- (void)submitDecodeBuffer:(unsigned char *)data length:(int)length - (int)submitDecodeBuffer:(unsigned char *)data length:(int)length
{ {
unsigned char nalType = data[FRAME_START_PREFIX_SIZE] & 0x1F; unsigned char nalType = data[FRAME_START_PREFIX_SIZE] & 0x1F;
OSStatus status; OSStatus status;
// Check for previous decoder errors before doing anything
if (displayLayer.status == AVQueuedSampleBufferRenderingStatusFailed) {
NSLog(@"Display layer rendering failed: %@", displayLayer.error);
// Recreate the display layer
[self reinitializeDisplayLayer];
// Request an IDR frame to initialize the new decoder
return DR_NEED_IDR;
}
if (nalType == NAL_TYPE_SPS || nalType == NAL_TYPE_PPS) { if (nalType == NAL_TYPE_SPS || nalType == NAL_TYPE_PPS) {
if (nalType == NAL_TYPE_SPS) { if (nalType == NAL_TYPE_SPS) {
NSLog(@"Got SPS"); NSLog(@"Got SPS");
@@ -148,19 +182,19 @@
free(data); free(data);
// No frame data to submit for these NALUs // No frame data to submit for these NALUs
return; return DR_OK;
} }
if (formatDesc == NULL) { if (formatDesc == NULL) {
// Can't decode if we haven't gotten our parameter sets yet // Can't decode if we haven't gotten our parameter sets yet
free(data); free(data);
return; return DR_OK;
} }
if (nalType != 0x1 && nalType != 0x5) { if (nalType != 0x1 && nalType != 0x5) {
// Don't submit parameter set data // Don't submit parameter set data
free(data); free(data);
return; return DR_OK;
} }
// Now we're decoding actual frame data here // Now we're decoding actual frame data here
@@ -170,7 +204,7 @@
if (status != noErr) { if (status != noErr) {
NSLog(@"CMBlockBufferCreateEmpty failed: %d", (int)status); NSLog(@"CMBlockBufferCreateEmpty failed: %d", (int)status);
free(data); free(data);
return; return DR_NEED_IDR;
} }
int lastOffset = -1; int lastOffset = -1;
@@ -205,7 +239,7 @@
if (status != noErr) { if (status != noErr) {
NSLog(@"CMSampleBufferCreate failed: %d", (int)status); NSLog(@"CMSampleBufferCreate failed: %d", (int)status);
CFRelease(blockBuffer); CFRelease(blockBuffer);
return; return DR_NEED_IDR;
} }
CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES); CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
@@ -229,6 +263,8 @@
// Dereference the buffers // Dereference the buffers
CFRelease(blockBuffer); CFRelease(blockBuffer);
CFRelease(sampleBuffer); CFRelease(sampleBuffer);
return DR_OK;
} }
@end @end