--- old/modules/media/src/main/native/gstreamer/plugins/avcdecoder/avcdecoder.c 2014-03-21 17:46:34.000000000 +0400 +++ new/modules/media/src/main/native/gstreamer/plugins/avcdecoder/avcdecoder.c 2014-03-21 17:46:33.000000000 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -253,7 +253,7 @@ CVImageBufferRef imageBuffer) { AvcDecoder *decode = AVCDECODER (userData); - + if(decode->is_flushing) { return; @@ -312,14 +312,15 @@ return; } + GstBuffer* buf = NULL; + if (isGap) { // Push a flagged, empty buffer it there is a problem. - GstBuffer* buf = gst_buffer_new(); + buf = gst_buffer_new(); GST_BUFFER_TIMESTAMP(buf) = timestamp; GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_GAP); - g_queue_insert_sorted(decode->ordered_frames, buf, avcdecoder_buffer_compare, NULL); } else { @@ -338,11 +339,9 @@ gst_structure_set(caps_struct, "line_stride", G_TYPE_INT, (int)bytes_per_row, NULL); decode->is_stride_set = TRUE; } - gboolean is_buffer_enqueued = FALSE; if (kCVReturnSuccess == CVPixelBufferLockBaseAddress (imageBuffer, 0)) { void* image_data = CVPixelBufferGetBaseAddress(imageBuffer); - GstBuffer* buf; if (GST_FLOW_OK == gst_pad_alloc_buffer_and_set_caps (srcpad, 0, bytes_per_row*height, GST_PAD_CAPS(srcpad), &buf)) @@ -351,9 +350,6 @@ memcpy (buffer_data, image_data, GST_BUFFER_SIZE (buf)); GST_BUFFER_TIMESTAMP(buf) = timestamp; - - g_queue_insert_sorted(decode->ordered_frames, buf, avcdecoder_buffer_compare, NULL); - is_buffer_enqueued = TRUE; } CVPixelBufferUnlockBaseAddress (imageBuffer, 0); // ignore return value @@ -361,15 +357,20 @@ CVBufferRelease(imageBuffer); - if (!is_buffer_enqueued) + if (!buf) { - GstBuffer* buf = gst_buffer_new(); + buf = gst_buffer_new(); GST_BUFFER_TIMESTAMP(buf) = timestamp; GST_BUFFER_FLAG_SET(buf, GST_BUFFER_FLAG_GAP); - g_queue_insert_sorted(decode->ordered_frames, buf, avcdecoder_buffer_compare, NULL); } } + // the callback might be called from several threads + // need to synchronize ordered_frames queue access + g_mutex_lock(decode->mutex); + + g_queue_insert_sorted(decode->ordered_frames, buf, avcdecoder_buffer_compare, NULL); + GstBuffer* frame; GstFlowReturn ret = GST_FLOW_OK; while(ret == GST_FLOW_OK && !decode->is_flushing && NULL != (frame = g_queue_peek_head(decode->ordered_frames))) @@ -379,6 +380,9 @@ ts <= decode->previous_timestamp + decode->timestamp_ceil || // frame is at next timestamp (0 == deltaFlag && ts < timestamp)) // have newer I-frame { + decode->previous_timestamp = ts; + g_queue_pop_head(decode->ordered_frames); + if(GST_BUFFER_FLAG_IS_SET(frame, GST_BUFFER_FLAG_GAP)) { // INLINE - gst_buffer_unref() @@ -391,16 +395,20 @@ GST_BUFFER_FLAG_SET(frame, GST_BUFFER_FLAG_DISCONT); decode->is_newsegment = FALSE; } + + // it's better not to call gst_pad_push under mutex to avoid deadlocks + g_mutex_unlock(decode->mutex); ret = gst_pad_push(decode->srcpad, frame); + g_mutex_lock(decode->mutex); } - decode->previous_timestamp = ts; - g_queue_pop_head(decode->ordered_frames); } else { break; } } + + g_mutex_unlock(decode->mutex); } /* @@ -432,6 +440,7 @@ decode->is_stride_set = FALSE; decode->frame_duration = GST_CLOCK_TIME_NONE; decode->ordered_frames = g_queue_new(); + decode->mutex = g_mutex_new(); decode->segment_start = 0; } @@ -453,6 +462,8 @@ #endif } + g_mutex_lock(decode->mutex); + // Unref all sorted buffers and clear the associated queue. if (NULL != decode->ordered_frames) { @@ -462,6 +473,8 @@ decode->is_newsegment = FALSE; decode->segment_start = 0; + + g_mutex_unlock(decode->mutex); } /** @@ -491,6 +504,8 @@ { g_queue_free(decode->ordered_frames); decode->ordered_frames = NULL; + g_mutex_free(decode->mutex); + decode->mutex = NULL; } } --- old/modules/media/src/main/native/gstreamer/plugins/avcdecoder/avcdecoder.h 2014-03-21 17:46:35.000000000 +0400 +++ new/modules/media/src/main/native/gstreamer/plugins/avcdecoder/avcdecoder.h 2014-03-21 17:46:35.000000000 +0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,6 +66,7 @@ GstClockTime frame_duration; // the duration of a single video frame (nsec) GQueue* ordered_frames; // decoded frames sorted into order of increasign time stamp + GMutex* mutex; // synchronize frames queue access GstClockTime previous_timestamp; // the timestamp of the most recent preceding frame GstClockTime timestamp_ceil; // increment above previous timestamp in which frame should fall