fix memory leak in error cases of feed_task function 62/105962/6
authorZhao Cancan <cancan.zhao@samsung.com>
Tue, 20 Dec 2016 06:11:06 +0000 (01:11 -0500)
committerZhao Cancan <cancan.zhao@samsung.com>
Fri, 23 Dec 2016 03:54:06 +0000 (22:54 -0500)
Change-Id: I7adca39677fb64ce0a48880b433baf0b11751c7e

packaging/capi-media-codec.spec
src/media_codec_port_gst.c

index 92cb31b..293d7b8 100755 (executable)
@@ -1,6 +1,6 @@
 Name:       capi-media-codec
 Summary:    A Media Codec library in Tizen Native API
-Version:    0.5.0
+Version:    0.5.1
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index d7856a3..5d0d5d6 100755 (executable)
@@ -47,7 +47,7 @@ static mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, gchar *factory_name
 static mc_ret_e _mc_gst_destroy_pipeline(mc_gst_core_t *core);
 static void __mc_gst_buffer_add(GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer data);
 static int __mc_output_buffer_finalize_cb(media_packet_h packet, int error_code, void *user_data);
-static int  _mc_gst_update_caps(mc_gst_core_t *core, media_packet_h pkt, GstMCBuffer* buff, bool codec_config);
+static int _mc_gst_update_caps(mc_gst_core_t *core, GstMCBuffer *buff, bool codec_config);
 static gboolean _mc_update_packet_info(mc_gst_core_t *core, media_format_h fmt);
 static GstMCBuffer *_mc_gst_media_packet_to_gstbuffer(mc_gst_core_t *core, media_packet_h pkt, bool codec_config);
 static int _mc_gst_gstbuffer_to_appsrc(mc_gst_core_t *core, GstMCBuffer *buff);
@@ -56,12 +56,13 @@ static media_packet_h __mc_gst_make_media_packet(mc_gst_core_t *core, unsigned c
 static gboolean __mc_gst_bus_callback(GstBus *bus, GstMessage *msg, gpointer data);
 static GstBusSyncReply __mc_gst_bus_sync_callback(GstBus *bus, GstMessage *msg, gpointer data);
 static MMVideoBuffer *__mc_gst_make_tbm_buffer(mc_gst_core_t *core, media_packet_h pkt);
-static GstMCBuffer *gst_mediacodec_buffer_new(mc_gst_core_tcore, media_packet_h pkt, uint64_t size);
+static GstMCBuffer *gst_mediacodec_buffer_new(mc_gst_core_t *core, media_packet_h pkt, uint64_t size);
 static void gst_mediacodec_buffer_finalize(GstMCBuffer *buffer);
-static int __mc_set_caps_streamheader(mc_gst_core_t *core, GstMCBuffer*buff, guint streamheader_size);
-static int __mc_set_caps_codecdata(mc_gst_core_t *core, GstMCBuffer*buff, guint codecdata_size);
+static int __mc_set_caps_streamheader(mc_gst_core_t *core, GstMCBuffer *buff, guint streamheader_size);
+static int __mc_set_caps_codecdata(mc_gst_core_t *core, GstMCBuffer *buff, guint codecdata_size);
 static void __mc_push_output_to_queue(mc_gst_core_t *core, media_packet_h out_pkt);
 static int __mc_gst_create_eos_packet(media_format_h fmt, media_packet_h *out_pkt);
+static void _mc_gst_handle_input_buffer_used(mc_gst_core_t *core, media_packet_h pkt);
 
 static gint __gst_handle_stream_error(mc_gst_core_t *core, GError *error, GstMessage *message);
 static gint __gst_transform_gsterror(mc_gst_core_t *core, GstMessage *message, GError *error);
@@ -185,7 +186,7 @@ int __mc_fill_inbuf_with_mm_video_buffer(mc_gst_core_t *core, media_packet_h pkt
 
        ret = media_packet_get_buffer_data_ptr(pkt, &buf_data);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
-               LOGW("buffer size get fail");
+               LOGW("buffer data get fail");
                return MC_ERROR;
        }
 
@@ -221,7 +222,7 @@ int __mc_fill_input_buffer_with_packet(mc_gst_core_t *core, media_packet_h pkt,
 
        ret = media_packet_get_buffer_data_ptr(pkt, &buf_data);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
-               LOGW("buffer size get fail");
+               LOGW("buffer data get fail");
                return MC_ERROR;
        }
 
@@ -581,7 +582,7 @@ int __mc_set_caps_streamheader(mc_gst_core_t *core, GstMCBuffer*buff, guint stre
 
        ret = media_packet_get_buffer_data_ptr(buff->pkt, &buf_data);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
-               LOGW("buffer size get fail");
+               LOGW("buffer data get fail");
                return ret;
        }
 
@@ -1029,11 +1030,12 @@ gboolean _mc_update_packet_info(mc_gst_core_t *core, media_format_h fmt)
        return is_updated;
 }
 
-static int _mc_gst_update_caps(mc_gst_core_t *core, media_packet_h pkt, GstMCBuffer* buff, bool codec_config)
+static int _mc_gst_update_caps(mc_gst_core_t *core, GstMCBuffer *buff, bool codec_config)
 {
        MEDIACODEC_FENTER();
 
        g_return_val_if_fail(core != NULL, MC_PARAM_ERROR);
+       g_return_val_if_fail(buff != NULL, MC_PARAM_ERROR);
 
        int ret = MC_ERROR_NONE;
 
@@ -1041,7 +1043,7 @@ static int _mc_gst_update_caps(mc_gst_core_t *core, media_packet_h pkt, GstMCBuf
                if (core->encoder) {
                        mc_encoder_info_t *enc_info = (mc_encoder_info_t *)core->codec_info;
 
-                       core->format = __mc_get_gst_input_format(pkt, core->is_hw);
+                       core->format = __mc_get_gst_input_format(buff->pkt, core->is_hw);
                        gst_caps_set_simple(core->caps,
                                        "format", G_TYPE_STRING, core->format,
                                        "width", G_TYPE_INT, enc_info->width,
@@ -1053,7 +1055,7 @@ static int _mc_gst_update_caps(mc_gst_core_t *core, media_packet_h pkt, GstMCBuf
                                g_object_set(GST_OBJECT(core->codec), "bitrate", enc_info->bitrate, NULL);
                        else
                                g_object_set(GST_OBJECT(core->codec), "target-bitrate", enc_info->bitrate, NULL);
-
+                       LOGD("set bitrate = %d.", enc_info->bitrate);
                } else {
                        mc_decoder_info_t *dec_info = (mc_decoder_info_t *)core->codec_info;
 
@@ -1140,7 +1142,6 @@ static gpointer feed_task(gpointer data)
        while (g_atomic_int_get(&core->available_queue->running)) {
                LOGD("waiting for next input....");
                in_buf = _mc_get_input_buffer(core);
-
                if (!in_buf)
                        goto LEAVE;
 
@@ -1160,12 +1161,27 @@ static gpointer feed_task(gpointer data)
                        LOGE("media_packet_is_end_of_stream failed");
                        goto ERROR;
                }
+               /*
+                * receive an eos packet. For decoder + encoder case, encoder always get tbm surface plane first from input data,
+                * but eos packet only has flag not valid data, so we don't put it to downstream.
+                */
+               if (eos) {
+                       LOGD("end of stream");
+                       gst_app_src_end_of_stream(GST_APP_SRC(core->appsrc));
+                       _mc_wait_for_eos(core);
+                       initiative = true;
+
+                       _mc_gst_handle_input_buffer_used(core, in_buf);
+                       goto LEAVE;
+               }
 
                buff = _mc_gst_media_packet_to_gstbuffer(core, in_buf, codec_config);
                if (!buff) {
                        LOGW("gstbuffer can't make");
                        goto ERROR;
                }
+               /* buff took the ownership of the in_buf, so set in_buf to NULL to aviod double unref */
+               in_buf = NULL;
 
                if (codec_config)
                        initiative = TRUE;
@@ -1173,9 +1189,11 @@ static gpointer feed_task(gpointer data)
                if (initiative) {
                        GstPad *pad;
 
-                       ret = _mc_gst_update_caps(core, in_buf, buff, codec_config);
+                       ret = _mc_gst_update_caps(core, buff, codec_config);
                        if (ret != MC_ERROR_NONE) {
                                LOGE("failed to update caps");
+                               /* unref buff->buffer will invoke the finalize() of GstMcBuffer */
+                               gst_buffer_unref(buff->buffer);
                                goto ERROR;
                        }
 
@@ -1195,16 +1213,11 @@ static gpointer feed_task(gpointer data)
 
                initiative = false;
 
-               if (eos) {
-                       LOGD("end of stream");
-                       gst_app_src_end_of_stream(GST_APP_SRC(core->appsrc));
-                       _mc_wait_for_eos(core);
-                       initiative = true;
-               }
-
-
                continue;
 ERROR:
+               if (in_buf)
+                       _mc_gst_handle_input_buffer_used(core, in_buf);
+
                _mc_gst_set_flush_input(core);
 
                if (core->user_cb[_MEDIACODEC_EVENT_TYPE_ERROR]) {
@@ -2034,10 +2047,10 @@ void __mc_push_output_to_queue(mc_gst_core_t *core, media_packet_h out_pkt)
        GstBuffer *buffer = NULL;
        media_packet_get_extra(out_pkt, (void**)&buffer);
        if (buffer) {
-               LOGD("dq : %d TIMESTAMP = %"GST_TIME_FORMAT " DURATION = %"GST_TIME_FORMAT,
+               LOGD("dq : v(%d)e(%d) %d TIMESTAMP = %"GST_TIME_FORMAT " DURATION = %"GST_TIME_FORMAT, core->video, core->encoder,
                        core->ftb_count, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)), GST_TIME_ARGS(GST_BUFFER_DURATION(buffer)));
        } else {
-               LOGD("dq : %d ", core->ftb_count);
+               LOGD("dq : v(%d)e(%d) %d ", core->video, core->encoder, core->ftb_count);
        }
 
        g_mutex_unlock(&core->ports[1]->mutex);
@@ -2181,7 +2194,7 @@ gchar *__mc_get_gst_input_format(media_packet_h packet, bool is_hw)
        return format;
 }
 
-GstMCBuffer *_mc_gst_media_packet_to_gstbuffer(mc_gst_core_tcore, media_packet_h pkt, bool codec_config)
+GstMCBuffer *_mc_gst_media_packet_to_gstbuffer(mc_gst_core_t *core, media_packet_h pkt, bool codec_config)
 {
        int ret = MEDIA_PACKET_ERROR_NONE;
        GstMCBuffer *mc_buffer = NULL;
@@ -2198,7 +2211,7 @@ GstMCBuffer *_mc_gst_media_packet_to_gstbuffer(mc_gst_core_t* core, media_packet
 
        ret = media_packet_get_buffer_data_ptr(pkt, &buf_data);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
-               LOGW("buffer size get fail");
+               LOGW("buffer data get fail");
                return NULL;
        }
 
@@ -2208,11 +2221,17 @@ GstMCBuffer *_mc_gst_media_packet_to_gstbuffer(mc_gst_core_t* core, media_packet
                return NULL;
        }
 
-       LOGD("pkt : %p, buf_size : %d", pkt, (int)buf_size);
+       LOGD("pkt :v(%d)e(%d) %p, buf_size : %d", core->video, core->encoder, pkt, (int)buf_size);
 
        ret = __mc_fill_input_buffer(core, pkt, mc_buffer);
        if (ret != MC_ERROR_NONE) {
                LOGW("failed to fill inbuf: %s (ox%08x)", _mc_error_to_string(ret), ret);
+               /*
+                * if __mc_fill_input_buffer() failed, no memory appended to mc_buffer->buffer, so gst_mediacodec_buffer_finalize()
+                * will not be invoked
+                */
+               gst_buffer_unref(mc_buffer->buffer);
+               free(mc_buffer);
                return NULL;
        }
 
@@ -2248,7 +2267,7 @@ int __mc_gst_create_eos_packet(media_format_h fmt, media_packet_h *out_pkt)
        int ret = MC_ERROR_NONE;
 
        MEDIACODEC_FENTER();
-       if (media_packet_create_alloc(fmt, NULL, NULL, &mediabuf)) {
+       if (media_packet_create(fmt, NULL, NULL, &mediabuf)) {
                LOGE("media_packet_create_alloc failed\n");
                ret = MC_ERROR;
                goto ERROR;
@@ -2272,6 +2291,19 @@ ERROR:
        return ret;
 }
 
+void _mc_gst_handle_input_buffer_used(mc_gst_core_t *core, media_packet_h pkt)
+{
+       g_atomic_int_dec_and_test(&core->etb_count);
+
+       if (core && core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]) {
+               ((mc_empty_buffer_cb)core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER])
+                       (pkt, core->user_data[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]);
+       }
+
+       if (core)
+               LOGD("@v(%d)e(%d) input port emptied buffer(%d): %p", core->video, core->encoder, core->etb_count, pkt);
+}
+
 gboolean __mc_gst_bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
 {
        int ret  = MC_ERROR_NONE;
@@ -2398,7 +2430,7 @@ static GstBusSyncReply __mc_gst_bus_sync_callback(GstBus *bus, GstMessage *msg,
        return reply;
 }
 
-static MMVideoBuffer *__mc_gst_make_tbm_buffer(mc_gst_core_tcore, media_packet_h pkt)
+static MMVideoBuffer *__mc_gst_make_tbm_buffer(mc_gst_core_t *core, media_packet_h pkt)
 {
        int i;
        int num_bos;
@@ -2488,13 +2520,8 @@ static void gst_mediacodec_buffer_finalize(GstMCBuffer *mc_buffer)
 
        mc_gst_core_t *core = (mc_gst_core_t *)mc_buffer->core;
 
-       g_atomic_int_dec_and_test(&core->etb_count);
-       if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]) {
-               ((mc_empty_buffer_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER])
-                       (mc_buffer->pkt, core->user_data[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]);
-       }
+       _mc_gst_handle_input_buffer_used(core, mc_buffer->pkt);
 
-       LOGD("@v(%d)e(%d)input port emptied buffer(%d): %p", core->video, core->encoder, core->etb_count, mc_buffer->pkt);
        free(mc_buffer);
        mc_buffer = NULL;
 
@@ -2503,7 +2530,7 @@ static void gst_mediacodec_buffer_finalize(GstMCBuffer *mc_buffer)
        return;
 }
 
-static GstMCBuffer *gst_mediacodec_buffer_new(mc_gst_core_tcore, media_packet_h pkt, uint64_t size)
+static GstMCBuffer *gst_mediacodec_buffer_new(mc_gst_core_t *core, media_packet_h pkt, uint64_t size)
 {
        GstMCBuffer *mc_buffer = NULL;
 
@@ -2604,7 +2631,7 @@ static gint __gst_handle_resource_error(mc_gst_core_t *core, int code)
        return trans_err;
 }
 
-static gint __gst_handle_stream_error(mc_gst_core_t *core, GError* error, GstMessage * message)
+static gint __gst_handle_stream_error(mc_gst_core_t *core, GError *error, GstMessage *message)
 {
        gint trans_err = MEDIACODEC_ERROR_NONE;
 
@@ -2637,7 +2664,7 @@ static gint __gst_handle_stream_error(mc_gst_core_t *core, GError* error, GstMes
        return trans_err;
 }
 
-static gint __gst_transform_gsterror(mc_gst_core_t *core, GstMessage * message, GError* error)
+static gint __gst_transform_gsterror(mc_gst_core_t *core, GstMessage *message, GError *error)
 {
        gchar *src_element_name = NULL;
        GstElement *src_element = NULL;
@@ -2725,10 +2752,7 @@ static void _mc_gst_set_flush_input(mc_gst_core_t *core)
                g_atomic_int_dec_and_test(&core->etb_count);
                LOGD("%p poped(%d)", pkt, core->etb_count);
 
-               if (core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]) {
-                       ((mc_empty_buffer_cb) core->user_cb[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER])
-                               (pkt, core->user_data[_MEDIACODEC_EVENT_TYPE_EMPTYBUFFER]);
-               }
+               _mc_gst_handle_input_buffer_used(core, pkt);
        }
 
        mc_async_queue_flush(core->available_queue->input);