6e70b1af25ccb7cc9721e23d0b29a0cc59a6554e
[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                 LOGE("[ERROR] - handle");
39                 return GST_PAD_PROBE_REMOVE;
40         }
41
42         if (!handle->property) {
43                 LOGE("[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                 LOGE("[ERROR] - handle");
82                 return GST_PAD_PROBE_REMOVE;
83         }
84
85         if (!handle->property) {
86                 LOGE("[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                 LOGE("[ERROR] - handle");
125                 return GST_PAD_PROBE_REMOVE;
126         }
127
128         if (!handle->property) {
129                 LOGE("[ERROR] - handle property");
130                 return GST_PAD_PROBE_REMOVE;
131         }
132
133         if (!event) {
134                 LOGE("[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                                 LOGE("[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                 LOGE("[ERROR] - handle");
182                 return MM_ERROR_INVALID_ARGUMENT;
183         }
184
185         if (!handle->property) {
186                 LOGE("[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                         LOGE("audiodecodename is NULL");
195                         return GST_AUTOPLUG_SELECT_TRY;
196                 }
197                 memset(handle->property->audiodecodename, 0, ENC_BUFFER_SIZE);
198                 g_strlcpy(handle->property->audiodecodename, feature_name, ENC_BUFFER_SIZE);
199                 LOGD("[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                         LOGD("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                         LOGE("videodecodename is NULL");
211                         return GST_AUTOPLUG_SELECT_TRY;
212                 }
213                 memset(handle->property->videodecodename, 0, ENC_BUFFER_SIZE);
214                 g_strlcpy(handle->property->videodecodename, feature_name, ENC_BUFFER_SIZE);
215                 LOGD("[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                 LOGE("[ERROR] - handle");
226                 return;
227         }
228
229         if (!handle->decoder_vidp) {
230                 LOGE("[ERROR] - handle decoder_vidp");
231                 return;
232         }
233
234         if (!handle->decoder_audp) {
235                 LOGE("[ERROR] - handle decoder_audp");
236                 return;
237         }
238
239         if (!handle->encodebin) {
240                 LOGE("[ERROR] - handle encodebin");
241                 return;
242         }
243
244         if (!handle->property) {
245                 LOGE("[ERROR] - handle property");
246                 return;
247         }
248
249         LOGD("[============ 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                 LOGE("[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                         LOGD("pad liked");
264                 } else {
265                         if (gst_pad_link(pad, (GstPad *) handle->decoder_vidp->sinkdecvideopad) != GST_PAD_LINK_OK)
266                                 LOGE("Error [pad - sinkdecvideopad]");
267                         else
268                                 LOGD("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                         LOGD("pad liked");
277                 } else {
278                         if (gst_pad_link(pad, (GstPad *) handle->decoder_audp->sinkdecaudiopad) != GST_PAD_LINK_OK)
279                                 LOGE("Error [pad - sinkdecaudiopad]");
280                         else
281                                 LOGD("Success [pad - sinkdecaudiopad]");
282                 }
283
284         } else {
285                 LOGD("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                 LOGE("[ERROR] - handle");
296                 return FALSE;
297         }
298
299         if (!handle->property) {
300                 LOGE("[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                 LOGE("[ERROR] - handle");
350                 return FALSE;
351         }
352
353         if (!handle->property) {
354                 LOGE("[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                                 LOGW("Fail to parse error message");
371                                 break;
372                         }
373
374                         LOGE("[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                                 LOGD("Success - Cancel Transcode");
379                         } else {
380                                 LOGE("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                         LOGD("[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                                 LOGD("[Set State: Pause]");
405                                 /* Pause Transcode */
406                                 ret = _mm_transcode_state_change(handle, GST_STATE_PAUSED);
407                                 if (ret == MM_ERROR_NONE) {
408                                         LOGD("Success - Pause pipeline");
409                                 } else {
410                                         LOGE("ERROR - Pause pipeline");
411                                         return FALSE;
412                                 }
413                         }
414
415                         if (State_Old == GST_STATE_READY && State_New == GST_STATE_PAUSED) {
416                                 /* Seek */
417                                 LOGD("[%s] Start New Segment pipeline", handle->param->outputfile);
418                                 ret = _mm_transcode_seek(handle);
419
420                                 if (ret == MM_ERROR_NONE) {
421                                         LOGD("Success - Set New Segment pipeline");
422                                 } else {
423                                         LOGD("[Null Trancode]");
424                                         if (_mm_transcode_state_change(handle, GST_STATE_NULL) != MM_ERROR_NONE) {
425                                                 LOGE("ERROR -Null Pipeline");
426                                                 return FALSE;
427                                         }
428                                         g_mutex_lock(handle->property->thread_mutex);
429                                         LOGD("[g_mutex_lock]");
430                                         TRANSCODE_FREE(handle->param);
431                                         LOGD("g_free(param)");
432                                         g_cond_signal(handle->property->thread_cond);
433                                         LOGD("[g_cond_signal]");
434                                         g_mutex_unlock(handle->property->thread_mutex);
435                                         LOGD("[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                                 LOGD("[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                         LOGD("GST_MESSAGE_ASYNC_DONE");
454
455                         /* Play Transcode */
456                         LOGD("[Play Trancode] [%lu ~ %lu]", handle->param->start_pos, handle->property->end_pos);
457
458                         if (_mm_transcode_play(handle) != MM_ERROR_NONE) {
459                                 LOGE("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                         LOGD("GST_MESSAGE_SEGMENT_DONE");
472                         break;
473                 }
474
475         case GST_MESSAGE_EOS:
476                 {
477                         /* end-of-stream */
478                         LOGD("[GST_MESSAGE_EOS] end-of-stream");
479
480                         LOGD("[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                         LOGD("[Null Trancode]");
486                         if (_mm_transcode_state_change(handle, GST_STATE_NULL) != MM_ERROR_NONE) {
487                                 LOGE("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                                 LOGD("[unlink] %s %lu > %lu", 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                         LOGD("===> send completed signal");
500                         g_mutex_unlock(handle->property->thread_mutex);
501
502                         LOGD("[MMHandle] %p [msg_cb] %p [msg_cb_param] %p", 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                 /*LOGD("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                 LOGE("[ERROR] - handle");
526                 return;
527         }
528
529         if (!handle->encodebin) {
530                 LOGE("[ERROR] - handle encodebin");
531                 return;
532         }
533
534         if (!handle->property) {
535                 LOGE("[ERROR] - handle property");
536                 return;
537         }
538
539         if (!caps) {
540                 LOGE("[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                 LOGD("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                 LOGE("[ERROR] - handle");
569                 return MM_ERROR_INVALID_ARGUMENT;
570         }
571
572         ret = _mm_decodesrcbin_create(handle);
573         if (ret == MM_ERROR_NONE) {
574                 LOGD("Success - Create decodesrcbin");
575         } else {
576                 LOGE("ERROR - Create decodesrcbin");
577                 return ret;
578         }
579
580         ret = _mm_encodebin_set_venc_aenc(handle);
581         if (ret == MM_ERROR_NONE) {
582                 LOGD("Success - Setup video and audio encoder of encodebin");
583         } else {
584                 LOGE("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                 LOGD("Success - Create encodebin");
591         } else {
592                 LOGE("ERROR - Create encodebin");
593                 return ret;
594         }
595
596         /*create filesink */
597         ret = _mm_filesink_create(handle);
598         if (ret == MM_ERROR_NONE) {
599                 LOGD("Success - Create Filesink");
600         } else {
601                 LOGE("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                 LOGE("[ERROR] - handle");
614                 return MM_ERROR_INVALID_ARGUMENT;
615         }
616
617         if (!handle->property) {
618                 LOGE("[ERROR] - handle property");
619                 return MM_ERROR_TRANSCODE_INTERNAL;
620         }
621
622         if (!param || !param->outputfile) {
623                 LOGE("[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                 LOGD("unlock destory");
632         } else {
633                 LOGD("start_pos: %lu, duration: %lu, 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                         LOGE("[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                 g_strlcpy(handle->param->outputfile, param->outputfile, BUFFER_SIZE);
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                 LOGD("[SEEK: %d] width: %d height: %d fps_value: %d start_pos: %lu duration: %lu seek_mode: %d outputfile: %s",
663                         handle->param->seeking, handle->param->resolution_width, handle->param->resolution_height,
664                         handle->param->fps_value, handle->param->start_pos, handle->param->duration,
665                         handle->param->seek_mode, handle->param->outputfile);
666
667                 if (handle->property->total_length != 0 && handle->param->start_pos > handle->property->total_length) {
668                         LOGD("[SKIP] [%s] because out of duration [%lu < %lu ~ %lu] ", handle->param->outputfile, handle->property->total_length, handle->param->start_pos, handle->param->duration);
669                         g_mutex_unlock(handle->property->thread_mutex);
670                         LOGD("[thread_mutex unlock]");
671                 } else {
672                         g_object_set(G_OBJECT(handle->filesink), "location", handle->param->outputfile, NULL);
673                         LOGD("[%s] set filesink location", handle->param->outputfile);
674
675                         /* Ready Transcode */
676                         if (strlen(handle->param->outputfile) != 0) {
677                                 LOGD("[Set State: Ready]");
678                                 ret = _mm_transcode_state_change(handle, GST_STATE_READY);
679                                 if (ret == MM_ERROR_NONE) {
680                                         LOGD("Success - Ready pipeline");
681                                 } else {
682                                         LOGE("ERROR - Reay pipeline");
683                                         g_mutex_unlock(handle->property->thread_mutex);
684                                         return ret;
685                                 }
686                         }
687
688                         if (0 == handle->property->seek_idx) {
689                                 LOGD("Link Filesink");
690                                 /* link filesink */
691                                 ret = _mm_filesink_link(handle);
692                                 if (ret == MM_ERROR_NONE) {
693                                         LOGD("Success - Link Filesink");
694                                 } else {
695                                         LOGE("ERROR - Link Filesink");
696                                         g_mutex_unlock(handle->property->thread_mutex);
697                                         return ret;
698                                 }
699                         }
700
701                         g_cond_wait(handle->property->thread_cond, handle->property->thread_mutex);
702                         LOGD("<=== get completed signal");
703                         g_mutex_unlock(handle->property->thread_mutex);
704                 }
705         }
706
707         return ret;
708 }
709
710 int _mm_transcode_get_stream_info(handle_s *handle)
711 {
712         int ret = MM_ERROR_NONE;
713
714         if (!handle) {
715                 LOGE("[ERROR] - handle");
716                 return MM_ERROR_INVALID_ARGUMENT;
717         }
718
719         if (!handle->property) {
720                 LOGE("[ERROR] - handle property");
721                 return MM_ERROR_TRANSCODE_INTERNAL;
722         }
723
724         if (strlen(handle->property->sourcefile) == 0) {
725                 LOGE("Invalid arguments [sourcefile size 0]\n");
726                 return MM_ERROR_INVALID_ARGUMENT;
727         }
728
729         int audio_track_num = 0;
730         int video_track_num = 0;
731
732         ret = mm_file_get_stream_info(handle->property->sourcefile, &audio_track_num, &video_track_num);
733         if (ret == MM_ERROR_NONE) {
734                 LOGD("Success - mm_file_get_stream_info");
735         } else {
736                 LOGE("ERROR - mm_file_get_stream_info");
737                 return MM_ERROR_TRANSCODE_INTERNAL;
738         }
739
740         if (audio_track_num)
741                 handle->property->has_audio_stream = TRUE;
742         else
743                 handle->property->has_audio_stream = FALSE;
744
745         LOGD("has_audio_stream: %d", handle->property->has_audio_stream);
746
747         if (video_track_num)
748                 handle->property->has_video_stream = TRUE;
749         else
750                 handle->property->has_video_stream = FALSE;
751
752         LOGD("has_video_stream: %d", handle->property->has_video_stream);
753
754         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)) {
755                 LOGE("No video || audio stream");
756                 return MM_ERROR_INVALID_ARGUMENT;
757         }
758
759         return ret;
760 }
761
762 int _mm_transcode_link(handle_s *handle)
763 {
764         int ret = MM_ERROR_NONE;
765
766         if (!handle) {
767                 LOGE("[ERROR] - handle");
768                 return MM_ERROR_INVALID_ARGUMENT;
769         }
770
771         ret = _mm_decodesrcbin_link(handle);
772         if (ret == MM_ERROR_NONE) {
773                 LOGD("Success - decodesrcbin link");
774         } else {
775                 LOGE("ERROR - decodesrcbin link");
776                 return ret;
777         }
778
779         ret = _mm_encodebin_link(handle);
780         if (ret == MM_ERROR_NONE) {
781                 LOGD("Success - encodebin link");
782         } else {
783                 LOGE("ERROR - encodebin link");
784                 return ret;
785         }
786
787         return ret;
788 }
789
790 static void _mm_transcode_video_capsfilter(GstCaps *caps, handle_s *handle)
791 {
792         if (!handle) {
793                 LOGE("[ERROR] - handle");
794                 return;
795         }
796
797         if (!handle->property) {
798                 LOGE("[ERROR] - handle property");
799                 return;
800         }
801
802         if (!caps) {
803                 LOGE("[ERROR] - caps");
804                 TRANSCODE_FREE(handle->property->videodecodename);
805                 return;
806         }
807
808         LOGD("[First Video Buffer] Set CapsFilter Parameter");
809         _mm_transcode_video_capsfilter_set_parameter(caps, handle);
810
811         /* Not support enlarge video resolution */
812         LOGD("Execute Resize");
813 #if 0
814         /* Not irrelevant to the ratio */
815         handle->param->resolution_height = handle->param->resolution_width * handle->in_height / handle->in_width;
816 #endif
817
818         LOGD("[Resize] resolution_width: %d, resolution_height: %d", handle->param->resolution_width, handle->param->resolution_height);
819         if (0 == handle->param->resolution_width || 0 == handle->param->resolution_height) {
820                 LOGD("[Origin Resolution] Two resolutoin value = 0");
821                 handle->param->resolution_width = handle->property->in_width;
822                 handle->param->resolution_height = handle->property->in_height;
823         }
824
825         if (handle->param->resolution_width < VIDEO_RESOLUTION_WIDTH_SQCIF || handle->param->resolution_height < VIDEO_RESOLUTION_HEIGHT_SQCIF) {
826                 LOGD("The Minimun resolution is SQCIF");
827                 handle->param->resolution_width = VIDEO_RESOLUTION_WIDTH_SQCIF;
828                 handle->param->resolution_height = VIDEO_RESOLUTION_HEIGHT_SQCIF;
829         }
830
831         if (handle->property->in_width < handle->param->resolution_width || handle->property->in_height < handle->param->resolution_height) {
832                 LOGD("[Origin Resolution] resolutoin value > origin resolution");
833                 handle->param->resolution_width = handle->property->in_width;
834                 handle->param->resolution_height = handle->property->in_height;
835         }
836
837         LOGD("[Call CapsFilter] resolution_width: %d, resolution_height: %d", handle->param->resolution_width, handle->param->resolution_height);
838         _mm_transcode_video_capsfilter_call(handle);
839         TRANSCODE_FREE(handle->property->videodecodename);
840 }
841
842 static void _mm_transcode_video_capsfilter_call(handle_s *handle)
843 {
844         if (!handle) {
845                 LOGE("[ERROR] - handle");
846                 return;
847         }
848
849         if (!handle->decoder_vidp) {
850                 LOGE("[ERROR] - handle decoder video process bin");
851                 return;
852         }
853
854         if (!handle->property) {
855                 LOGE("[ERROR] - handle property");
856                 return;
857         }
858
859         /* Configure videoscale to use 4-tap scaling for higher quality */
860         LOGD("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);
861
862         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);
863 }
864
865 static void _mm_transcode_video_capsfilter_set_parameter(GstCaps *caps, handle_s *handle)
866 {
867         const GValue *par, *fps;
868
869         if (!handle) {
870                 LOGE("[ERROR] - handle");
871                 return;
872         }
873
874         if (!handle->property) {
875                 LOGE("[ERROR] - handle property");
876                 return;
877         }
878
879         if (!caps) {
880                 LOGE("[ERROR] - caps");
881                 return;
882         }
883
884         GstStructure *_str = gst_caps_get_structure(caps, 0);
885         handle->property->mime = _mm_check_media_type(caps);
886         LOGD("mime: %s", handle->property->mime);
887
888         const gchar *format = gst_structure_get_string(_str, "format");
889         g_strlcpy(handle->property->format, format, sizeof(handle->property->format));
890
891         switch (gst_video_format_from_string(handle->property->format)) {
892         case GST_VIDEO_FORMAT_I420:
893         case GST_VIDEO_FORMAT_RGB:
894         case GST_VIDEO_FORMAT_NV12:
895                 LOGD("format: %s", handle->property->format);
896                 break;
897
898         case GST_VIDEO_FORMAT_UNKNOWN:
899                 if (strcmp(handle->property->format, "SN12") == 0 || strcmp(handle->property->format, "ST12") == 0)
900                         LOGD("format: %s", handle->property->format);
901
902                 break;
903
904         default:
905                 break;
906         }
907
908         if (!gst_structure_get_int(_str, "width", &handle->property->in_width) || !gst_structure_get_int(_str, "height", &handle->property->in_height))
909                 LOGE("error gst_structure_get_int [width] [height]");
910         else
911                 LOGD("Origin File's Width: [%u] Origin File's Hieght: [%u]", handle->property->in_width, handle->property->in_height);
912
913         fps = gst_structure_get_value(_str, "framerate");
914
915         if (fps) {
916                 handle->property->fps_n = gst_value_get_fraction_numerator(fps);
917                 handle->property->fps_d = gst_value_get_fraction_denominator(fps);
918                 LOGD("[Origin framerate] gst_value_get_fraction_numerator: %d, gst_value_get_fraction_denominator: %d", handle->property->fps_n, handle->property->fps_d);
919         }
920
921         if (handle->param->fps_value >= 5 && handle->param->fps_value <= 30 && handle->param->fps_value <= handle->property->fps_n) {
922                 handle->property->fps_n = (gint) handle->param->fps_value;
923                 handle->property->fps_d = 1;
924         }
925         LOGD("[framerate] gst_value_get_fraction_numerator: %d, gst_value_get_fraction_denominator: %d", handle->property->fps_n, handle->property->fps_d);
926
927         par = gst_structure_get_value(_str, "pixel-aspect-ratio");
928         if (par) {
929                 handle->property->aspect_x = gst_value_get_fraction_numerator(par);
930                 handle->property->aspect_y = gst_value_get_fraction_denominator(par);
931         } else {
932                 handle->property->aspect_x = handle->property->aspect_y = 1;
933         }
934         LOGD("[pixel-aspect-ratio] gst_value_get_fraction_numerator: %d, gst_value_get_fraction_denominator: %d", handle->property->aspect_x, handle->property->aspect_y);
935
936 }
937
938 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)
939 {
940         int ret = MM_ERROR_NONE;
941
942         if (!handle) {
943                 LOGE("[ERROR] - handle");
944                 return MM_ERROR_INVALID_ARGUMENT;
945         }
946
947         if (!handle->property) {
948                 LOGE("[ERROR] - handle property");
949                 return MM_ERROR_TRANSCODE_INTERNAL;
950         }
951
952         if (in_Filename == NULL) {
953                 LOGE("Invalid arguments [filename null]\n");
954                 return MM_ERROR_INVALID_ARGUMENT;
955         }
956
957         if (strlen(in_Filename) == 0 || strlen(in_Filename) > BUFFER_SIZE) {
958                 LOGE("Invalid arguments [filename size: %d]\n", strlen(in_Filename));
959                 return MM_ERROR_INVALID_ARGUMENT;
960         }
961
962         handle->property->sourcefile = malloc(sizeof(char) * BUFFER_SIZE);
963         if (handle->property->sourcefile) {
964                 memset(handle->property->sourcefile, 0, BUFFER_SIZE);
965                 g_strlcpy(handle->property->sourcefile, in_Filename, BUFFER_SIZE);
966                 LOGD("%s", handle->property->sourcefile);
967         } else {
968                 LOGE("[ERROR] malloc fail of sourcefile");
969                 return MM_ERROR_TRANSCODE_INTERNAL;
970         }
971
972         handle->property->containerformat = containerformat;
973         handle->property->videoencoder = videoencoder;
974         handle->property->audioencoder = audioencoder;
975
976         LOGD("container format: %d videoencoder:%d, audioencoder: %d", handle->property->containerformat, handle->property->videoencoder, handle->property->audioencoder);
977
978         return ret;
979 }
980
981 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)
982 {
983         int ret = MM_ERROR_NONE;
984
985         if (!param) {
986                 LOGE("param error");
987                 return MM_ERROR_TRANSCODE_INTERNAL;
988         }
989
990         param->resolution_width = resolution_width;
991         param->resolution_height = resolution_height;
992         param->fps_value = fps_value;
993
994         param->start_pos = start_pos;
995         param->duration = duration;
996         param->seek_mode = seek_mode;
997         LOGD("resolution_width: %d, resolution_height: %d, fps_value: %d, start_pos: %lu, duration: %lu, seek_mode: %d \n",
998                 param->resolution_width, param->resolution_height, fps_value, param->start_pos, param->duration, param->seek_mode);
999
1000         if (start_pos == 0 && duration == 0)
1001                 param->seeking = FALSE;
1002         else
1003                 param->seeking = TRUE;
1004
1005         if (out_Filename) {
1006                 param->outputfile = malloc(sizeof(gchar) * BUFFER_SIZE);
1007                 if (!param->outputfile) {
1008                         LOGE("[ERROR] outputfile");
1009                         return MM_ERROR_TRANSCODE_NO_FREE_SPACE;
1010                 }
1011                 memset(param->outputfile, 0, BUFFER_SIZE);
1012                 g_strlcpy(param->outputfile, out_Filename, BUFFER_SIZE);
1013                 LOGD("%s(%d)", param->outputfile, strlen(out_Filename));
1014         } else {
1015                 LOGE("out_Filename error");
1016                 return MM_ERROR_INVALID_ARGUMENT;
1017         }
1018
1019         return ret;
1020 }
1021
1022 int _mm_transcode_state_change(handle_s *handle, GstState gst_state)
1023 {
1024         int ret = MM_ERROR_NONE;
1025         GstStateChangeReturn ret_state;
1026
1027         if (gst_state == GST_STATE_NULL)
1028                 LOGD("Before - GST_STATE_NULL");
1029         else if (gst_state == GST_STATE_READY)
1030                 LOGD("Before - GST_STATE_READY");
1031         else if (gst_state == GST_STATE_PAUSED)
1032                 LOGD("Before - GST_STATE_PAUSED");
1033         else if (gst_state == GST_STATE_PLAYING)
1034                 LOGD("Before - GST_STATE_PLAYING");
1035
1036         ret_state = gst_element_set_state(handle->pipeline, gst_state);
1037         if (ret_state == GST_STATE_CHANGE_FAILURE) {
1038                 if (gst_state == GST_STATE_NULL)
1039                         LOGE("ERROR - SET GST_STATE_NULL");
1040                 else if (gst_state == GST_STATE_READY)
1041                         LOGE("ERROR - SET GST_STATE_READY");
1042                 else if (gst_state == GST_STATE_PAUSED)
1043                         LOGE("ERROR - SET GST_STATE_PAUSED");
1044                 else if (gst_state == GST_STATE_PLAYING)
1045                         LOGE("ERROR - SET GST_STATE_PLAYING");
1046
1047                 return MM_ERROR_TRANSCODE_INTERNAL;
1048         } else {
1049                 if (gst_state == GST_STATE_NULL)
1050                         LOGD("Success - SET GST_STATE_NULL");
1051                 else if (gst_state == GST_STATE_READY)
1052                         LOGD("Success - SET GST_STATE_READY");
1053                 else if (gst_state == GST_STATE_PAUSED)
1054                         LOGD("Success - SET GST_STATE_PAUSED");
1055                 else if (gst_state == GST_STATE_PLAYING)
1056                         LOGD("Success - SET GST_STATE_PLAYING");
1057         }
1058
1059         ret_state = gst_element_get_state(handle->pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
1060         if (ret_state == GST_STATE_CHANGE_FAILURE) {
1061                 if (gst_state == GST_STATE_NULL)
1062                         LOGE("ERROR - GET GST_STATE_NULL");
1063                 else if (gst_state == GST_STATE_READY)
1064                         LOGE("ERROR - GET GST_STATE_READY");
1065                 else if (gst_state == GST_STATE_PAUSED)
1066                         LOGE("ERROR - GET GST_STATE_PAUSED");
1067                 else if (gst_state == GST_STATE_PLAYING)
1068                         LOGE("ERROR - GET GST_STATE_PLAYING");
1069
1070                 return MM_ERROR_TRANSCODE_INTERNAL;
1071         } else {
1072                 if (gst_state == GST_STATE_NULL)
1073                         LOGD("Success - GET GST_STATE_NULL");
1074                 else if (gst_state == GST_STATE_READY)
1075                         LOGD("Success - GET GST_STATE_READY");
1076                 else if (gst_state == GST_STATE_PAUSED)
1077                         LOGD("Success - GET GST_STATE_PAUSED");
1078                 else if (gst_state == GST_STATE_PLAYING)
1079                         LOGD("Success - GET GST_STATE_PLAYING");
1080         }
1081
1082         return ret;
1083 }
1084
1085 int _mm_transcode_param_flush(handle_s *handle)
1086 {
1087         int ret = MM_ERROR_NONE;
1088
1089         if (!handle) {
1090                 LOGE("[ERROR] - handle");
1091                 return MM_ERROR_INVALID_ARGUMENT;
1092         }
1093
1094         if (!handle->encodebin) {
1095                 LOGE("[ERROR] - handle encodebin");
1096                 return MM_ERROR_TRANSCODE_INTERNAL;
1097         }
1098
1099         if (!handle->property) {
1100                 LOGE("[ERROR] - handle property");
1101                 return MM_ERROR_TRANSCODE_INTERNAL;
1102         }
1103
1104         handle->property->linked_vidoutbin = FALSE;
1105         handle->property->linked_audoutbin = FALSE;
1106         handle->encodebin->encodebin_profile = 0;
1107         handle->property->AUDFLAG = 0;
1108         handle->property->VIDFLAG = 0;
1109         handle->encodebin->audio_event_probe_id = 0;
1110         handle->encodebin->video_event_probe_id = 0;
1111
1112         handle->property->total_length = 0;
1113         handle->property->repeat_thread_exit = FALSE;
1114         handle->property->is_busy = FALSE;
1115         handle->property->audio_cb_probe_id = 0;
1116         handle->property->video_cb_probe_id = 0;
1117         handle->property->progress_event_id = 0;
1118         handle->property->seek_idx = 0;
1119
1120         return ret;
1121 }
1122
1123 static int _mm_transcode_play(handle_s *handle)
1124 {
1125         int ret = MM_ERROR_NONE;
1126
1127         if (!handle) {
1128                 LOGE("[ERROR] - handle");
1129                 return MM_ERROR_INVALID_ARGUMENT;
1130         }
1131
1132         if (!handle->property) {
1133                 LOGE("[ERROR] - handle property");
1134                 return MM_ERROR_TRANSCODE_INTERNAL;
1135         }
1136
1137         ret = _mm_transcode_state_change(handle, GST_STATE_PLAYING);
1138         if (ret != MM_ERROR_NONE) {
1139                 LOGE("ERROR -Playing Pipeline");
1140                 return ret;
1141         }
1142
1143         LOGD("[SEEK: %d] width: %d height: %d start_pos: %lu duration: %lu (%lu) seek_mode: %d outputfile: %s",
1144                 handle->param->seeking, handle->param->resolution_width, handle->param->resolution_height,
1145                 handle->param->start_pos, handle->param->duration, handle->property->end_pos,
1146                 handle->param->seek_mode, handle->param->outputfile);
1147
1148         if (!handle->property->progress_event_id) {
1149                 handle->property->progress_event_id = g_timeout_add(LAZY_PAUSE_TIMEOUT_MSEC, (GSourceFunc) _mm_cb_print_position, handle);
1150                 LOGD("Timer (id=[%d], timeout=[%d ms])\n", handle->property->progress_event_id, LAZY_PAUSE_TIMEOUT_MSEC);
1151         }
1152
1153         return ret;
1154 }
1155
1156 static int _mm_transcode_seek(handle_s *handle)
1157 {
1158         int ret = MM_ERROR_NONE;
1159
1160         if (!handle) {
1161                 LOGE("[ERROR] - handle");
1162                 return MM_ERROR_INVALID_ARGUMENT;
1163         }
1164
1165         if (!handle->property) {
1166                 LOGE("[ERROR] - handle property");
1167                 return MM_ERROR_TRANSCODE_INTERNAL;
1168         }
1169
1170         GList *walk_element = handle->property->sink_elements;
1171         gint64 start_pos, end_pos;
1172         gdouble rate = 1.0;
1173         GstSeekFlags _Flags = GST_SEEK_FLAG_NONE;
1174
1175         start_pos = handle->param->start_pos * G_GINT64_CONSTANT(1000000);
1176         handle->property->end_pos = handle->param->start_pos + handle->param->duration;
1177
1178         if (handle->param->start_pos > handle->property->total_length && handle->property->seek_idx) {
1179                 LOGE("[%lu ~ %lu] out of %lu",
1180                         handle->param->start_pos, handle->property->end_pos, handle->property->total_length);
1181                 return MM_ERROR_TRANSCODE_SEEK_FAILED;
1182         } else {
1183                 if (handle->param->duration != 0) {
1184                         end_pos = start_pos + handle->param->duration * G_GINT64_CONSTANT(1000000);
1185                 } else if (handle->param->duration == 0) {
1186                         /* seek to origin file length */
1187                         end_pos = handle->property->total_length * G_GINT64_CONSTANT(1000000);
1188                 }
1189
1190                 LOGD("seek time : [ (%lu msec) : (%lu msec) ]\n",
1191                         handle->param->start_pos, handle->property->end_pos);
1192
1193                 while (walk_element) {
1194                         GstElement *seekable_element = GST_ELEMENT(walk_element->data);
1195
1196                         if (!seekable_element) {
1197                                 LOGE("ERROR - seekable");
1198                                 return MM_ERROR_TRANSCODE_INTERNAL;
1199                         }
1200
1201                         if (handle->param->seek_mode == MM_SEEK_ACCURATE)
1202                                 _Flags = GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH;
1203                         else if (handle->param->seek_mode == MM_SEEK_INACCURATE)
1204                                 _Flags = GST_SEEK_FLAG_KEY_UNIT | GST_SEEK_FLAG_FLUSH;
1205
1206                         if (!gst_element_seek(seekable_element, rate, GST_FORMAT_TIME, _Flags, GST_SEEK_TYPE_SET, start_pos, GST_SEEK_TYPE_SET, end_pos)) {
1207                                 LOGE("ERROR - gst_element_seek (on) event : %s", GST_OBJECT_NAME(GST_OBJECT_CAST(seekable_element)));
1208                                 return MM_ERROR_TRANSCODE_SEEK_FAILED;
1209                         }
1210
1211                         if (walk_element)
1212                                 walk_element = g_list_next(walk_element);
1213                 }
1214         }
1215
1216         return ret;
1217 }
1218
1219 int _mm_transcode_thread(handle_s *handle)
1220 {
1221         int ret = MM_ERROR_NONE;
1222
1223         if (!handle) {
1224                 LOGE("[ERROR] - handle");
1225                 return MM_ERROR_INVALID_ARGUMENT;
1226         }
1227
1228         if (!handle->property) {
1229                 LOGE("[ERROR] - handle property");
1230                 return MM_ERROR_TRANSCODE_INTERNAL;
1231         }
1232
1233         if (!handle->property->thread_mutex) {
1234                 handle->property->thread_mutex = g_new(GMutex, 1);
1235                 g_mutex_init(handle->property->thread_mutex);
1236                 LOGD("create thread_mutex: %p", handle->property->thread_mutex);
1237         } else {
1238                 LOGE("ERROR - thread_mutex is already created");
1239         }
1240
1241         if (!handle->property->thread_exit_mutex) {
1242                 handle->property->thread_exit_mutex = g_new(GMutex, 1);
1243                 g_mutex_init(handle->property->thread_exit_mutex);
1244                 LOGD("create exit mutex: %p", handle->property->thread_exit_mutex);
1245         } else {
1246                 LOGE("ERROR - thread_exit_mutex is already created");
1247         }
1248
1249         /* These are a communicator for thread */
1250         if (!handle->property->queue) {
1251                 handle->property->queue = g_async_queue_new();
1252                 LOGD("create async queue: %p", handle->property->queue);
1253         } else {
1254                 LOGE("ERROR - async queue is already created");
1255         }
1256
1257         if (!handle->property->thread_cond) {
1258                 handle->property->thread_cond = g_new(GCond, 1);
1259                 g_cond_init(handle->property->thread_cond);
1260                 LOGD("create thread cond: %p", handle->property->thread_cond);
1261         } else {
1262                 LOGE("thread cond is already created");
1263         }
1264
1265         /* create threads */
1266         LOGD("create thread");
1267         handle->property->thread = g_thread_new(NULL, (GThreadFunc)_mm_transcode_thread_repeate, (gpointer)handle);
1268         if (!handle->property->thread) {
1269                 LOGE("ERROR - create thread");
1270                 return MM_ERROR_TRANSCODE_INTERNAL;
1271         } else {
1272                 LOGD("create thread: %p", handle->property->thread);
1273         }
1274
1275         return ret;
1276 }
1277
1278 static gpointer _mm_transcode_thread_repeate(gpointer data)
1279 {
1280         handle_s *handle = (handle_s *) data;
1281         int ret = MM_ERROR_NONE;
1282
1283         if (!handle) {
1284                 LOGE("[ERROR] - handle");
1285                 return NULL;
1286         }
1287
1288         if (!handle->property) {
1289                 LOGE("[ERROR] - handle property");
1290                 return NULL;
1291         }
1292
1293         /* thread while */
1294         while (1) {
1295                 int length = g_async_queue_length(handle->property->queue);
1296                 if (length) {
1297                         LOGD("[QUEUE #] %d", length);
1298                         handle->property->is_busy = TRUE;
1299                 }
1300
1301                 handle_param_s *pop_data = (handle_param_s *) g_async_queue_pop(handle->property->queue);
1302
1303                 if (handle->property->repeat_thread_exit || !handle->property->is_busy) {
1304                         LOGD("[Receive Last Queue]");
1305                         LOGD("[Destroy]");
1306                         break;
1307                 } else {
1308                         LOGD("[pop queue] resolution_width: %d, resolution_height: %d, start_pos: %lu, duration: %lu, seek_mode: %d outputfile: %s\n",
1309                                 pop_data->resolution_width, pop_data->resolution_height, pop_data->start_pos,
1310                                 pop_data->duration, pop_data->seek_mode, pop_data->outputfile);
1311
1312                         /* Need to block */
1313                         ret = _mm_transcode_exec(handle, pop_data);
1314                         if (ret == MM_ERROR_NONE) {
1315                                 LOGD("Success - transcode_exec");
1316                         } else {
1317                                 LOGD("Destroy - transcode_exec");
1318                                 LOGD("<=== get exit (%d) signal", handle->property->repeat_thread_exit);
1319                                 break;
1320                         }
1321                 }
1322         }
1323         LOGD("exit thread");
1324         return NULL;
1325 }