4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: YoungHun Kim <yh8004.kim@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "mm_transcode.h"
22 #include "mm_transcode_internal.h"
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);
33 GstPadProbeReturn _mm_cb_audio_output_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
35 handle_s *handle = (handle_s *)user_data;
38 debug_error("[ERROR] - handle");
39 return GST_PAD_PROBE_REMOVE;
42 if (!handle->property) {
43 debug_error("[ERROR] - handle property");
44 return GST_PAD_PROBE_REMOVE;
47 gint64 start_pos_ts = handle->param->start_pos * G_GINT64_CONSTANT(1000000);
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);
57 gst_caps_unref(current_caps);
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;
65 /* If input buffer time is less than start position,
66 * input buffer will be dropped.
68 return GST_PAD_PROBE_DROP;
73 return GST_PAD_PROBE_OK;
76 GstPadProbeReturn _mm_cb_video_output_stream_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
78 handle_s *handle = (handle_s *)user_data;
81 debug_error("[ERROR] - handle");
82 return GST_PAD_PROBE_REMOVE;
85 if (!handle->property) {
86 debug_error("[ERROR] - handle property");
87 return GST_PAD_PROBE_REMOVE;
90 gint64 start_pos_ts = handle->param->start_pos * G_GINT64_CONSTANT(1000000);
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);
99 gst_caps_unref(current_caps);
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;
107 /* If input buffer time is less than start position,
108 * input buffer will be dropped.
110 return GST_PAD_PROBE_DROP;
115 return GST_PAD_PROBE_OK;
118 GstPadProbeReturn _mm_cb_encodebin_sinkpad_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
120 handle_s *handle = (handle_s *)user_data;
121 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
124 debug_error("[ERROR] - handle");
125 return GST_PAD_PROBE_REMOVE;
128 if (!handle->property) {
129 debug_error("[ERROR] - handle property");
130 return GST_PAD_PROBE_REMOVE;
134 debug_error("[ERROR] - event");
135 return GST_PAD_PROBE_REMOVE;
138 switch (GST_EVENT_TYPE(event)) {
139 case GST_EVENT_SEGMENT:
141 if (!handle->param->seeking)
144 const GstSegment *segment = NULL;
145 GstSegment *new_segment = NULL;
146 gst_event_parse_segment(event, &segment);
147 if (segment->format != GST_FORMAT_TIME)
150 new_segment = gst_segment_copy(segment);
151 gst_event_unref(event);
154 debug_error("[ERROR] segment copy error");
155 return GST_PAD_PROBE_REMOVE;
158 new_segment->start = 0;
159 new_segment->stop = handle->param->duration * G_GINT64_CONSTANT(1000000);
161 /* replace the new segment (change start/stop position) */
162 GstEvent *new_event = gst_event_new_segment(new_segment);
164 GST_PAD_PROBE_INFO_DATA(info) = new_event;
172 return GST_PAD_PROBE_OK;
175 GstAutoplugSelectResult _mm_cb_decode_bin_autoplug_select(GstElement *element, GstPad *pad, GstCaps *caps, GstElementFactory *factory, handle_s *handle)
177 const gchar *feature_name = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
178 const gchar *caps_str = NULL;
181 debug_error("[ERROR] - handle");
182 return MM_ERROR_INVALID_ARGUMENT;
185 if (!handle->property) {
186 debug_error("[ERROR] - handle property");
187 return MM_ERROR_TRANSCODE_INTERNAL;
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;
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);
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;
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;
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);
219 return GST_AUTOPLUG_SELECT_TRY;
222 void _mm_cb_decoder_newpad_encoder(GstElement *decodebin, GstPad *pad, handle_s *handle)
225 debug_error("[ERROR] - handle");
229 if (!handle->decoder_vidp) {
230 debug_error("[ERROR] - handle decoder_vidp");
234 if (!handle->decoder_audp) {
235 debug_error("[ERROR] - handle decoder_audp");
239 if (!handle->encodebin) {
240 debug_error("[ERROR] - handle encodebin");
244 if (!handle->property) {
245 debug_error("[ERROR] - handle property");
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);
254 debug_error("[ERROR] - mime");
258 if (g_strrstr(mime, "video")) {
259 handle->property->linked_vidoutbin = TRUE;
262 if (gst_pad_is_linked(pad)) {
263 debug_log("pad liked");
265 if (gst_pad_link(pad, (GstPad *) handle->decoder_vidp->sinkdecvideopad) != GST_PAD_LINK_OK)
266 debug_error("Error [pad - sinkdecvideopad]");
268 debug_log("Success [pad - sinkdecvideopad]");
271 } else if (g_strrstr(mime, "audio")) {
272 handle->property->linked_audoutbin = TRUE;
275 if (gst_pad_is_linked(pad)) {
276 debug_log("pad liked");
278 if (gst_pad_link(pad, (GstPad *) handle->decoder_audp->sinkdecaudiopad) != GST_PAD_LINK_OK)
279 debug_error("Error [pad - sinkdecaudiopad]");
281 debug_log("Success [pad - sinkdecaudiopad]");
285 debug_log("gst structure error");
289 gboolean _mm_cb_print_position(handle_s *handle)
291 GstFormat fmt = GST_FORMAT_TIME;
295 debug_error("[ERROR] - handle");
299 if (!handle->property) {
300 debug_error("[ERROR] - handle property");
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;
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;
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;
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++;
343 gboolean _mm_cb_transcode_bus(GstBus *bus, GstMessage *message, gpointer userdata)
345 handle_s *handle = (handle_s *)userdata;
346 int ret = MM_ERROR_NONE;
349 debug_error("[ERROR] - handle");
353 if (!handle->property) {
354 debug_error("[ERROR] - handle property");
359 GstFormat fmt = GST_FORMAT_TIME;
360 MMHandleType MMHandle = (MMHandleType)handle;
362 switch (GST_MESSAGE_TYPE(message)) {
363 case GST_MESSAGE_ERROR:
367 gst_message_parse_error(message, &err, &debug);
370 debug_warning("Fail to parse error message");
374 debug_error("[Source: %s] Error: %s", GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC(message)))), err->message);
376 ret = mm_transcode_cancel(MMHandle);
377 if (ret == MM_ERROR_NONE) {
378 debug_log("Success - Cancel Transcode");
380 debug_error("ERROR - Cancel Transcode");
387 TRANSCODE_FREE(debug);
388 TRANSCODE_FREE(handle->param);
389 /* g_main_loop_quit (handle->loop); */
393 case GST_MESSAGE_STATE_CHANGED:
395 if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != handle->pipeline)
398 GstState State_Old, State_New, State_Pending;
399 gst_message_parse_state_changed(message, &State_Old, &State_New, &State_Pending);
401 debug_log("[Source: %s] [State: %d -> %d]", GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC(message)))), State_Old, State_New);
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");
410 debug_error("ERROR - Pause pipeline");
415 if (State_Old == GST_STATE_READY && State_New == GST_STATE_PAUSED) {
417 debug_log("[%s] Start New Segment pipeline", handle->param->outputfile);
418 ret = _mm_transcode_seek(handle);
420 if (ret == MM_ERROR_NONE) {
421 debug_log("Success - Set New Segment pipeline");
423 debug_log("[Null Trancode]");
424 if (_mm_transcode_state_change(handle, GST_STATE_NULL) != MM_ERROR_NONE) {
425 debug_error("ERROR -Null Pipeline");
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]");
442 case GST_MESSAGE_ASYNC_DONE:
444 if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != handle->pipeline)
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));
452 handle->param->async_done = TRUE;
453 debug_log("GST_MESSAGE_ASYNC_DONE");
456 debug_log("[Play Trancode] [%d ~ %d]", handle->param->start_pos, handle->property->end_pos);
458 if (_mm_transcode_play(handle) != MM_ERROR_NONE) {
459 debug_error("ERROR - Play Pipeline");
465 case GST_MESSAGE_SEGMENT_DONE:
467 if (GST_ELEMENT(GST_MESSAGE_SRC(message)) != handle->pipeline)
470 handle->param->segment_done = TRUE;
471 debug_log("GST_MESSAGE_SEGMENT_DONE");
475 case GST_MESSAGE_EOS:
478 debug_log("[GST_MESSAGE_EOS] end-of-stream");
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;
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");
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);
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);
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);
504 if (handle->property->progress_cb)
505 handle->property->progress_cb(handle->property->real_duration, handle->property->real_duration, handle->property->progress_cb_param);
507 if (handle->property->completed_cb)
508 handle->property->completed_cb(MM_ERROR_NONE, handle->property->completed_cb_param);
514 /*debug_log("unhandle message"); */
520 static void _mm_transcode_audio_capsfilter(GstCaps *caps, handle_s *handle)
525 debug_error("[ERROR] - handle");
529 if (!handle->encodebin) {
530 debug_error("[ERROR] - handle encodebin");
534 if (!handle->property) {
535 debug_error("[ERROR] - handle property");
540 debug_error("[ERROR] - caps");
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);
549 TRANSCODE_FREE(handle->property->audiodecodename);
550 g_object_set(G_OBJECT(handle->decoder_audp->audflt), "caps", caps, NULL);
552 str = gst_caps_to_string(caps);
555 debug_log("audio decoder capsfilter audiocaps: %s", str);
563 int _mm_transcode_create(handle_s *handle)
565 int ret = MM_ERROR_NONE;
568 debug_error("[ERROR] - handle");
569 return MM_ERROR_INVALID_ARGUMENT;
572 ret = _mm_decodesrcbin_create(handle);
573 if (ret == MM_ERROR_NONE) {
574 debug_log("Success - Create decodesrcbin");
576 debug_error("ERROR - Create decodesrcbin");
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");
584 debug_error("ERROR -Setup video and audio encoder of encodebin ");
588 ret = _mm_encodebin_create(handle);
589 if (ret == MM_ERROR_NONE) {
590 debug_log("Success - Create encodebin");
592 debug_error("ERROR - Create encodebin");
597 ret = _mm_filesink_create(handle);
598 if (ret == MM_ERROR_NONE) {
599 debug_log("Success - Create Filesink");
601 debug_error("ERROR - Create Filesink");
608 static int _mm_transcode_exec(handle_s *handle, handle_param_s *param)
610 int ret = MM_ERROR_NONE;
613 debug_error("[ERROR] - handle");
614 return MM_ERROR_INVALID_ARGUMENT;
617 if (!handle->property) {
618 debug_error("[ERROR] - handle property");
619 return MM_ERROR_TRANSCODE_INTERNAL;
622 if (!param || !param->outputfile) {
623 debug_error("[ERROR] - param");
624 return MM_ERROR_TRANSCODE_INVALID_VALUE;
627 g_mutex_lock(handle->property->thread_mutex);
629 if (handle->property->repeat_thread_exit) {
630 g_mutex_unlock(handle->property->thread_mutex);
631 debug_log("unlock destory");
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); */
637 if (!handle->param) {
638 debug_error("[ERROR] - handle param");
639 return MM_ERROR_TRANSCODE_INTERNAL;
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;
654 memset(handle->param->outputfile, 0, BUFFER_SIZE);
655 strncpy(handle->param->outputfile, param->outputfile, strlen(param->outputfile));
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);
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]");
669 g_object_set(G_OBJECT(handle->filesink), "location", handle->param->outputfile, NULL);
670 debug_log("[%s] set filesink location", handle->param->outputfile);
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");
679 debug_error("ERROR - Reay pipeline");
680 g_mutex_unlock(handle->property->thread_mutex);
685 if (0 == handle->property->seek_idx) {
686 debug_log("Link Filesink");
688 ret = _mm_filesink_link(handle);
689 if (ret == MM_ERROR_NONE) {
690 debug_log("Success - Link Filesink");
692 debug_error("ERROR - Link Filesink");
693 g_mutex_unlock(handle->property->thread_mutex);
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);
707 int _mm_transcode_get_stream_info(handle_s *handle)
709 int ret = MM_ERROR_NONE;
712 debug_error("[ERROR] - handle");
713 return MM_ERROR_INVALID_ARGUMENT;
716 if (!handle->property) {
717 debug_error("[ERROR] - handle property");
718 return MM_ERROR_TRANSCODE_INTERNAL;
721 if (strlen(handle->property->sourcefile) == 0) {
722 debug_error("Invalid arguments [sourcefile size 0]\n");
723 return MM_ERROR_INVALID_ARGUMENT;
726 int audio_track_num = 0;
727 int video_track_num = 0;
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");
733 debug_error("ERROR - mm_file_get_stream_info");
734 return MM_ERROR_TRANSCODE_INTERNAL;
738 handle->property->has_audio_stream = TRUE;
740 handle->property->has_audio_stream = FALSE;
742 debug_log("has_audio_stream: %d", handle->property->has_audio_stream);
745 handle->property->has_video_stream = TRUE;
747 handle->property->has_video_stream = FALSE;
749 debug_log("has_video_stream: %d", handle->property->has_video_stream);
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;
759 int _mm_transcode_link(handle_s *handle)
761 int ret = MM_ERROR_NONE;
764 debug_error("[ERROR] - handle");
765 return MM_ERROR_INVALID_ARGUMENT;
768 ret = _mm_decodesrcbin_link(handle);
769 if (ret == MM_ERROR_NONE) {
770 debug_log("Success - decodesrcbin link");
772 debug_error("ERROR - decodesrcbin link");
776 ret = _mm_encodebin_link(handle);
777 if (ret == MM_ERROR_NONE) {
778 debug_log("Success - encodebin link");
780 debug_error("ERROR - encodebin link");
787 static void _mm_transcode_video_capsfilter(GstCaps *caps, handle_s *handle)
790 debug_error("[ERROR] - handle");
794 if (!handle->property) {
795 debug_error("[ERROR] - handle property");
800 debug_error("[ERROR] - caps");
801 TRANSCODE_FREE(handle->property->videodecodename);
805 debug_log("[First Video Buffer] Set CapsFilter Parameter");
806 _mm_transcode_video_capsfilter_set_parameter(caps, handle);
808 /* Not support enlarge video resolution */
809 debug_log("Execute Resize");
811 /* Not irrelevant to the ratio */
812 handle->param->resolution_height = handle->param->resolution_width * handle->in_height / handle->in_width;
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;
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;
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;
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);
839 static void _mm_transcode_video_capsfilter_call(handle_s *handle)
842 debug_error("[ERROR] - handle");
846 if (!handle->decoder_vidp) {
847 debug_error("[ERROR] - handle decoder video process bin");
851 if (!handle->property) {
852 debug_error("[ERROR] - handle property");
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);
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);
862 static void _mm_transcode_video_capsfilter_set_parameter(GstCaps *caps, handle_s *handle)
864 const GValue *par, *fps;
867 debug_error("[ERROR] - handle");
871 if (!handle->property) {
872 debug_error("[ERROR] - handle property");
877 debug_error("[ERROR] - caps");
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);
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';
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);
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);
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]");
909 debug_log("Origin File's Width: [%u] Origin File's Hieght: [%u]", handle->property->in_width, handle->property->in_height);
911 fps = gst_structure_get_value(_str, "framerate");
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);
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;
923 debug_log("[framerate] gst_value_get_fraction_numerator: %d, gst_value_get_fraction_denominator: %d", handle->property->fps_n, handle->property->fps_d);
925 par = gst_structure_get_value(_str, "pixel-aspect-ratio");
927 handle->property->aspect_x = gst_value_get_fraction_numerator(par);
928 handle->property->aspect_y = gst_value_get_fraction_denominator(par);
930 handle->property->aspect_x = handle->property->aspect_y = 1;
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);
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)
938 int ret = MM_ERROR_NONE;
941 debug_error("[ERROR] - handle");
942 return MM_ERROR_INVALID_ARGUMENT;
945 if (!handle->property) {
946 debug_error("[ERROR] - handle property");
947 return MM_ERROR_TRANSCODE_INTERNAL;
950 if (in_Filename == NULL) {
951 debug_error("Invalid arguments [filename null]\n");
952 return MM_ERROR_INVALID_ARGUMENT;
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;
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);
966 debug_error("[ERROR] malloc fail of sourcefile");
967 return MM_ERROR_TRANSCODE_INTERNAL;
970 handle->property->containerformat = containerformat;
971 handle->property->videoencoder = videoencoder;
972 handle->property->audioencoder = audioencoder;
974 debug_log("container format: %d videoencoder:%d, audioencoder: %d", handle->property->containerformat, handle->property->videoencoder, handle->property->audioencoder);
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)
981 int ret = MM_ERROR_NONE;
984 debug_error("param error");
985 return MM_ERROR_TRANSCODE_INTERNAL;
988 param->resolution_width = resolution_width;
989 param->resolution_height = resolution_height;
990 param->fps_value = fps_value;
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);
997 if (start_pos == 0 && duration == 0)
998 param->seeking = FALSE;
1000 param->seeking = TRUE;
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;
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));
1012 debug_error("out_Filename error");
1013 return MM_ERROR_INVALID_ARGUMENT;
1019 int _mm_transcode_state_change(handle_s *handle, GstState gst_state)
1021 int ret = MM_ERROR_NONE;
1022 GstStateChangeReturn ret_state;
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");
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");
1044 return MM_ERROR_TRANSCODE_INTERNAL;
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");
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");
1067 return MM_ERROR_TRANSCODE_INTERNAL;
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");
1082 int _mm_transcode_param_flush(handle_s *handle)
1084 int ret = MM_ERROR_NONE;
1087 debug_error("[ERROR] - handle");
1088 return MM_ERROR_INVALID_ARGUMENT;
1091 if (!handle->encodebin) {
1092 debug_error("[ERROR] - handle encodebin");
1093 return MM_ERROR_TRANSCODE_INTERNAL;
1096 if (!handle->property) {
1097 debug_error("[ERROR] - handle property");
1098 return MM_ERROR_TRANSCODE_INTERNAL;
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;
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;
1120 static int _mm_transcode_play(handle_s *handle)
1122 int ret = MM_ERROR_NONE;
1125 debug_error("[ERROR] - handle");
1126 return MM_ERROR_INVALID_ARGUMENT;
1129 if (!handle->property) {
1130 debug_error("[ERROR] - handle property");
1131 return MM_ERROR_TRANSCODE_INTERNAL;
1134 ret = _mm_transcode_state_change(handle, GST_STATE_PLAYING);
1135 if (ret != MM_ERROR_NONE) {
1136 debug_error("ERROR -Playing Pipeline");
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);
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);
1148 static int _mm_transcode_seek(handle_s *handle)
1150 int ret = MM_ERROR_NONE;
1153 debug_error("[ERROR] - handle");
1154 return MM_ERROR_INVALID_ARGUMENT;
1157 if (!handle->property) {
1158 debug_error("[ERROR] - handle property");
1159 return MM_ERROR_TRANSCODE_INTERNAL;
1162 GList *walk_element = handle->property->sink_elements;
1163 gint64 start_pos, end_pos;
1165 GstSeekFlags _Flags = GST_SEEK_FLAG_NONE;
1167 start_pos = handle->param->start_pos * G_GINT64_CONSTANT(1000000);
1168 handle->property->end_pos = handle->param->start_pos + handle->param->duration;
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;
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);
1181 debug_log("seek time : [ (%d msec) : (%d msec) ]\n", handle->param->start_pos, handle->property->end_pos);
1183 while (walk_element) {
1184 GstElement *seekable_element = GST_ELEMENT(walk_element->data);
1186 if (!seekable_element) {
1187 debug_error("ERROR - seekable");
1188 return MM_ERROR_TRANSCODE_INTERNAL;
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;
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;
1202 walk_element = g_list_next(walk_element);
1209 int _mm_transcode_thread(handle_s *handle)
1211 int ret = MM_ERROR_NONE;
1214 debug_error("[ERROR] - handle");
1215 return MM_ERROR_INVALID_ARGUMENT;
1218 if (!handle->property) {
1219 debug_error("[ERROR] - handle property");
1220 return MM_ERROR_TRANSCODE_INTERNAL;
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);
1228 debug_error("ERROR - thread_mutex is already created");
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);
1236 debug_error("ERROR - thread_exit_mutex is already created");
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);
1244 debug_error("ERROR - async queue is already created");
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);
1252 debug_error("thread cond is already created");
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;
1262 debug_log("create thread: 0x%2x", handle->property->thread);
1268 static gpointer _mm_transcode_thread_repeate(gpointer data)
1270 handle_s *handle = (handle_s *) data;
1271 int ret = MM_ERROR_NONE;
1274 debug_error("[ERROR] - handle");
1278 if (!handle->property) {
1279 debug_error("[ERROR] - handle property");
1285 int length = g_async_queue_length(handle->property->queue);
1287 debug_log("[QUEUE #] %d", length);
1288 handle->property->is_busy = TRUE;
1291 handle_param_s *pop_data = (handle_param_s *) g_async_queue_pop(handle->property->queue);
1293 if (handle->property->repeat_thread_exit || !handle->property->is_busy) {
1294 debug_log("[Receive Last Queue]");
1295 debug_log("[Destroy]");
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);
1301 ret = _mm_transcode_exec(handle, pop_data);
1302 if (ret == MM_ERROR_NONE) {
1303 debug_log("Success - transcode_exec");
1305 debug_log("Destroy - transcode_exec");
1306 debug_log("<=== get exit (%d) signal", handle->property->repeat_thread_exit);
1311 debug_log("exit thread");