Fix memory leak
[platform/core/multimedia/libmm-transcode.git] / transcode / mm_transcode_seek.c
1 /*
2  * libmm-transcode
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: YoungHun Kim <yh8004.kim@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 #include "mm_transcode.h"
22 #include "mm_transcode_internal.h"
23
24 static void _mm_transcode_audio_capsfilter(GstCaps *caps, handle_s *handle);
25 static void _mm_transcode_video_capsfilter(GstCaps *caps, handle_s *handle);
26 static void _mm_transcode_video_capsfilter_call(handle_s *handle);
27 static void _mm_transcode_video_capsfilter_set_parameter(GstCaps *caps, handle_s *handle);
28 static int _mm_transcode_exec(handle_s *handle, handle_param_s *param);
29 static int _mm_transcode_play(handle_s *handle);
30 static int _mm_transcode_seek(handle_s *handle);
31 static gpointer _mm_transcode_thread_repeate(gpointer data);
32
33 GstPadProbeReturn _mm_cb_audio_output_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
34 {
35         handle_s *handle = (handle_s *)user_data;
36
37         if (!handle) {
38                 debug_error("[ERROR] - handle");
39                 return GST_PAD_PROBE_REMOVE;
40         }
41
42         if (!handle->property) {
43                 debug_error("[ERROR] - handle property");
44                 return GST_PAD_PROBE_REMOVE;
45         }
46
47         gint64 start_pos_ts = handle->param->start_pos * G_GINT64_CONSTANT(1000000);
48
49         if (GST_BUFFER_PTS_IS_VALID(GST_PAD_PROBE_INFO_BUFFER(info))) {
50                 if (0 == handle->property->AUDFLAG++) {
51                         GstCaps *current_caps = gst_pad_get_current_caps(pad);
52                         /* Need to audio caps converting when amrnbenc */
53                         /* Not drop buffer with 'return FALSE' */
54                         _mm_transcode_audio_capsfilter(current_caps, handle);
55
56                         if (current_caps)
57                                 gst_caps_unref(current_caps);
58                 }
59
60                 if (handle->param->seeking) {
61                         /* Shifting the decoded out buffer time as the start time */
62                         if (GST_BUFFER_PTS(GST_PAD_PROBE_INFO_BUFFER(info)) >= start_pos_ts) {
63                                 GST_BUFFER_PTS(GST_PAD_PROBE_INFO_BUFFER(info)) -= start_pos_ts;
64                         } else {
65                                 /* If input buffer time is less than start position,
66                                  * input buffer will be dropped.
67                                  */
68                                 return GST_PAD_PROBE_DROP;
69                         }
70
71                 }
72         }
73         return GST_PAD_PROBE_OK;
74 }
75
76 GstPadProbeReturn _mm_cb_video_output_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
77 {
78         handle_s *handle = (handle_s *)user_data;
79
80         if (!handle) {
81                 debug_error("[ERROR] - handle");
82                 return GST_PAD_PROBE_REMOVE;
83         }
84
85         if (!handle->property) {
86                 debug_error("[ERROR] - handle property");
87                 return GST_PAD_PROBE_REMOVE;
88         }
89
90         gint64 start_pos_ts = handle->param->start_pos * G_GINT64_CONSTANT(1000000);
91
92         if (GST_BUFFER_PTS_IS_VALID(GST_PAD_PROBE_INFO_BUFFER(info))) {
93                 if (0 == handle->property->VIDFLAG++) {
94                         GstCaps *current_caps = gst_pad_get_current_caps(pad);
95                         /* Not drop buffer with 'return FALSE' */
96                         _mm_transcode_video_capsfilter(current_caps, handle);
97
98                         if (current_caps)
99                                 gst_caps_unref(current_caps);
100                 }
101
102                 if (handle->param->seeking) {
103                         /* Shifting the decoded out buffer time as the start time */
104                         if (GST_BUFFER_PTS(GST_PAD_PROBE_INFO_BUFFER(info)) >= start_pos_ts) {
105                                 GST_BUFFER_PTS(GST_PAD_PROBE_INFO_BUFFER(info)) -= start_pos_ts;
106                         } else {
107                                 /* If input buffer time is less than start position,
108                                  * input buffer will be dropped.
109                                  */
110                                 return GST_PAD_PROBE_DROP;
111                         }
112
113                 }
114         }
115         return GST_PAD_PROBE_OK;
116 }
117
118 GstPadProbeReturn _mm_cb_encodebin_sinkpad_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
119 {
120         handle_s *handle = (handle_s *)user_data;
121         GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
122
123         if (!handle) {
124                 debug_error("[ERROR] - handle");
125                 return GST_PAD_PROBE_REMOVE;
126         }
127
128         if (!handle->property) {
129                 debug_error("[ERROR] - handle property");
130                 return GST_PAD_PROBE_REMOVE;
131         }
132
133         if (!event) {
134                 debug_error("[ERROR] - event");
135                 return GST_PAD_PROBE_REMOVE;
136         }
137
138         switch (GST_EVENT_TYPE(event)) {
139         case GST_EVENT_SEGMENT:
140                 {
141                         if (!handle->param->seeking)
142                                 break;
143
144                         const GstSegment *segment = NULL;
145                         GstSegment *new_segment = NULL;
146                         gst_event_parse_segment(event, &segment);
147                         if (segment->format != GST_FORMAT_TIME)
148                                 break;
149
150                         new_segment = gst_segment_copy(segment);
151                         gst_event_unref(event);
152
153                         if (!new_segment) {
154                                 debug_error("[ERROR] segment copy error");
155                                 return GST_PAD_PROBE_REMOVE;
156                         }
157
158                         new_segment->start = 0;
159                         new_segment->stop = handle->param->duration * G_GINT64_CONSTANT(1000000);
160
161                         /* replace the new segment (change start/stop position) */
162                         GstEvent *new_event = gst_event_new_segment(new_segment);
163
164                         GST_PAD_PROBE_INFO_DATA(info) = new_event;
165                 }
166
167                 break;
168         default:
169                 break;
170         }
171
172         return GST_PAD_PROBE_OK;
173 }
174
175 GstAutoplugSelectResult _mm_cb_decode_bin_autoplug_select(GstElement *element, GstPad *pad, GstCaps *caps, GstElementFactory *factory, handle_s *handle)
176 {
177         const gchar *feature_name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
178         const gchar *caps_str = NULL;
179
180         if (!handle) {
181                 debug_error("[ERROR] - handle");
182                 return MM_ERROR_INVALID_ARGUMENT;
183         }
184
185         if (!handle->property) {
186                 debug_error("[ERROR] - handle property");
187                 return MM_ERROR_TRANSCODE_INTERNAL;
188         }
189
190         caps_str = _mm_check_media_type(caps);
191         if (g_strrstr(caps_str, "audio")) {
192                 handle->property->audiodecodename = (char *)malloc(sizeof(char) * ENC_BUFFER_SIZE);
193                 if (handle->property->audiodecodename == NULL) {
194                         debug_error("audiodecodename is NULL");
195                         return GST_AUTOPLUG_SELECT_TRY;
196                 }
197                 memset(handle->property->audiodecodename, 0, ENC_BUFFER_SIZE);
198                 strncpy(handle->property->audiodecodename, feature_name, strlen(feature_name));
199                 debug_log("[audio decode name %s : %s]", caps_str, handle->property->audiodecodename);
200         }
201
202         if (g_strrstr(caps_str, "video")) {
203                 if (g_strrstr(feature_name, "omx") || g_strrstr(feature_name, "sprd") || g_strrstr(feature_name, "v4l2")) {
204                         /* emit autoplug-select to see what we should do with it. */
205                         debug_log("SKIP %s Codec", feature_name);
206                         return GST_AUTOPLUG_SELECT_SKIP;
207                 }
208                 handle->property->videodecodename = (char *)malloc(sizeof(char) * ENC_BUFFER_SIZE);
209                 if (handle->property->videodecodename == NULL) {
210                         debug_error("videodecodename is NULL");
211                         return GST_AUTOPLUG_SELECT_TRY;
212                 }
213                 memset(handle->property->videodecodename, 0, ENC_BUFFER_SIZE);
214                 strncpy(handle->property->videodecodename, feature_name, strlen(feature_name));
215                 debug_log("[video decode name %s : %s]", caps_str, handle->property->videodecodename);
216         }
217
218         /* Try factory. */
219         return GST_AUTOPLUG_SELECT_TRY;
220 }
221
222 void _mm_cb_decoder_newpad_encoder(GstElement *decodebin, GstPad *pad, handle_s *handle)
223 {
224         if (!handle) {
225                 debug_error("[ERROR] - handle");
226                 return;
227         }
228
229         if (!handle->decoder_vidp) {
230                 debug_error("[ERROR] - handle decoder_vidp");
231                 return;
232         }
233
234         if (!handle->decoder_audp) {
235                 debug_error("[ERROR] - handle decoder_audp");
236                 return;
237         }
238
239         if (!handle->encodebin) {
240                 debug_error("[ERROR] - handle encodebin");
241                 return;
242         }
243
244         if (!handle->property) {
245                 debug_error("[ERROR] - handle property");
246                 return;
247         }
248
249         debug_log("[============ new-decoded-pad ============]");
250         handle->property->caps = gst_pad_query_caps(pad, NULL);
251         const gchar *mime = _mm_check_media_type(handle->property->caps);
252
253         if (!mime) {
254                 debug_error("[ERROR] - mime");
255                 return;
256         }
257
258         if (g_strrstr(mime, "video")) {
259                 handle->property->linked_vidoutbin = TRUE;
260
261                 /* link videopad */
262                 if (gst_pad_is_linked(pad)) {
263                         debug_log("pad liked");
264                 } else {
265                         if (gst_pad_link(pad, (GstPad *) handle->decoder_vidp->sinkdecvideopad) != GST_PAD_LINK_OK)
266                                 debug_error("Error [pad - sinkdecvideopad]");
267                         else
268                                 debug_log("Success [pad - sinkdecvideopad]");
269                 }
270
271         } else if (g_strrstr(mime, "audio")) {
272                 handle->property->linked_audoutbin = TRUE;
273
274                 /* link audiopad */
275                 if (gst_pad_is_linked(pad)) {
276                         debug_log("pad liked");
277                 } else {
278                         if (gst_pad_link(pad, (GstPad *) handle->decoder_audp->sinkdecaudiopad) != GST_PAD_LINK_OK)
279                                 debug_error("Error [pad - sinkdecaudiopad]");
280                         else
281                                 debug_log("Success [pad - sinkdecaudiopad]");
282                 }
283
284         } else {
285                 debug_log("gst structure error");
286         }
287 }
288
289 gboolean _mm_cb_print_position(handle_s *handle)
290 {
291         GstFormat fmt = GST_FORMAT_TIME;
292         gint64 pos;
293
294         if (!handle) {
295                 debug_error("[ERROR] - handle");
296                 return FALSE;
297         }
298
299         if (!handle->property) {
300                 debug_error("[ERROR] - handle property");
301                 return FALSE;
302         }
303
304         /* To avoid gst_element_query_position bs */
305         if (!handle->property->repeat_thread_exit) {
306                 if (gst_element_query_position(handle->pipeline, fmt, &pos)) {
307                         unsigned long current_pos = (unsigned long)(GST_TIME_AS_MSECONDS(pos));
308                         if (handle->param->seeking == FALSE) {
309                                 handle->property->current_pos = current_pos;
310                                 handle->property->real_duration = handle->property->total_length;
311                         } else if (handle->param->seeking == TRUE) {
312                                 handle->property->current_pos = current_pos - handle->param->start_pos;
313                                 if (handle->param->duration != 0) {
314                                         if (handle->param->start_pos + handle->param->duration > handle->property->total_length)
315                                                 handle->property->real_duration = handle->property->total_length - handle->param->start_pos;
316                                         else
317                                                 handle->property->real_duration = handle->param->duration;
318                                 /* seek to origin file length */
319                                 } else if (handle->param->duration == 0) {
320                                         handle->property->real_duration = handle->property->total_length - handle->param->start_pos;
321                                 }
322                         }
323
324                         if (handle->property->current_pos <= handle->property->real_duration) {
325                                 /* 2 = 1000 / 500 minimum printed cnt for last buffer */
326                                 if (handle->property->current_pos == 0 && handle->param->printed > 2)
327                                         handle->property->current_pos = handle->property->real_duration;
328
329                                 if (handle->property->progress_cb) {
330                                         /* for first buffer */
331                                         if (0 == handle->param->printed)
332                                                 handle->property->current_pos = 0;
333                                         handle->property->progress_cb(handle->property->current_pos, handle->property->real_duration, handle->property->progress_cb_param);
334                                         handle->param->printed++;
335                                 }
336                         }
337                 }
338         }
339
340         return TRUE;
341 }
342
343 gboolean _mm_cb_transcode_bus(GstBus *bus, GstMessage *message, gpointer userdata)
344 {
345         handle_s *handle = (handle_s *)userdata;
346         int ret = MM_ERROR_NONE;
347
348         if (!handle) {
349                 debug_error("[ERROR] - handle");
350                 return FALSE;
351         }
352
353         if (!handle->property) {
354                 debug_error("[ERROR] - handle property");
355                 return FALSE;
356         }
357
358         gint64 total_length;
359         GstFormat fmt = GST_FORMAT_TIME;
360         MMHandleType MMHandle = (MMHandleType)handle;
361
362         switch (GST_MESSAGE_TYPE(message)) {
363         case GST_MESSAGE_ERROR:
364                 {
365                         GError *err;
366                         gchar *debug;
367                         gst_message_parse_error(message, &err, &debug);
368
369                         if (!err) {
370                                 debug_warning("Fail to parse error message");
371                                 break;
372                         }
373
374                         debug_error("[Source: %s] Error: %s", GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC(message)))), err->message);
375
376                         ret = mm_transcode_cancel(MMHandle);
377                         if (ret == MM_ERROR_NONE) {
378                                 debug_log("Success - Cancel Transcode");
379                         } else {
380                                 debug_error("ERROR - Cancel Transcode");
381                                 return FALSE;
382                         }
383
384                         g_error_free(err);
385                         err = NULL;
386
387                         TRANSCODE_FREE(debug);
388                         TRANSCODE_FREE(handle->param);
389                         /* g_main_loop_quit (handle->loop); */
390                         break;
391                 }
392
393         case GST_MESSAGE_STATE_CHANGED:
394                 {
395                         if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != handle->pipeline)
396                                 break;
397
398                         GstState State_Old, State_New, State_Pending;
399                         gst_message_parse_state_changed(message, &State_Old, &State_New, &State_Pending);
400
401                         debug_log("[Source: %s] [State: %d -> %d]", GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC(message)))), State_Old, State_New);
402
403                         if (State_Old == GST_STATE_NULL && State_New == GST_STATE_READY) {
404                                 debug_log("[Set State: Pause]");
405                                 /* Pause Transcode */
406                                 ret = _mm_transcode_state_change(handle, GST_STATE_PAUSED);
407                                 if (ret == MM_ERROR_NONE) {
408                                         debug_log("Success - Pause pipeline");
409                                 } else {
410                                         debug_error("ERROR - Pause pipeline");
411                                         return FALSE;
412                                 }
413                         }
414
415                         if (State_Old == GST_STATE_READY && State_New == GST_STATE_PAUSED) {
416                                 /* Seek */
417                                 debug_log("[%s] Start New Segment pipeline", handle->param->outputfile);
418                                 ret = _mm_transcode_seek(handle);
419
420                                 if (ret == MM_ERROR_NONE) {
421                                         debug_log("Success - Set New Segment pipeline");
422                                 } else {
423                                         debug_log("[Null Trancode]");
424                                         if (_mm_transcode_state_change(handle, GST_STATE_NULL) != MM_ERROR_NONE) {
425                                                 debug_error("ERROR -Null Pipeline");
426                                                 return FALSE;
427                                         }
428                                         g_mutex_lock(handle->property->thread_mutex);
429                                         debug_log("[g_mutex_lock]");
430                                         TRANSCODE_FREE(handle->param);
431                                         debug_log("g_free(param)");
432                                         g_cond_signal(handle->property->thread_cond);
433                                         debug_log("[g_cond_signal]");
434                                         g_mutex_unlock(handle->property->thread_mutex);
435                                         debug_log("[g_mutex_unlock]");
436                                 }
437                         }
438
439                         break;
440                 }
441
442         case GST_MESSAGE_ASYNC_DONE:
443                 {
444                         if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != handle->pipeline)
445                                 break;
446
447                         if (gst_element_query_duration(handle->pipeline, fmt, &total_length) && handle->property->total_length == 0) {
448                                 debug_log("[GST_MESSAGE_ASYNC_DONE] Total Duration: %" G_GUINT64_FORMAT " ", total_length);
449                                 handle->property->total_length = (unsigned long)(GST_TIME_AS_MSECONDS(total_length));
450                         }
451
452                         handle->param->async_done = TRUE;
453                         debug_log("GST_MESSAGE_ASYNC_DONE");
454
455                         /* Play Transcode */
456                         debug_log("[Play Trancode] [%d ~ %d]", handle->param->start_pos, handle->property->end_pos);
457
458                         if (_mm_transcode_play(handle) != MM_ERROR_NONE) {
459                                 debug_error("ERROR - Play Pipeline");
460                                 return FALSE;
461                         }
462                         break;
463                 }
464
465         case GST_MESSAGE_SEGMENT_DONE:
466                 {
467                         if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != handle->pipeline)
468                                 break;
469
470                         handle->param->segment_done = TRUE;
471                         debug_log("GST_MESSAGE_SEGMENT_DONE");
472                         break;
473                 }
474
475         case GST_MESSAGE_EOS:
476                 {
477                         /* end-of-stream */
478                         debug_log("[GST_MESSAGE_EOS] end-of-stream");
479
480                         debug_log("[completed] %s (Transcode ID: %d)", handle->param->outputfile, handle->property->seek_idx++);
481                         handle->property->AUDFLAG = 0;
482                         handle->property->VIDFLAG = 0;
483
484                         /* Null Transcode *//* Need to fresh filesink's property */
485                         debug_log("[Null Trancode]");
486                         if (_mm_transcode_state_change(handle, GST_STATE_NULL) != MM_ERROR_NONE) {
487                                 debug_error("ERROR -Null Pipeline");
488                                 return FALSE;
489                         }
490                         /* checkpoint once more here (eos) and not unlink when Audio only */
491                         if ((handle->param->start_pos > handle->property->total_length && handle->property->total_length != 0) && (handle->property->videoencoder != MM_VIDEOENCODER_NO_USE)) {
492                                 unlink(handle->param->outputfile);
493                                 debug_log("[unlink] %s %d > %d", handle->param->outputfile, handle->param->start_pos, handle->property->total_length);
494                         }
495                         g_mutex_lock(handle->property->thread_mutex);
496                         handle->param->completed = TRUE;
497                         handle->property->is_busy = FALSE;
498                         g_cond_signal(handle->property->thread_cond);
499                         debug_log("===> send completed signal");
500                         g_mutex_unlock(handle->property->thread_mutex);
501
502                         debug_log("[MMHandle] 0x%2x [msg_cb] 0x%2x [msg_cb_param] 0x%2x", MMHandle, handle->property->completed_cb, handle->property->completed_cb_param);
503
504                         if (handle->property->progress_cb)
505                                 handle->property->progress_cb(handle->property->real_duration, handle->property->real_duration, handle->property->progress_cb_param);
506
507                         if (handle->property->completed_cb)
508                                 handle->property->completed_cb(MM_ERROR_NONE, handle->property->completed_cb_param);
509
510                         break;
511                 }
512         default:
513                 /* unhandle meage */
514                 /*debug_log("unhandle message"); */
515                 break;
516         }
517         return TRUE;
518 }
519
520 static void _mm_transcode_audio_capsfilter(GstCaps *caps, handle_s *handle)
521 {
522         gchar *str = NULL;
523
524         if (!handle) {
525                 debug_error("[ERROR] - handle");
526                 return;
527         }
528
529         if (!handle->encodebin) {
530                 debug_error("[ERROR] - handle encodebin");
531                 return;
532         }
533
534         if (!handle->property) {
535                 debug_error("[ERROR] - handle property");
536                 return;
537         }
538
539         if (!caps) {
540                 debug_error("[ERROR] - caps");
541                 return;
542         }
543
544         if (!strcmp(handle->property->aenc, AMRENC))
545                 caps = gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, 8000, "channels", G_TYPE_INT, 1, NULL);
546         else if (!strcmp(handle->property->aenc, AACENC))
547                 caps = gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 1, NULL);
548
549         TRANSCODE_FREE(handle->property->audiodecodename);
550         g_object_set(G_OBJECT(handle->decoder_audp->audflt), "caps", caps, NULL);
551
552         str = gst_caps_to_string(caps);
553
554         if (str) {
555                 debug_log("audio decoder capsfilter audiocaps: %s", str);
556                 g_free(str);
557         }
558
559         return;
560
561 }
562
563 int _mm_transcode_create(handle_s *handle)
564 {
565         int ret = MM_ERROR_NONE;
566
567         if (!handle) {
568                 debug_error("[ERROR] - handle");
569                 return MM_ERROR_INVALID_ARGUMENT;
570         }
571
572         ret = _mm_decodesrcbin_create(handle);
573         if (ret == MM_ERROR_NONE) {
574                 debug_log("Success - Create decodesrcbin");
575         } else {
576                 debug_error("ERROR - Create decodesrcbin");
577                 return ret;
578         }
579
580         ret = _mm_encodebin_set_venc_aenc(handle);
581         if (ret == MM_ERROR_NONE) {
582                 debug_log("Success - Setup video and audio encoder of encodebin");
583         } else {
584                 debug_error("ERROR -Setup video and audio encoder of encodebin ");
585                 return ret;
586         }
587
588         ret = _mm_encodebin_create(handle);
589         if (ret == MM_ERROR_NONE) {
590                 debug_log("Success - Create encodebin");
591         } else {
592                 debug_error("ERROR - Create encodebin");
593                 return ret;
594         }
595
596         /*create filesink */
597         ret = _mm_filesink_create(handle);
598         if (ret == MM_ERROR_NONE) {
599                 debug_log("Success - Create Filesink");
600         } else {
601                 debug_error("ERROR - Create Filesink");
602                 return ret;
603         }
604
605         return ret;
606 }
607
608 static int _mm_transcode_exec(handle_s *handle, handle_param_s *param)
609 {
610         int ret = MM_ERROR_NONE;
611
612         if (!handle) {
613                 debug_error("[ERROR] - handle");
614                 return MM_ERROR_INVALID_ARGUMENT;
615         }
616
617         if (!handle->property) {
618                 debug_error("[ERROR] - handle property");
619                 return MM_ERROR_TRANSCODE_INTERNAL;
620         }
621
622         if (!param || !param->outputfile) {
623                 debug_error("[ERROR] - param");
624                 return MM_ERROR_TRANSCODE_INVALID_VALUE;
625         }
626
627         g_mutex_lock(handle->property->thread_mutex);
628
629         if (handle->property->repeat_thread_exit) {
630                 g_mutex_unlock(handle->property->thread_mutex);
631                 debug_log("unlock destory");
632         } else {
633                 debug_log("start_pos: %d, duration: %d, seek_mode: %d output file name: %s\n", param->start_pos, param->duration, param->seek_mode, param->outputfile);
634                 handle->param = g_new0(handle_param_s, 1);
635                 /*g_value_init (handle->param, G_TYPE_INT); */
636
637                 if (!handle->param) {
638                         debug_error("[ERROR] - handle param");
639                         return MM_ERROR_TRANSCODE_INTERNAL;
640                 }
641
642                 handle->param->resolution_width = param->resolution_width;
643                 handle->param->resolution_height = param->resolution_height;
644                 handle->param->fps_value = param->fps_value;
645                 handle->param->start_pos = param->start_pos;
646                 handle->param->duration = param->duration;
647                 handle->param->seek_mode = param->seek_mode;
648                 handle->param->outputfile = malloc(sizeof(gchar) * BUFFER_SIZE);
649                 if (!handle->param->outputfile) {
650                         TRANSCODE_FREE(handle->param);
651                         return MM_ERROR_TRANSCODE_NO_FREE_SPACE;
652                 }
653
654                 memset(handle->param->outputfile, 0, BUFFER_SIZE);
655                 strncpy(handle->param->outputfile, param->outputfile, strlen(param->outputfile));
656
657                 handle->param->seeking = param->seeking;
658                 handle->param->async_done = FALSE;
659                 handle->param->segment_done = FALSE;
660                 handle->param->completed = FALSE;
661                 handle->param->printed = 0;
662                 debug_log("[SEEK: %d] width: %d height: %d fps_value: %d start_pos: %d duration: %d seek_mode: %d outputfile: %s", handle->param->seeking, handle->param->resolution_width, handle->param->resolution_height, handle->param->fps_value, handle->param->start_pos, handle->param->duration, handle->param->seek_mode, handle->param->outputfile);
663
664                 if (handle->property->total_length != 0 && handle->param->start_pos > handle->property->total_length) {
665                         debug_log("[SKIP] [%s] because out of duration [%d < %d ~ %d] ", handle->param->outputfile, handle->property->total_length, handle->param->start_pos, handle->param->duration);
666                         g_mutex_unlock(handle->property->thread_mutex);
667                         debug_log("[thread_mutex unlock]");
668                 } else {
669                         g_object_set(G_OBJECT(handle->filesink), "location", handle->param->outputfile, NULL);
670                         debug_log("[%s] set filesink location", handle->param->outputfile);
671
672                         /* Ready Transcode */
673                         if (strlen(handle->param->outputfile) != 0) {
674                                 debug_log("[Set State: Ready]");
675                                 ret = _mm_transcode_state_change(handle, GST_STATE_READY);
676                                 if (ret == MM_ERROR_NONE) {
677                                         debug_log("Success - Ready pipeline");
678                                 } else {
679                                         debug_error("ERROR - Reay pipeline");
680                                         g_mutex_unlock(handle->property->thread_mutex);
681                                         return ret;
682                                 }
683                         }
684
685                         if (0 == handle->property->seek_idx) {
686                                 debug_log("Link Filesink");
687                                 /* link filesink */
688                                 ret = _mm_filesink_link(handle);
689                                 if (ret == MM_ERROR_NONE) {
690                                         debug_log("Success - Link Filesink");
691                                 } else {
692                                         debug_error("ERROR - Link Filesink");
693                                         g_mutex_unlock(handle->property->thread_mutex);
694                                         return ret;
695                                 }
696                         }
697
698                         g_cond_wait(handle->property->thread_cond, handle->property->thread_mutex);
699                         debug_log("<=== get completed signal");
700                         g_mutex_unlock(handle->property->thread_mutex);
701                 }
702         }
703
704         return ret;
705 }
706
707 int _mm_transcode_get_stream_info(handle_s *handle)
708 {
709         int ret = MM_ERROR_NONE;
710
711         if (!handle) {
712                 debug_error("[ERROR] - handle");
713                 return MM_ERROR_INVALID_ARGUMENT;
714         }
715
716         if (!handle->property) {
717                 debug_error("[ERROR] - handle property");
718                 return MM_ERROR_TRANSCODE_INTERNAL;
719         }
720
721         if (strlen(handle->property->sourcefile) == 0) {
722                 debug_error("Invalid arguments [sourcefile size 0]\n");
723                 return MM_ERROR_INVALID_ARGUMENT;
724         }
725
726         int audio_track_num = 0;
727         int video_track_num = 0;
728
729         ret = mm_file_get_stream_info(handle->property->sourcefile, &audio_track_num, &video_track_num);
730         if (ret == MM_ERROR_NONE) {
731                 debug_log("Success - mm_file_get_stream_info");
732         } else {
733                 debug_error("ERROR - mm_file_get_stream_info");
734                 return MM_ERROR_TRANSCODE_INTERNAL;
735         }
736
737         if (audio_track_num)
738                 handle->property->has_audio_stream = TRUE;
739         else
740                 handle->property->has_audio_stream = FALSE;
741
742         debug_log("has_audio_stream: %d", handle->property->has_audio_stream);
743
744         if (video_track_num)
745                 handle->property->has_video_stream = TRUE;
746         else
747                 handle->property->has_video_stream = FALSE;
748
749         debug_log("has_video_stream: %d", handle->property->has_video_stream);
750
751         if ((handle->property->videoencoder != MM_VIDEOENCODER_NO_USE && !handle->property->has_video_stream) || (handle->property->audioencoder != MM_AUDIOENCODER_NO_USE && !handle->property->has_audio_stream)) {
752                 debug_error("No video || audio stream");
753                 return MM_ERROR_INVALID_ARGUMENT;
754         }
755
756         return ret;
757 }
758
759 int _mm_transcode_link(handle_s *handle)
760 {
761         int ret = MM_ERROR_NONE;
762
763         if (!handle) {
764                 debug_error("[ERROR] - handle");
765                 return MM_ERROR_INVALID_ARGUMENT;
766         }
767
768         ret = _mm_decodesrcbin_link(handle);
769         if (ret == MM_ERROR_NONE) {
770                 debug_log("Success - decodesrcbin link");
771         } else {
772                 debug_error("ERROR - decodesrcbin link");
773                 return ret;
774         }
775
776         ret = _mm_encodebin_link(handle);
777         if (ret == MM_ERROR_NONE) {
778                 debug_log("Success - encodebin link");
779         } else {
780                 debug_error("ERROR - encodebin link");
781                 return ret;
782         }
783
784         return ret;
785 }
786
787 static void _mm_transcode_video_capsfilter(GstCaps *caps, handle_s *handle)
788 {
789         if (!handle) {
790                 debug_error("[ERROR] - handle");
791                 return;
792         }
793
794         if (!handle->property) {
795                 debug_error("[ERROR] - handle property");
796                 return;
797         }
798
799         if (!caps) {
800                 debug_error("[ERROR] - caps");
801                 TRANSCODE_FREE(handle->property->videodecodename);
802                 return;
803         }
804
805         debug_log("[First Video Buffer] Set CapsFilter Parameter");
806         _mm_transcode_video_capsfilter_set_parameter(caps, handle);
807
808         /* Not support enlarge video resolution */
809         debug_log("Execute Resize");
810 #if 0
811         /* Not irrelevant to the ratio */
812         handle->param->resolution_height = handle->param->resolution_width * handle->in_height / handle->in_width;
813 #endif
814
815         debug_log("[Resize] resolution_width: %d, resolution_height: %d", handle->param->resolution_width, handle->param->resolution_height);
816         if (0 == handle->param->resolution_width || 0 == handle->param->resolution_height) {
817                 debug_log("[Origin Resolution] Two resolutoin value = 0");
818                 handle->param->resolution_width = handle->property->in_width;
819                 handle->param->resolution_height = handle->property->in_height;
820         }
821
822         if (handle->param->resolution_width < VIDEO_RESOLUTION_WIDTH_SQCIF || handle->param->resolution_height < VIDEO_RESOLUTION_HEIGHT_SQCIF) {
823                 debug_log("The Minimun resolution is SQCIF");
824                 handle->param->resolution_width = VIDEO_RESOLUTION_WIDTH_SQCIF;
825                 handle->param->resolution_height = VIDEO_RESOLUTION_HEIGHT_SQCIF;
826         }
827
828         if (handle->property->in_width < handle->param->resolution_width || handle->property->in_height < handle->param->resolution_height) {
829                 debug_log("[Origin Resolution] resolutoin value > origin resolution");
830                 handle->param->resolution_width = handle->property->in_width;
831                 handle->param->resolution_height = handle->property->in_height;
832         }
833
834         debug_log("[Call CapsFilter] resolution_width: %d, resolution_height: %d", handle->param->resolution_width, handle->param->resolution_height);
835         _mm_transcode_video_capsfilter_call(handle);
836         TRANSCODE_FREE(handle->property->videodecodename);
837 }
838
839 static void _mm_transcode_video_capsfilter_call(handle_s *handle)
840 {
841         if (!handle) {
842                 debug_error("[ERROR] - handle");
843                 return;
844         }
845
846         if (!handle->decoder_vidp) {
847                 debug_error("[ERROR] - handle decoder video process bin");
848                 return;
849         }
850
851         if (!handle->property) {
852                 debug_error("[ERROR] - handle property");
853                 return;
854         }
855
856         /* Configure videoscale to use 4-tap scaling for higher quality */
857         debug_log("Input Width: [%d] Input Hieght: [%d] Output Width: [%d], Output Height: [%d]", handle->property->in_width, handle->property->in_height, handle->param->resolution_width, handle->param->resolution_height);
858
859         g_object_set(G_OBJECT(handle->decoder_vidp->vidflt), "caps", gst_caps_new_simple(handle->property->mime, "format", G_TYPE_STRING, handle->property->format, "width", G_TYPE_INT, handle->param->resolution_width, "height", G_TYPE_INT, handle->param->resolution_height, "framerate", GST_TYPE_FRACTION, handle->property->fps_n, handle->property->fps_d, "pixel-aspect-ratio", GST_TYPE_FRACTION, handle->property->aspect_x, handle->property->aspect_y, NULL), NULL);
860 }
861
862 static void _mm_transcode_video_capsfilter_set_parameter(GstCaps *caps, handle_s *handle)
863 {
864         const GValue *par, *fps;
865
866         if (!handle) {
867                 debug_error("[ERROR] - handle");
868                 return;
869         }
870
871         if (!handle->property) {
872                 debug_error("[ERROR] - handle property");
873                 return;
874         }
875
876         if (!caps) {
877                 debug_error("[ERROR] - caps");
878                 return;
879         }
880
881         GstStructure *_str = gst_caps_get_structure(caps, 0);
882         handle->property->mime = _mm_check_media_type(caps);
883         debug_log("mime: %s", handle->property->mime);
884
885         const gchar *format = gst_structure_get_string(_str, "format");
886         strncpy(handle->property->format, format, sizeof(handle->property->format));
887         handle->property->format[sizeof(handle->property->format) - 1] = '\0';
888
889         switch (gst_video_format_from_string(handle->property->format)) {
890         case GST_VIDEO_FORMAT_I420:
891         case GST_VIDEO_FORMAT_RGB:
892         case GST_VIDEO_FORMAT_NV12:
893                 debug_log("format: %s", handle->property->format);
894                 break;
895
896         case GST_VIDEO_FORMAT_UNKNOWN:
897                 if (strcmp(handle->property->format, "SN12") == 0 || strcmp(handle->property->format, "ST12") == 0)
898                         debug_log("format: %s", handle->property->format);
899
900                 break;
901
902         default:
903                 break;
904         }
905
906         if (!gst_structure_get_int(_str, "width", &handle->property->in_width) || !gst_structure_get_int(_str, "height", &handle->property->in_height))
907                 debug_error("error gst_structure_get_int [width] [height]");
908         else
909                 debug_log("Origin File's Width: [%u] Origin File's Hieght: [%u]", handle->property->in_width, handle->property->in_height);
910
911         fps = gst_structure_get_value(_str, "framerate");
912
913         if (fps) {
914                 handle->property->fps_n = gst_value_get_fraction_numerator(fps);
915                 handle->property->fps_d = gst_value_get_fraction_denominator(fps);
916                 debug_log("[Origin framerate] gst_value_get_fraction_numerator: %d, gst_value_get_fraction_denominator: %d", handle->property->fps_n, handle->property->fps_d);
917         }
918
919         if (handle->param->fps_value >= 5 && handle->param->fps_value <= 30 && handle->param->fps_value <= handle->property->fps_n) {
920                 handle->property->fps_n = (gint) handle->param->fps_value;
921                 handle->property->fps_d = 1;
922         }
923         debug_log("[framerate] gst_value_get_fraction_numerator: %d, gst_value_get_fraction_denominator: %d", handle->property->fps_n, handle->property->fps_d);
924
925         par = gst_structure_get_value(_str, "pixel-aspect-ratio");
926         if (par) {
927                 handle->property->aspect_x = gst_value_get_fraction_numerator(par);
928                 handle->property->aspect_y = gst_value_get_fraction_denominator(par);
929         } else {
930                 handle->property->aspect_x = handle->property->aspect_y = 1;
931         }
932         debug_log("[pixel-aspect-ratio] gst_value_get_fraction_numerator: %d, gst_value_get_fraction_denominator: %d", handle->property->aspect_x, handle->property->aspect_y);
933
934 }
935
936 int _mm_transcode_set_handle_element(handle_s *handle, const char *in_Filename, mm_containerformat_e containerformat, mm_videoencoder_e videoencoder, mm_audioencoder_e audioencoder)
937 {
938         int ret = MM_ERROR_NONE;
939
940         if (!handle) {
941                 debug_error("[ERROR] - handle");
942                 return MM_ERROR_INVALID_ARGUMENT;
943         }
944
945         if (!handle->property) {
946                 debug_error("[ERROR] - handle property");
947                 return MM_ERROR_TRANSCODE_INTERNAL;
948         }
949
950         if (in_Filename == NULL) {
951                 debug_error("Invalid arguments [filename null]\n");
952                 return MM_ERROR_INVALID_ARGUMENT;
953         }
954
955         if (strlen(in_Filename) == 0 || strlen(in_Filename) > BUFFER_SIZE) {
956                 debug_error("Invalid arguments [filename size: %d]\n", strlen(in_Filename));
957                 return MM_ERROR_INVALID_ARGUMENT;
958         }
959
960         handle->property->sourcefile = malloc(sizeof(char) * BUFFER_SIZE);
961         if (handle->property->sourcefile) {
962                 memset(handle->property->sourcefile, 0, BUFFER_SIZE);
963                 strncpy(handle->property->sourcefile, in_Filename, strlen(in_Filename));
964                 debug_log("%s", handle->property->sourcefile);
965         } else {
966                 debug_error("[ERROR] malloc fail of sourcefile");
967                 return MM_ERROR_TRANSCODE_INTERNAL;
968         }
969
970         handle->property->containerformat = containerformat;
971         handle->property->videoencoder = videoencoder;
972         handle->property->audioencoder = audioencoder;
973
974         debug_log("container format: %d videoencoder:%d, audioencoder: %d", handle->property->containerformat, handle->property->videoencoder, handle->property->audioencoder);
975
976         return ret;
977 }
978
979 int _mm_transcode_set_handle_parameter(handle_param_s *param, unsigned int resolution_width, unsigned int resolution_height, unsigned int fps_value, unsigned long start_pos, unsigned long duration, mm_seek_mode_e seek_mode, const char *out_Filename)
980 {
981         int ret = MM_ERROR_NONE;
982
983         if (!param) {
984                 debug_error("param error");
985                 return MM_ERROR_TRANSCODE_INTERNAL;
986         }
987
988         param->resolution_width = resolution_width;
989         param->resolution_height = resolution_height;
990         param->fps_value = fps_value;
991
992         param->start_pos = start_pos;
993         param->duration = duration;
994         param->seek_mode = seek_mode;
995         debug_log("resolution_width: %d, resolution_height: %d, fps_value: %d, start_pos: %d, duration: %d, seek_mode: %d \n", param->resolution_width, param->resolution_height, fps_value, param->start_pos, param->duration, param->seek_mode);
996
997         if (start_pos == 0 && duration == 0)
998                 param->seeking = FALSE;
999         else
1000                 param->seeking = TRUE;
1001
1002         if (out_Filename) {
1003                 param->outputfile = malloc(sizeof(gchar) * BUFFER_SIZE);
1004                 if (!param->outputfile) {
1005                         debug_error("[ERROR] outputfile");
1006                         return MM_ERROR_TRANSCODE_NO_FREE_SPACE;
1007                 }
1008                 memset(param->outputfile, 0, BUFFER_SIZE);
1009                 strncpy(param->outputfile, out_Filename, strlen(out_Filename));
1010                 debug_log("%s(%d)", param->outputfile, strlen(out_Filename));
1011         } else {
1012                 debug_error("out_Filename error");
1013                 return MM_ERROR_INVALID_ARGUMENT;
1014         }
1015
1016         return ret;
1017 }
1018
1019 int _mm_transcode_state_change(handle_s *handle, GstState gst_state)
1020 {
1021         int ret = MM_ERROR_NONE;
1022         GstStateChangeReturn ret_state;
1023
1024         if (gst_state == GST_STATE_NULL)
1025                 debug_log("Before - GST_STATE_NULL");
1026         else if (gst_state == GST_STATE_READY)
1027                 debug_log("Before - GST_STATE_READY");
1028         else if (gst_state == GST_STATE_PAUSED)
1029                 debug_log("Before - GST_STATE_PAUSED");
1030         else if (gst_state == GST_STATE_PLAYING)
1031                 debug_log("Before - GST_STATE_PLAYING");
1032
1033         ret_state = gst_element_set_state(handle->pipeline, gst_state);
1034         if (ret_state == GST_STATE_CHANGE_FAILURE) {
1035                 if (gst_state == GST_STATE_NULL)
1036                         debug_error("ERROR - SET GST_STATE_NULL");
1037                 else if (gst_state == GST_STATE_READY)
1038                         debug_error("ERROR - SET GST_STATE_READY");
1039                 else if (gst_state == GST_STATE_PAUSED)
1040                         debug_error("ERROR - SET GST_STATE_PAUSED");
1041                 else if (gst_state == GST_STATE_PLAYING)
1042                         debug_error("ERROR - SET GST_STATE_PLAYING");
1043
1044                 return MM_ERROR_TRANSCODE_INTERNAL;
1045         } else {
1046                 if (gst_state == GST_STATE_NULL)
1047                         debug_log("Success - SET GST_STATE_NULL");
1048                 else if (gst_state == GST_STATE_READY)
1049                         debug_log("Success - SET GST_STATE_READY");
1050                 else if (gst_state == GST_STATE_PAUSED)
1051                         debug_log("Success - SET GST_STATE_PAUSED");
1052                 else if (gst_state == GST_STATE_PLAYING)
1053                         debug_log("Success - SET GST_STATE_PLAYING");
1054         }
1055
1056         ret_state = gst_element_get_state(handle->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
1057         if (ret_state == GST_STATE_CHANGE_FAILURE) {
1058                 if (gst_state == GST_STATE_NULL)
1059                         debug_error("ERROR - GET GST_STATE_NULL");
1060                 else if (gst_state == GST_STATE_READY)
1061                         debug_error("ERROR - GET GST_STATE_READY");
1062                 else if (gst_state == GST_STATE_PAUSED)
1063                         debug_error("ERROR - GET GST_STATE_PAUSED");
1064                 else if (gst_state == GST_STATE_PLAYING)
1065                         debug_error("ERROR - GET GST_STATE_PLAYING");
1066
1067                 return MM_ERROR_TRANSCODE_INTERNAL;
1068         } else {
1069                 if (gst_state == GST_STATE_NULL)
1070                         debug_log("Success - GET GST_STATE_NULL");
1071                 else if (gst_state == GST_STATE_READY)
1072                         debug_log("Success - GET GST_STATE_READY");
1073                 else if (gst_state == GST_STATE_PAUSED)
1074                         debug_log("Success - GET GST_STATE_PAUSED");
1075                 else if (gst_state == GST_STATE_PLAYING)
1076                         debug_log("Success - GET GST_STATE_PLAYING");
1077         }
1078
1079         return ret;
1080 }
1081
1082 int _mm_transcode_param_flush(handle_s *handle)
1083 {
1084         int ret = MM_ERROR_NONE;
1085
1086         if (!handle) {
1087                 debug_error("[ERROR] - handle");
1088                 return MM_ERROR_INVALID_ARGUMENT;
1089         }
1090
1091         if (!handle->encodebin) {
1092                 debug_error("[ERROR] - handle encodebin");
1093                 return MM_ERROR_TRANSCODE_INTERNAL;
1094         }
1095
1096         if (!handle->property) {
1097                 debug_error("[ERROR] - handle property");
1098                 return MM_ERROR_TRANSCODE_INTERNAL;
1099         }
1100
1101         handle->property->linked_vidoutbin = FALSE;
1102         handle->property->linked_audoutbin = FALSE;
1103         handle->encodebin->encodebin_profile = 0;
1104         handle->property->AUDFLAG = 0;
1105         handle->property->VIDFLAG = 0;
1106         handle->encodebin->audio_event_probe_id = 0;
1107         handle->encodebin->video_event_probe_id = 0;
1108
1109         handle->property->total_length = 0;
1110         handle->property->repeat_thread_exit = FALSE;
1111         handle->property->is_busy = FALSE;
1112         handle->property->audio_cb_probe_id = 0;
1113         handle->property->video_cb_probe_id = 0;
1114         handle->property->progrss_event_id = 0;
1115         handle->property->seek_idx = 0;
1116
1117         return ret;
1118 }
1119
1120 static int _mm_transcode_play(handle_s *handle)
1121 {
1122         int ret = MM_ERROR_NONE;
1123
1124         if (!handle) {
1125                 debug_error("[ERROR] - handle");
1126                 return MM_ERROR_INVALID_ARGUMENT;
1127         }
1128
1129         if (!handle->property) {
1130                 debug_error("[ERROR] - handle property");
1131                 return MM_ERROR_TRANSCODE_INTERNAL;
1132         }
1133
1134         ret = _mm_transcode_state_change(handle, GST_STATE_PLAYING);
1135         if (ret != MM_ERROR_NONE) {
1136                 debug_error("ERROR -Playing Pipeline");
1137                 return ret;
1138         }
1139
1140         debug_log("[SEEK: %d] width: %d height: %d start_pos: %d duration: %d (%d) seek_mode: %d outputfile: %s", handle->param->seeking, handle->param->resolution_width, handle->param->resolution_height, handle->param->start_pos, handle->param->duration, handle->property->end_pos, handle->param->seek_mode, handle->param->outputfile);
1141
1142         handle->property->progrss_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc) _mm_cb_print_position, handle);
1143         debug_log("Timer (id=[%d], timeout=[%d ms])\n", handle->property->progrss_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
1144
1145         return ret;
1146 }
1147
1148 static int _mm_transcode_seek(handle_s *handle)
1149 {
1150         int ret = MM_ERROR_NONE;
1151
1152         if (!handle) {
1153                 debug_error("[ERROR] - handle");
1154                 return MM_ERROR_INVALID_ARGUMENT;
1155         }
1156
1157         if (!handle->property) {
1158                 debug_error("[ERROR] - handle property");
1159                 return MM_ERROR_TRANSCODE_INTERNAL;
1160         }
1161
1162         GList *walk_element = handle->property->sink_elements;
1163         gint64 start_pos, end_pos;
1164         gdouble rate = 1.0;
1165         GstSeekFlags _Flags = GST_SEEK_FLAG_NONE;
1166
1167         start_pos = handle->param->start_pos * G_GINT64_CONSTANT(1000000);
1168         handle->property->end_pos = handle->param->start_pos + handle->param->duration;
1169
1170         if (handle->param->start_pos > handle->property->total_length && handle->property->seek_idx) {
1171                 debug_error("[%d ~ %d] out of %d", handle->param->start_pos, handle->property->end_pos, handle->property->total_length);
1172                 return MM_ERROR_TRANSCODE_SEEK_FAILED;
1173         } else {
1174                 if (handle->param->duration != 0) {
1175                         end_pos = start_pos + handle->param->duration * G_GINT64_CONSTANT(1000000);
1176                 } else if (handle->param->duration == 0) {
1177                         /* seek to origin file length */
1178                         end_pos = handle->property->total_length * G_GINT64_CONSTANT(1000000);
1179                 }
1180
1181                 debug_log("seek time : [ (%d msec) : (%d msec) ]\n", handle->param->start_pos, handle->property->end_pos);
1182
1183                 while (walk_element) {
1184                         GstElement *seekable_element = GST_ELEMENT(walk_element->data);
1185
1186                         if (!seekable_element) {
1187                                 debug_error("ERROR - seekable");
1188                                 return MM_ERROR_TRANSCODE_INTERNAL;
1189                         }
1190
1191                         if (handle->param->seek_mode == MM_SEEK_ACCURATE)
1192                                 _Flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH;
1193                         else if (handle->param->seek_mode == MM_SEEK_INACCURATE)
1194                                 _Flags = GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH;
1195
1196                         if (!gst_element_seek(seekable_element, rate, GST_FORMAT_TIME, _Flags, GST_SEEK_TYPE_SET, start_pos, GST_SEEK_TYPE_SET, end_pos)) {
1197                                 debug_error("ERROR - gst_element_seek (on) event : %s", GST_OBJECT_NAME(GST_OBJECT_CAST(seekable_element)));
1198                                 return MM_ERROR_TRANSCODE_SEEK_FAILED;
1199                         }
1200
1201                         if (walk_element)
1202                                 walk_element = g_list_next(walk_element);
1203                 }
1204         }
1205
1206         return ret;
1207 }
1208
1209 int _mm_transcode_thread(handle_s *handle)
1210 {
1211         int ret = MM_ERROR_NONE;
1212
1213         if (!handle) {
1214                 debug_error("[ERROR] - handle");
1215                 return MM_ERROR_INVALID_ARGUMENT;
1216         }
1217
1218         if (!handle->property) {
1219                 debug_error("[ERROR] - handle property");
1220                 return MM_ERROR_TRANSCODE_INTERNAL;
1221         }
1222
1223         if (!handle->property->thread_mutex) {
1224                 handle->property->thread_mutex = g_new(GMutex, 1);
1225                 g_mutex_init(handle->property->thread_mutex);
1226                 debug_log("create thread_mutex: 0x%2x", handle->property->thread_mutex);
1227         } else {
1228                 debug_error("ERROR - thread_mutex is already created");
1229         }
1230
1231         if (!handle->property->thread_exit_mutex) {
1232                 handle->property->thread_exit_mutex = g_new(GMutex, 1);
1233                 g_mutex_init(handle->property->thread_exit_mutex);
1234                 debug_log("create exit mutex: 0x%2x", handle->property->thread_exit_mutex);
1235         } else {
1236                 debug_error("ERROR - thread_exit_mutex is already created");
1237         }
1238
1239         /* These are a communicator for thread */
1240         if (!handle->property->queue) {
1241                 handle->property->queue = g_async_queue_new();
1242                 debug_log("create async queue: 0x%2x", handle->property->queue);
1243         } else {
1244                 debug_error("ERROR - async queue is already created");
1245         }
1246
1247         if (!handle->property->thread_cond) {
1248                 handle->property->thread_cond = g_new(GCond, 1);
1249                 g_cond_init(handle->property->thread_cond);
1250                 debug_log("create thread cond: 0x%2x", handle->property->thread_cond);
1251         } else {
1252                 debug_error("thread cond is already created");
1253         }
1254
1255         /* create threads */
1256         debug_log("create thread");
1257         handle->property->thread = g_thread_new(NULL, (GThreadFunc)_mm_transcode_thread_repeate, (gpointer)handle);
1258         if (!handle->property->thread) {
1259                 debug_error("ERROR - create thread");
1260                 return MM_ERROR_TRANSCODE_INTERNAL;
1261         } else {
1262                 debug_log("create thread: 0x%2x", handle->property->thread);
1263         }
1264
1265         return ret;
1266 }
1267
1268 static gpointer _mm_transcode_thread_repeate(gpointer data)
1269 {
1270         handle_s *handle = (handle_s *) data;
1271         int ret = MM_ERROR_NONE;
1272
1273         if (!handle) {
1274                 debug_error("[ERROR] - handle");
1275                 return NULL;
1276         }
1277
1278         if (!handle->property) {
1279                 debug_error("[ERROR] - handle property");
1280                 return NULL;
1281         }
1282
1283         /* thread while */
1284         while (1) {
1285                 int length = g_async_queue_length(handle->property->queue);
1286                 if (length) {
1287                         debug_log("[QUEUE #] %d", length);
1288                         handle->property->is_busy = TRUE;
1289                 }
1290
1291                 handle_param_s *pop_data = (handle_param_s *) g_async_queue_pop(handle->property->queue);
1292
1293                 if (handle->property->repeat_thread_exit || !handle->property->is_busy) {
1294                         debug_log("[Receive Last Queue]");
1295                         debug_log("[Destroy]");
1296                         break;
1297                 } else {
1298                         debug_log("[pop queue] resolution_width: %d, resolution_height: %d, start_pos: %d, duration: %d, seek_mode: %d outputfile: %s\n", pop_data->resolution_width, pop_data->resolution_height, pop_data->start_pos, pop_data->duration, pop_data->seek_mode, pop_data->outputfile);
1299
1300                         /* Need to block */
1301                         ret = _mm_transcode_exec(handle, pop_data);
1302                         if (ret == MM_ERROR_NONE) {
1303                                 debug_log("Success - transcode_exec");
1304                         } else {
1305                                 debug_log("Destroy - transcode_exec");
1306                                 debug_log("<=== get exit (%d) signal", handle->property->repeat_thread_exit);
1307                                 break;
1308                         }
1309                 }
1310         }
1311         debug_log("exit thread");
1312         return NULL;
1313 }