[vlc-commits] codec: videotoolbox: handle errors from callback too
Thomas Guillem
git at videolan.org
Wed Sep 27 19:17:00 CEST 2017
vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Wed Sep 27 16:29:52 2017 +0200| [efbdf5fb236c88ffe6282524565159d596a6e02b] | committer: Thomas Guillem
codec: videotoolbox: handle errors from callback too
Some errors are only triggered from the decoder callback and not from the
VTDecompressionSessionDecodeFrame() function. We need to handle them in both
places.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=efbdf5fb236c88ffe6282524565159d596a6e02b
---
modules/codec/videotoolbox.m | 136 ++++++++++++++++++++++++++++---------------
1 file changed, 90 insertions(+), 46 deletions(-)
diff --git a/modules/codec/videotoolbox.m b/modules/codec/videotoolbox.m
index 931c20a6e9..29ba7ee081 100644
--- a/modules/codec/videotoolbox.m
+++ b/modules/codec/videotoolbox.m
@@ -91,11 +91,19 @@ vlc_module_end()
#pragma mark - local prototypes
+enum vtsession_status
+{
+ VTSESSION_STATUS_OK,
+ VTSESSION_STATUS_RESTART,
+ VTSESSION_STATUS_RESTART_DECAGAIN,
+ VTSESSION_STATUS_ABORT,
+};
+
static int SetH264DecoderInfo(decoder_t *, CFMutableDictionaryRef);
static CFMutableDictionaryRef ESDSExtradataInfoCreate(decoder_t *, uint8_t *, uint32_t);
static CFMutableDictionaryRef ExtradataInfoCreate(CFStringRef, void *, size_t);
static CFMutableDictionaryRef H264ExtradataInfoCreate(const struct hxxx_helper *hh);
-static int HandleVTStatus(decoder_t *, OSStatus);
+static int HandleVTStatus(decoder_t *, OSStatus, enum vtsession_status *);
static int DecodeBlock(decoder_t *, block_t *);
static void Flush(decoder_t *);
static void DecoderCallback(void *, void *, OSStatus, VTDecodeInfoFlags,
@@ -145,7 +153,9 @@ struct decoder_sys_t
bool b_handle_deint;
bool b_format_propagated;
- bool b_abort;
+
+ enum vtsession_status vtsession_status;
+
int i_forced_cvpx_format;
poc_context_t pocctx;
@@ -801,7 +811,7 @@ static int StartVideoToolbox(decoder_t *p_dec)
CFRelease(decoderConfiguration);
CFRelease(destinationPixelBufferAttributes);
- if (HandleVTStatus(p_dec, status) != VLC_SUCCESS)
+ if (HandleVTStatus(p_dec, status, NULL) != VLC_SUCCESS)
return VLC_EGENERIC;
/* Check if the current session supports deinterlacing and temporal
@@ -953,7 +963,7 @@ static int OpenDecoder(vlc_object_t *p_this)
p_sys->b_invalid_pic_reorder_max = false;
p_sys->b_poc_based_reorder = false;
p_sys->b_format_propagated = false;
- p_sys->b_abort = false;
+ p_sys->vtsession_status = VTSESSION_STATUS_OK;
p_sys->b_enable_temporal_processing =
var_InheritBool(p_dec, "videotoolbox-temporal-deinterlacing");
@@ -1278,7 +1288,8 @@ static CMSampleBufferRef VTSampleBufferCreate(decoder_t *p_dec,
return sample_buf;
}
-static int HandleVTStatus(decoder_t *p_dec, OSStatus status)
+static int HandleVTStatus(decoder_t *p_dec, OSStatus status,
+ enum vtsession_status * p_vtsession_status)
{
#define VTERRCASE(x) \
case x: msg_Err(p_dec, "vt session error: '" #x "'"); break;
@@ -1325,6 +1336,28 @@ static int HandleVTStatus(decoder_t *p_dec, OSStatus status)
msg_Err(p_dec, "unknown vt session error (%i)", (int)status);
}
#undef VTERRCASE
+
+ if (p_vtsession_status)
+ {
+ switch (status)
+ {
+ case -8960 /* codecErr */:
+ case kCVReturnInvalidArgument:
+ case kVTVideoDecoderMalfunctionErr:
+ *p_vtsession_status = VTSESSION_STATUS_ABORT;
+ break;
+ case -8969 /* codecBadDataErr */:
+ case kVTVideoDecoderBadDataErr:
+ *p_vtsession_status = VTSESSION_STATUS_RESTART_DECAGAIN;
+ break;
+ case kVTInvalidSessionErr:
+ *p_vtsession_status = VTSESSION_STATUS_RESTART;
+ break;
+ default:
+ *p_vtsession_status = VTSESSION_STATUS_OK;
+ break;
+ }
+ }
return VLC_EGENERIC;
}
@@ -1378,10 +1411,23 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
vlc_mutex_lock(&p_sys->lock);
p_sys->b_vt_flush = false;
- if (p_sys->b_abort) { /* abort from output thread (DecoderCallback) */
+ if (p_sys->vtsession_status == VTSESSION_STATUS_RESTART)
+ {
+ msg_Warn(p_dec, "restarting vt session (dec callback failed)");
+
+ vlc_mutex_unlock(&p_sys->lock);
+ int ret = RestartVideoToolbox(p_dec, true);
+ vlc_mutex_lock(&p_sys->lock);
+
+ p_sys->vtsession_status = ret == VLC_SUCCESS ? VTSESSION_STATUS_OK
+ : VTSESSION_STATUS_ABORT;
+ }
+
+ if (p_sys->vtsession_status == VTSESSION_STATUS_ABORT)
+ {
vlc_mutex_unlock(&p_sys->lock);
/* Add an empty variable so that videotoolbox won't be loaded again for
- * this ES */
+ * this ES */
var_Create(p_dec, "videotoolbox-failed", VLC_VAR_VOID);
return VLCDEC_RELOAD;
}
@@ -1415,7 +1461,7 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
if (!p_sys->session ||
VideoToolboxNeedsToRestartH264(p_dec,p_sys->session, &p_sys->hh))
{
- if(p_sys->session)
+ if (p_sys->session)
{
msg_Dbg(p_dec, "SPS/PPS changed: draining H264 decoder");
Drain(p_dec);
@@ -1457,7 +1503,9 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
OSStatus status =
VTDecompressionSessionDecodeFrame(p_sys->session, sampleBuffer,
decoderFlags, p_info, &flagOut);
- if (HandleVTStatus(p_dec, status) == VLC_SUCCESS)
+
+ enum vtsession_status vtsession_status;
+ if (HandleVTStatus(p_dec, status, &vtsession_status) == VLC_SUCCESS)
{
p_sys->b_vt_feed = true;
if( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE )
@@ -1465,43 +1513,36 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
}
else
{
- bool b_abort = false;
- switch (status)
+ if (vtsession_status == VTSESSION_STATUS_RESTART
+ || vtsession_status == VTSESSION_STATUS_RESTART_DECAGAIN)
{
- case -8960 /* codecErr */:
- case kCVReturnInvalidArgument:
- case kVTVideoDecoderMalfunctionErr:
- b_abort = true;
- break;
- case -8969 /* codecBadDataErr */:
- case kVTVideoDecoderBadDataErr:
- if (RestartVideoToolbox(p_dec, true) == VLC_SUCCESS)
- {
- /* Duplicate p_info since it is or will be freed by the
- * Decoder Callback */
- p_info = CreateReorderInfo(p_dec, p_block);
- if (likely(p_info))
- status = VTDecompressionSessionDecodeFrame(p_sys->session,
- sampleBuffer, decoderFlags, p_info, &flagOut);
-
- }
+ int ret = RestartVideoToolbox(p_dec, true);
+ if (ret == VLC_SUCCESS
+ && vtsession_status == VTSESSION_STATUS_RESTART_DECAGAIN)
+ {
+ /* Duplicate p_info since it is or will be freed by the
+ * Decoder Callback */
+ p_info = CreateReorderInfo(p_dec, p_block);
+ if (likely(p_info))
+ status = VTDecompressionSessionDecodeFrame(p_sys->session,
+ sampleBuffer, decoderFlags, p_info, &flagOut);
if (status != 0)
- b_abort = true;
- break;
- case kVTInvalidSessionErr:
- if (RestartVideoToolbox(p_dec, true) != VLC_SUCCESS)
- b_abort = true;
- break;
+ ret = VLC_EGENERIC;
+ }
+ if (ret != VLC_SUCCESS) /* restart failed, abort */
+ vtsession_status = VTSESSION_STATUS_ABORT;
}
- if (b_abort)
+ vlc_mutex_lock(&p_sys->lock);
+ if (vtsession_status == VTSESSION_STATUS_ABORT)
{
msg_Err(p_dec, "decoder failure, Abort.");
/* The decoder module will be reloaded next time since we already
* modified the input block */
- vlc_mutex_lock(&p_sys->lock);
- p_dec->p_sys->b_abort = true;
- vlc_mutex_unlock(&p_sys->lock);
+ p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
}
+ else /* reset status set by the decoder callback during restart */
+ p_sys->vtsession_status = VTSESSION_STATUS_OK;
+ vlc_mutex_unlock(&p_sys->lock);
}
CFRelease(sampleBuffer);
@@ -1567,7 +1608,7 @@ static int UpdateVideoFormat(decoder_t *p_dec, CVPixelBufferRef imageBuffer)
assert(CVPixelBufferIsPlanar(imageBuffer) == false);
break;
default:
- p_dec->p_sys->b_abort = true;
+ p_dec->p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
return -1;
}
return decoder_UpdateVideoFormat(p_dec);
@@ -1590,23 +1631,26 @@ static void DecoderCallback(void *decompressionOutputRefCon,
if (p_sys->b_vt_flush)
goto end;
- if (HandleVTStatus(p_dec, status) != VLC_SUCCESS)
+ enum vtsession_status vtsession_status;
+ if (HandleVTStatus(p_dec, status, &vtsession_status) != VLC_SUCCESS)
{
- if (status == kVTVideoDecoderMalfunctionErr)
- p_dec->p_sys->b_abort = true;
- msg_Warn(p_dec, "decoding of a frame failed (%i, %u)", (int)status,
- (unsigned int) infoFlags);
+ /* Can't decode again from here */
+ if (vtsession_status == VTSESSION_STATUS_RESTART_DECAGAIN)
+ vtsession_status = VTSESSION_STATUS_RESTART;
+
+ if (p_sys->vtsession_status != VTSESSION_STATUS_ABORT)
+ p_sys->vtsession_status = vtsession_status;
goto end;
}
assert(imageBuffer);
if (unlikely(!imageBuffer))
{
msg_Err(p_dec, "critical: null imageBuffer with a valid status");
- p_dec->p_sys->b_abort = true;
+ p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
goto end;
}
- if (p_dec->p_sys->b_abort)
+ if (p_sys->vtsession_status == VTSESSION_STATUS_ABORT)
goto end;
if (unlikely(!p_sys->b_format_propagated)) {
More information about the vlc-commits
mailing list