[vlc-commits] videotoolbox: make it asynchronous
Thomas Guillem
git at videolan.org
Fri Jan 20 11:22:10 CET 2017
vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Thu Jan 19 13:15:22 2017 +0100| [a94406b5deefae0c0c8a29731885d0925125b9d3] | committer: Thomas Guillem
videotoolbox: make it asynchronous
Use the new decoder_QueuePicture() call to queue pictures directly from the
VideoToolBox render callback.
Replace the NSMutableDictionary/NSMutableArray frame reordering by using a
linked list of picture_t.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a94406b5deefae0c0c8a29731885d0925125b9d3
---
modules/codec/videotoolbox.m | 225 +++++++++++++++++++++----------------------
1 file changed, 109 insertions(+), 116 deletions(-)
diff --git a/modules/codec/videotoolbox.m b/modules/codec/videotoolbox.m
index 449c2d4..be50e01 100644
--- a/modules/codec/videotoolbox.m
+++ b/modules/codec/videotoolbox.m
@@ -91,6 +91,9 @@ vlc_module_end()
static CFDataRef ESDSCreate(decoder_t *, uint8_t *, uint32_t);
static picture_t *DecodeBlock(decoder_t *, block_t **);
+static void PicReorder_pushSorted(decoder_t *, picture_t *);
+static picture_t *PicReorder_pop(decoder_t *, bool);
+static void PicReorder_flush(decoder_t *);
static void Flush(decoder_t *);
static void DecoderCallback(void *, void *, OSStatus, VTDecodeInfoFlags,
CVPixelBufferRef, CMTime, CMTime);
@@ -117,9 +120,10 @@ struct decoder_sys_t
CFMutableDictionaryRef decoderConfiguration;
CFMutableDictionaryRef destinationPixelBufferAttributes;
- vlc_mutex_t outLock;
- NSMutableArray *outputTimeStamps;
- NSMutableDictionary *outputFrames;
+ vlc_mutex_t lock;
+ picture_t *p_pic_reorder;
+ size_t i_pic_reorder;
+
bool b_zero_copy;
bool b_enable_temporal_processing;
@@ -712,19 +716,9 @@ static int OpenDecoder(vlc_object_t *p_this)
p_sys->videoFormatDescription = nil;
p_sys->decoderConfiguration = nil;
p_sys->destinationPixelBufferAttributes = nil;
-
- /* setup storage */
- p_sys->outputTimeStamps = [[NSMutableArray alloc] init];
- p_sys->outputFrames = [[NSMutableDictionary alloc] init];
- if (!p_sys->outputTimeStamps || !p_sys->outputFrames) {
- if (p_sys->outputTimeStamps)
- [p_sys->outputTimeStamps release];
- if (p_sys->outputFrames)
- [p_sys->outputFrames release];
- free(p_sys);
- return VLC_ENOMEM;
- }
- vlc_mutex_init(&p_sys->outLock);
+ p_sys->p_pic_reorder = NULL;
+ p_sys->i_pic_reorder = 0;
+ vlc_mutex_init(&p_sys->lock);
int i_ret = StartVideoToolbox(p_dec, NULL);
if (i_ret != VLC_SUCCESS) {
@@ -761,10 +755,7 @@ static void CloseDecoder(vlc_object_t *p_this)
VTDecompressionSessionWaitForAsynchronousFrames(p_sys->session);
StopVideoToolbox(p_dec);
- [p_sys->outputTimeStamps release];
- [p_sys->outputFrames release];
-
- vlc_mutex_destroy(&p_sys->outLock);
+ vlc_mutex_destroy(&p_sys->lock);
free(p_sys);
}
@@ -965,14 +956,68 @@ static void copy420YpCbCr8Planar(picture_t *p_pic,
#pragma mark - actual decoding
+static void PicReorder_pushSorted(decoder_t *p_dec, picture_t *p_pic)
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ assert(p_pic->p_next == NULL);
+ p_sys->i_pic_reorder++;
+ if (p_sys->p_pic_reorder == NULL)
+ {
+ p_sys->p_pic_reorder = p_pic;
+ return;
+ }
+
+ picture_t **pp_last = &p_sys->p_pic_reorder;
+ for (picture_t *p_cur = *pp_last; p_cur != NULL;
+ pp_last = &p_cur->p_next, p_cur = *pp_last)
+ {
+ if (p_pic->date < p_cur->date)
+ {
+ p_pic->p_next = p_cur;
+ *pp_last = p_pic;
+ return;
+ }
+ }
+ *pp_last = p_pic;
+}
+
+static picture_t *PicReorder_pop(decoder_t *p_dec, bool force)
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ if (p_sys->i_pic_reorder == 0
+ || (!force && p_sys->i_pic_reorder <= 5)) /* FIXME: calculate number of ref frames */
+ return NULL;
+
+ picture_t *p_pic = p_sys->p_pic_reorder;
+ p_sys->p_pic_reorder = p_pic->p_next;
+ p_pic->p_next = NULL;
+ p_sys->i_pic_reorder--;
+ return p_pic;
+}
+
+static void PicReorder_flush(decoder_t *p_dec)
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ for (picture_t *p_cur = p_sys->p_pic_reorder, *p_next;
+ p_cur != NULL; p_cur = p_next)
+ {
+ p_next = p_cur->p_next;
+ picture_Release(p_cur);
+ }
+ p_sys->i_pic_reorder = 0;
+ p_sys->p_pic_reorder = NULL;
+}
+
static void Flush(decoder_t *p_dec)
{
decoder_sys_t *p_sys = p_dec->p_sys;
- vlc_mutex_lock(&p_sys->outLock);
- [p_sys->outputTimeStamps removeAllObjects];
- [p_sys->outputFrames removeAllObjects];
- vlc_mutex_unlock(&p_sys->outLock);
+ vlc_mutex_lock(&p_sys->lock);
+ PicReorder_flush(p_dec);
+ vlc_mutex_unlock(&p_sys->lock);
}
static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
@@ -1071,84 +1116,6 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
skip:
*pp_block = NULL;
-
- if (unlikely(!p_sys->b_started))
- return NULL;
-
- vlc_mutex_lock(&p_sys->outLock);
- NSUInteger outputFramesCount = [p_sys->outputFrames count];
-
- if (outputFramesCount > 5) {
- CVPixelBufferRef imageBuffer;
- id imageBufferObject;
- picture_t *p_pic;
-
- NSString *timeStamp;
- [p_sys->outputTimeStamps sortUsingComparator:^(id obj1, id obj2) {
- if ([obj1 longLongValue] > [obj2 longLongValue]) {
- return (NSComparisonResult)NSOrderedDescending;
- }
- if ([obj1 longLongValue] < [obj2 longLongValue]) {
- return (NSComparisonResult)NSOrderedAscending;
- }
- return (NSComparisonResult)NSOrderedSame;
- }];
- NSMutableArray *timeStamps = p_sys->outputTimeStamps;
- timeStamp = [timeStamps firstObject];
- if (timeStamps.count > 0) {
- [timeStamps removeObjectAtIndex:0];
- }
-
- imageBufferObject = [p_sys->outputFrames objectForKey:timeStamp];
- if (imageBufferObject == NULL)
- {
- vlc_mutex_unlock(&p_sys->outLock);
- return NULL;
- }
- imageBuffer = (CVPixelBufferRef) CFBridgingRetain(imageBufferObject);
- [p_sys->outputFrames removeObjectForKey:timeStamp];
- vlc_mutex_unlock(&p_sys->outLock);
-
- if (CVPixelBufferGetDataSize(imageBuffer) == 0)
- {
- CFRelease(imageBuffer);
- return NULL;
- }
-
- if (decoder_UpdateVideoFormat(p_dec))
- return NULL;
- p_pic = decoder_NewPicture(p_dec);
- if (!p_pic)
- return NULL;
-
- if (!p_sys->b_zero_copy) {
- /* ehm, *cough*, memcpy.. */
- copy420YpCbCr8Planar(p_pic,
- imageBuffer,
- CVPixelBufferGetWidthOfPlane(imageBuffer, 0),
- CVPixelBufferGetHeightOfPlane(imageBuffer, 0));
- CFRelease(imageBuffer);
- } else {
- /* the structure is allocated by the vout's pool */
- if (p_pic->p_sys) {
- /* if we received a recycled picture from the pool
- * we need release the previous reference first,
- * otherwise we would leak it */
- if (p_pic->p_sys->pixelBuffer != nil) {
- CFRelease(p_pic->p_sys->pixelBuffer);
- p_pic->p_sys->pixelBuffer = nil;
- }
-
- p_pic->p_sys->pixelBuffer = imageBuffer;
- }
- /* will be freed by the vout */
- }
- p_pic->date = timeStamp.longLongValue;
- return p_pic;
- }
- else
- vlc_mutex_unlock(&p_sys->outLock);
-
return NULL;
}
@@ -1239,28 +1206,54 @@ static void DecoderCallback(void *decompressionOutputRefCon,
msg_Warn(p_dec, "decoding of a frame failed (%i, %u)", status, (unsigned int) infoFlags);
return;
}
+ assert(imageBuffer);
- if (infoFlags & kVTDecodeInfo_FrameDropped) {
+ if (infoFlags & kVTDecodeInfo_FrameDropped)
+ {
msg_Dbg(p_dec, "decoder dropped frame");
- if (imageBuffer)
- CFRelease(imageBuffer);
return;
}
- if (!imageBuffer)
+ if (!CMTIME_IS_VALID(pts))
return;
- if (!CMTIME_IS_VALID(pts)) {
- msg_Dbg(p_dec, "invalid timestamp, dropping frame");
- CFRelease(imageBuffer);
+ if (CVPixelBufferGetDataSize(imageBuffer) == 0)
return;
- }
- NSNumber *timeStamp = [NSNumber numberWithLongLong:pts.value];
- id imageBufferObject = (__bridge id)imageBuffer;
+ picture_t *p_pic = decoder_NewPicture(p_dec);
+ if (!p_pic)
+ return;
- vlc_mutex_lock(&p_sys->outLock);
- [p_sys->outputTimeStamps addObject:timeStamp];
- [p_sys->outputFrames setObject:imageBufferObject forKey:timeStamp];
- vlc_mutex_unlock(&p_sys->outLock);
+ p_pic->date = pts.value;
+ p_pic->b_progressive = true;
+
+ if (!p_sys->b_zero_copy) {
+ /* ehm, *cough*, memcpy.. */
+ copy420YpCbCr8Planar(p_pic,
+ imageBuffer,
+ CVPixelBufferGetWidthOfPlane(imageBuffer, 0),
+ CVPixelBufferGetHeightOfPlane(imageBuffer, 0));
+ } else {
+ /* the structure is allocated by the vout's pool */
+ if (p_pic->p_sys) {
+ /* if we received a recycled picture from the pool
+ * we need release the previous reference first,
+ * otherwise we would leak it */
+ if (p_pic->p_sys->pixelBuffer != nil) {
+ CFRelease(p_pic->p_sys->pixelBuffer);
+ p_pic->p_sys->pixelBuffer = nil;
+ }
+
+ /* will be freed by the vout */
+ p_pic->p_sys->pixelBuffer = CVPixelBufferRetain(imageBuffer);
+ }
+ }
+ vlc_mutex_lock(&p_sys->lock);
+ PicReorder_pushSorted(p_dec, p_pic);
+ p_pic = PicReorder_pop(p_dec, false);
+ vlc_mutex_unlock(&p_sys->lock);
+
+ if (p_pic != NULL)
+ decoder_QueueVideo(p_dec, p_pic);
+ return;
}
More information about the vlc-commits
mailing list