Fix deadlock issue on Hovis

This commit is contained in:
bossiel 2015-05-26 20:05:45 +00:00
parent 1948ff4480
commit f7ca47efc6
4 changed files with 69 additions and 67 deletions

View File

@ -385,21 +385,29 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
//static int __rotation_counter = 0;
/* encode */
tsk_size_t out_size = 0;
tmedia_codec_t* codec_encoder = tsk_null;
if (!base->rtp_manager->is_started) {
TSK_DEBUG_ERROR("Not started");
return 0;
goto bail;
}
// take a reference to the encoder to make sure it'll not be destroyed while we're using it
codec_encoder = tsk_object_ref(video->encoder.codec);
if (!codec_encoder) {
TSK_DEBUG_ERROR("The encoder is null");
goto bail;
}
#define PRODUCER_OUTPUT_FIXSIZE (base->producer->video.chroma != tmedia_chroma_mjpeg) // whether the output data has a fixed size/length
#define PRODUCER_OUTPUT_RAW (base->producer->encoder.codec_id == tmedia_codec_id_none) // Otherwise, frames from the producer are already encoded
#define PRODUCER_SIZE_CHANGED ((video->conv.producerWidth && video->conv.producerWidth != base->producer->video.width) || (video->conv.producerHeight && video->conv.producerHeight != base->producer->video.height) \
|| (video->conv.xProducerSize && (video->conv.xProducerSize != size && PRODUCER_OUTPUT_FIXSIZE)))
#define ENCODED_NEED_FLIP (TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.flip)
#define ENCODED_NEED_RESIZE (base->producer->video.width != TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.width || base->producer->video.height != TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.height)
#define ENCODED_NEED_FLIP (TMEDIA_CODEC_VIDEO(codec_encoder)->out.flip)
#define ENCODED_NEED_RESIZE (base->producer->video.width != TMEDIA_CODEC_VIDEO(codec_encoder)->out.width || base->producer->video.height != TMEDIA_CODEC_VIDEO(codec_encoder)->out.height)
#define PRODUCED_FRAME_NEED_ROTATION (base->producer->video.rotation != 0)
#define PRODUCED_FRAME_NEED_MIRROR (base->producer->video.mirror != tsk_false)
#define PRODUCED_FRAME_NEED_CHROMA_CONVERSION (base->producer->video.chroma != TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.chroma)
#define PRODUCED_FRAME_NEED_CHROMA_CONVERSION (base->producer->video.chroma != TMEDIA_CODEC_VIDEO(codec_encoder)->out.chroma)
// Video codecs only accept YUV420P buffers ==> do conversion if needed or producer doesn't have the right size
if (PRODUCER_OUTPUT_RAW && (PRODUCED_FRAME_NEED_CHROMA_CONVERSION || PRODUCER_SIZE_CHANGED || ENCODED_NEED_FLIP || ENCODED_NEED_RESIZE ||PRODUCED_FRAME_NEED_ROTATION || PRODUCED_FRAME_NEED_MIRROR)) {
// Create video converter if not already done or producer size have changed
@ -410,8 +418,8 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
video->conv.xProducerSize = size;
TSK_DEBUG_INFO("producer size = (%d, %d)", (int)base->producer->video.width, (int)base->producer->video.height);
if(!(video->conv.toYUV420 = tmedia_converter_video_create(base->producer->video.width, base->producer->video.height, base->producer->video.chroma, TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.width, TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.height,
TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.chroma))){
if (!(video->conv.toYUV420 = tmedia_converter_video_create(base->producer->video.width, base->producer->video.height, base->producer->video.chroma, TMEDIA_CODEC_VIDEO(codec_encoder)->out.width, TMEDIA_CODEC_VIDEO(codec_encoder)->out.height,
TMEDIA_CODEC_VIDEO(codec_encoder)->out.chroma))){
TSK_DEBUG_ERROR("Failed to create video converter");
ret = -5;
goto bail;
@ -438,14 +446,14 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
return -1;
}
video->encoder.rotation = base->producer->video.rotation; // update rotation to avoid calling the function several times
ret = tmedia_codec_set(video->encoder.codec, param);
ret = tmedia_codec_set(codec_encoder, param);
TSK_OBJECT_SAFE_FREE(param);
// (ret != 0) -> not supported by the codec -> to be done by the converter
video->encoder.scale_rotated_frames = (ret != 0);
}
// update one-shot parameters
tmedia_converter_video_set(video->conv.toYUV420, base->producer->video.rotation, TMEDIA_CODEC_VIDEO(video->encoder.codec)->out.flip, base->producer->video.mirror, video->encoder.scale_rotated_frames);
tmedia_converter_video_set(video->conv.toYUV420, base->producer->video.rotation, TMEDIA_CODEC_VIDEO(codec_encoder)->out.flip, base->producer->video.mirror, video->encoder.scale_rotated_frames);
yuv420p_size = tmedia_converter_video_process(video->conv.toYUV420, buffer, size, &video->encoder.conv_buffer, &video->encoder.conv_buffer_size);
if (!yuv420p_size || !video->encoder.conv_buffer) {
@ -457,24 +465,24 @@ static int tdav_session_video_producer_enc_cb(const void* callback_data, const v
// Encode data
tsk_mutex_lock(video->encoder.h_mutex);
if(video->encoder.codec){ // codec is destroyed by stop() which use same mutex
if (video->started && codec_encoder->opened) { // stop() function locks the encoder mutex before changing "started"
if (video->encoder.conv_buffer && yuv420p_size) {
/* producer doesn't support yuv42p */
out_size = video->encoder.codec->plugin->encode(video->encoder.codec, video->encoder.conv_buffer, yuv420p_size, &video->encoder.buffer, &video->encoder.buffer_size);
out_size = codec_encoder->plugin->encode(codec_encoder, video->encoder.conv_buffer, yuv420p_size, &video->encoder.buffer, &video->encoder.buffer_size);
}
else {
/* producer supports yuv42p */
out_size = video->encoder.codec->plugin->encode(video->encoder.codec, buffer, size, &video->encoder.buffer, &video->encoder.buffer_size);
out_size = codec_encoder->plugin->encode(codec_encoder, buffer, size, &video->encoder.buffer, &video->encoder.buffer_size);
}
}
tsk_mutex_unlock(video->encoder.h_mutex);
if (out_size) {
/* Never called, see tdav_session_video_raw_cb() */
trtp_manager_send_rtp(base->rtp_manager, video->encoder.buffer, out_size, 6006, tsk_true, tsk_true);
}
bail: ;
bail:
TSK_OBJECT_SAFE_FREE(codec_encoder);
}
else {
TSK_DEBUG_ERROR("Invalid parameter");
@ -1102,8 +1110,11 @@ static int tdav_session_video_stop(tmedia_session_t* self)
video = (tdav_session_video_t*)self;
base = (tdav_session_av_t*)self;
// must be here to make sure not other thread will lock the encoder once we have done it
// must be here to make sure no other thread will lock the encoder once we have done it
tsk_mutex_lock(video->encoder.h_mutex); // encoder thread will check "started" var right after the lock is passed
video->started = tsk_false;
tsk_mutex_unlock(video->encoder.h_mutex);
// at this step we're sure that encode() will no longer be called which means we can safely close the codec
if (video->jb) {
ret = tdav_video_jb_stop(video->jb);
@ -1113,9 +1124,12 @@ static int tdav_session_video_stop(tmedia_session_t* self)
tsk_list_clear_items(video->avpf.packets);
tsk_list_unlock(video->avpf.packets);
// the encoder must be locked before stopping the session as such action will close all codecs
tsk_mutex_lock(video->encoder.h_mutex);
// tdav_session_av_stop() : stop producer and consumer, close encoder and all other codecs, stop rtpManager...
// no need to lock the encoder to avoid using a closed codec (see above)
// no need to lock the decoder as the rtpManager will be stop before closing the codec
// lock-free stop() may avoid deadlock issue (cannot reproduce it myself) on Hovis
ret = tdav_session_av_stop(base);
tsk_mutex_lock(video->encoder.h_mutex);
TSK_OBJECT_SAFE_FREE(video->encoder.codec);
tsk_mutex_unlock(video->encoder.h_mutex);
TSK_OBJECT_SAFE_FREE(video->decoder.codec);
@ -1324,12 +1338,12 @@ static int _tdav_session_video_init(tdav_session_video_t *p_self, tmedia_type_t
TSK_DEBUG_ERROR("Failed to create encode mutex");
return -4;
}
if (!(p_self->avpf.packets = tsk_list_create())) {
if (!p_self->avpf.packets && !(p_self->avpf.packets = tsk_list_create())) {
TSK_DEBUG_ERROR("Failed to create list");
return -2;
}
if (p_self->jb_enabled) {
if(!(p_self->jb = tdav_video_jb_create())) {
if (!p_self->jb && !(p_self->jb = tdav_video_jb_create())) {
TSK_DEBUG_ERROR("Failed to create jitter buffer");
return -3;
}

View File

@ -279,35 +279,24 @@ bail:
tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size)
{
tnet_transport_t *transport = (tnet_transport_t*)handle;
WSABUF wsaBuffer;
DWORD numberOfBytesSent = 0;
int ret = -1;
int numberOfBytesSent = 0;
if (!transport) {
TSK_DEBUG_ERROR("Invalid server handle.");
return ret;
goto bail;
}
if (!TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)) {
TSK_DEBUG_ERROR("In order to use WSASendTo you must use an udp transport.");
return ret;
TSK_DEBUG_ERROR("In order to use sendto() you must use an udp transport.");
goto bail;
}
wsaBuffer.buf = (CHAR*)buf;
wsaBuffer.len = (ULONG)size;
if ((ret = WSASendTo(from, &wsaBuffer, 1, &numberOfBytesSent, 0, to, tnet_get_sockaddr_size(to), 0, 0)) == SOCKET_ERROR){
if ((ret = WSAGetLastError()) == WSA_IO_PENDING){
TSK_DEBUG_INFO("WSA_IO_PENDING error for WSASendTo SSESSION");
ret = 0;
}
else{
TNET_PRINT_LAST_ERROR("WSASendTo have failed.");
return ret;
}
}
else ret = 0;
if ((numberOfBytesSent = tnet_sockfd_sendto(from, to, buf, size)) <= 0) {
TNET_PRINT_LAST_ERROR("sendto have failed.");
goto bail;
}
bail:
return numberOfBytesSent;
}

View File

@ -1710,7 +1710,6 @@ int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf,
}
else {
TNET_PRINT_LAST_ERROR("sendto() failed");
}
goto bail;
}