Release signal before state change.
[platform/core/multimedia/libmm-transcode.git] / transcode / mm_transcode.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 int mm_transcode_create(MMHandleType *MMHandle)
25 {
26         int ret = MM_ERROR_NONE;
27         handle_s *handle = NULL;
28
29         /* Check argument here */
30         if (MMHandle == NULL) {
31                 debug_error("Invalid arguments [tag null]\n");
32                 return MM_ERROR_INVALID_ARGUMENT;
33         }
34
35         /* Init Transcode */
36         gst_init(NULL, NULL);
37         /*handle = g_malloc(sizeof(handle_s)); */
38         handle = g_new0(handle_s, 1);
39         if (!handle) {
40                 debug_error("[ERROR] - handle");
41                 return MM_ERROR_TRANSCODE_INTERNAL;
42         }
43
44         handle->decoder_vidp = g_new0(handle_vidp_plugin_s, 1);
45         if (!handle->decoder_vidp) {
46                 debug_error("[ERROR] - handle decoder video process bin");
47                 goto ERROR4;
48         }
49
50         handle->decoder_audp = g_new0(handle_audp_plugin_s, 1);
51         if (!handle->decoder_audp) {
52                 debug_error("[ERROR] - handle decoder audio process bin");
53                 goto ERROR3;
54         }
55
56         handle->encodebin = g_new0(handle_encode_s, 1);
57         if (!handle->encodebin) {
58                 debug_error("[ERROR] - handle encodebin");
59                 goto ERROR2;
60         }
61
62         handle->property = g_new0(handle_property_s, 1);
63         if (!handle->property) {
64                 debug_error("[ERROR] - handle property");
65                 goto ERROR1;
66         }
67
68         *MMHandle = (MMHandleType)handle;
69
70         debug_log("MMHandle: 0x%2x", handle);
71         handle->property->_MMHandle = 0;
72
73         return ret;
74
75 ERROR1:
76         TRANSCODE_FREE(handle->encodebin);
77 ERROR2:
78         TRANSCODE_FREE(handle->decoder_audp);
79 ERROR3:
80         TRANSCODE_FREE(handle->decoder_vidp);
81 ERROR4:
82         TRANSCODE_FREE(handle);
83         return MM_ERROR_TRANSCODE_INTERNAL;
84 }
85
86 int mm_transcode_prepare(MMHandleType MMHandle, const char *in_Filename, mm_containerformat_e containerformat, mm_videoencoder_e videoencoder, mm_audioencoder_e audioencoder)
87 {
88         int ret = MM_ERROR_NONE;
89
90         handle_s *handle = (handle_s *) MMHandle;
91
92         if (!handle) {
93                 debug_error("[ERROR] - handle");
94                 return MM_ERROR_INVALID_ARGUMENT;
95         }
96
97         if (!handle->property) {
98                 debug_error("[ERROR] - handle property");
99                 return MM_ERROR_TRANSCODE_INTERNAL;
100         }
101
102         if ((in_Filename == NULL) || (strlen(in_Filename) == 0)) {
103                 debug_error("Invalid Input file");
104                 return MM_ERROR_INVALID_ARGUMENT;
105         }
106
107         if (videoencoder == MM_VIDEOENCODER_NO_USE && audioencoder == MM_AUDIOENCODER_NO_USE) {
108                 debug_error("No encoder resource");
109                 return MM_ERROR_INVALID_ARGUMENT;
110         }
111
112         if (videoencoder == MM_VIDEOENCODER_H264) {
113                 debug_error("Can't support encoding to H264");
114                 return MM_ERROR_INVALID_ARGUMENT;
115         }
116
117         /* set element */
118         ret = _mm_transcode_set_handle_element(handle, in_Filename, containerformat, videoencoder, audioencoder);
119         if (ret != MM_ERROR_NONE) {
120                 debug_error("ERROR -Set element");
121                 return ret;
122         }
123
124         debug_log("%s == %s", handle->property->sourcefile, in_Filename);
125         /* protect the case of changing input file during transcoding */
126         if (0 == strlen(handle->property->sourcefile) || 0 == strcmp(handle->property->sourcefile, in_Filename)) {
127                 /* setup */
128                 ret = _mm_setup_pipeline(handle);
129                 if (ret == MM_ERROR_NONE) {
130                         debug_log("Success - Setup Pipeline");
131                 } else {
132                         debug_error("ERROR - Setup Pipeline");
133                         return ret;
134                 }
135
136                 /* video / auido stream */
137                 ret = _mm_transcode_get_stream_info(handle);
138                 if (ret == MM_ERROR_NONE) {
139                         debug_log("Success - Get stream info");
140                 } else {
141                         debug_error("ERROR - Get stream info");
142                         return ret;
143                 }
144
145                 /* create pipeline */
146                 ret = _mm_transcode_create(handle);
147                 if (ret == MM_ERROR_NONE) {
148                         debug_log("Success - Create Pipeline");
149                 } else {
150                         debug_error("ERROR -Create Pipeline");
151                         return ret;
152                 }
153
154                 /*link pipeline */
155                 ret = _mm_transcode_link(handle);
156                 if (ret == MM_ERROR_NONE) {
157                         debug_log("Success - Link pipeline");
158                 } else {
159                         debug_error("ERROR - Link pipeline");
160                         return ret;
161                 }
162
163                 /* flush param */
164                 ret = _mm_transcode_param_flush(handle);
165                 if (ret == MM_ERROR_NONE) {
166                         debug_log("Success - Init parameter");
167                 } else {
168                         debug_error("ERROR - Init parameter");
169                         return ret;
170                 }
171
172                 /* create thread */
173                 ret = _mm_transcode_thread(handle);
174                 if (ret == MM_ERROR_NONE) {
175                         debug_log("Success - Link pipeline");
176                 } else {
177                         debug_error("ERROR - Link pipeline");
178                         return ret;
179                 }
180
181                 /* Add_watcher Transcode Bus */
182                 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(handle->pipeline));
183                 handle->property->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)_mm_cb_transcode_bus, handle);
184                 gst_object_unref(GST_OBJECT(bus));
185                 debug_log("Success - gst_object_unref (bus)");
186         }
187
188         handle->property->_MMHandle++;
189
190         return ret;
191 }
192
193 int mm_transcode(MMHandleType MMHandle, unsigned int resolution_width, unsigned int resolution_height, unsigned int fps_value, unsigned long start_position, unsigned long duration, mm_seek_mode_e seek_mode, const char *out_Filename, mm_transcode_progress_callback progress_callback, mm_transcode_completed_callback completed_callback, void *user_param)
194 {
195         int ret = MM_ERROR_NONE;
196         handle_s *handle = (handle_s *)MMHandle;
197
198         if (!handle) {
199                 debug_error("[ERROR] - handle");
200                 return MM_ERROR_INVALID_ARGUMENT;
201         }
202
203         if (!handle->property) {
204                 debug_error("[ERROR] - handle property");
205                 return MM_ERROR_TRANSCODE_INTERNAL;
206         }
207
208         if (!completed_callback) {
209                 debug_error("[ERROR] - completed_callback");
210                 return MM_ERROR_INVALID_ARGUMENT;
211         }
212
213         if (!out_Filename) {
214                 debug_error("[ERROR] - out_Filename");
215                 return MM_ERROR_INVALID_ARGUMENT;
216         }
217
218         if (duration < MIN_DURATION && duration != 0) {
219                 debug_error("The minimum seek duration is 1000 msec ");
220                 return MM_ERROR_INVALID_ARGUMENT;
221         }
222
223         handle->property->progress_cb = progress_callback;
224         handle->property->progress_cb_param = user_param;
225         debug_log("[MMHandle] 0x%2x [progress_cb] 0x%2x [progress_cb_param] 0x%2x", MMHandle, handle->property->progress_cb, handle->property->progress_cb_param);
226
227         handle->property->completed_cb = completed_callback;
228         handle->property->completed_cb_param = user_param;
229         debug_log("[MMHandle] 0x%2x [completed_cb] 0x%2x [completed_cb_param] 0x%2x", MMHandle, handle->property->completed_cb, handle->property->completed_cb_param);
230
231         if (!handle->property) {
232                 debug_error("[ERROR] - handle property");
233                 return MM_ERROR_TRANSCODE_INTERNAL;
234         }
235         /* check if prepare is called during transcoding */
236         if (handle->property->_MMHandle == 1) {
237                 handle_param_s *param = g_new0(handle_param_s, 1);
238                 if (param) {
239                         /*g_value_init (param, G_TYPE_INT); */
240                         debug_log("[param] 0x%2x", param);
241                 }
242
243                 /* set parameter */
244                 ret = _mm_transcode_set_handle_parameter(param, resolution_width, resolution_height, fps_value, start_position, duration, seek_mode, out_Filename);
245                 if (ret != MM_ERROR_NONE) {
246                         debug_error("ERROR -Set parameter");
247                         return ret;
248                 }
249
250                 ret = _mm_transcode_preset_capsfilter(handle, resolution_width, resolution_height);
251                 if (ret == MM_ERROR_NONE) {
252                         debug_log("Success - Preset Capsfilter");
253                 } else {
254                         debug_error("ERROR - Preset Capsfilter");
255                         return ret;
256                 }
257
258                 handle->property->is_busy = TRUE;
259
260                 /*push data to handle */
261                 g_async_queue_push(handle->property->queue, GINT_TO_POINTER(param));
262         }
263
264         return ret;
265 }
266
267 int mm_transcode_is_busy(MMHandleType MMHandle, bool *is_busy)
268 {
269         int ret = MM_ERROR_NONE;
270
271         handle_s *handle = (handle_s *)MMHandle;
272
273         if (!handle) {
274                 debug_error("[ERROR] - handle");
275                 return MM_ERROR_INVALID_ARGUMENT;
276         }
277
278         if (!handle->property) {
279                 debug_error("[ERROR] - handle property");
280                 return MM_ERROR_TRANSCODE_INTERNAL;
281         }
282
283         if (!is_busy) {
284                 debug_error("[ERROR] - is_busy");
285                 return MM_ERROR_INVALID_ARGUMENT;
286         }
287
288         *is_busy = handle->property->is_busy;
289         debug_log("[Transcoding....] %d", *is_busy);
290
291         return ret;
292 }
293
294 int mm_transcode_cancel(MMHandleType MMHandle)
295 {
296         int ret = MM_ERROR_NONE;
297         handle_s *handle = (handle_s *)MMHandle;
298
299         if (!handle) {
300                 debug_error("[ERROR] - handle");
301                 return MM_ERROR_INVALID_ARGUMENT;
302         }
303
304         if (!handle->property) {
305                 debug_error("[ERROR] - handle property");
306                 return MM_ERROR_TRANSCODE_INTERNAL;
307         }
308
309         if (handle->property->is_busy) {
310                 debug_log("Cancel - [IS BUSY]");
311                 ret = _mm_transcode_state_change(handle, GST_STATE_NULL);
312                 if (ret != MM_ERROR_NONE) {
313                         debug_error("ERROR - Null Pipeline");
314                         return ret;
315                 }
316
317                 if ((handle->param) && (strlen(handle->param->outputfile) > 0)) {
318                         unlink(handle->param->outputfile);
319                         debug_log("[Cancel] unlink %s", handle->param->outputfile);
320                 } else {
321                         debug_error("unlink error");
322                         return MM_ERROR_TRANSCODE_INTERNAL;
323                 }
324                 g_mutex_lock(handle->property->thread_mutex);
325                 g_cond_signal(handle->property->thread_cond);
326                 debug_log("===> send completed signal <-cancel");
327                 g_mutex_unlock(handle->property->thread_mutex);
328         }
329
330         handle->property->is_busy = FALSE;
331
332         return ret;
333 }
334
335 int mm_transcode_destroy(MMHandleType MMHandle)
336 {
337         int ret = MM_ERROR_NONE;
338
339         handle_s *handle = (handle_s *)MMHandle;
340
341         if (!handle) {
342                 debug_error("[ERROR] - handle");
343                 return MM_ERROR_INVALID_ARGUMENT;
344         }
345
346         if (!handle->property) {
347                 debug_error("[ERROR] - handle property");
348                 return MM_ERROR_TRANSCODE_INTERNAL;
349         }
350
351         g_mutex_lock(handle->property->thread_exit_mutex);
352         handle->property->repeat_thread_exit = TRUE;
353         if (handle->property->is_busy) {
354                 ret = mm_transcode_cancel(MMHandle);
355                 if (ret == MM_ERROR_NONE) {
356                         debug_log("Success - Cancel Transcode");
357                 } else {
358                         debug_error("ERROR - Cancel Transcode");
359                         return FALSE;
360                 }
361         }
362         /* handle->property->is_busy = FALSE; */
363         g_mutex_unlock(handle->property->thread_exit_mutex);
364
365         handle_param_s *param = g_new0(handle_param_s, 1);
366         if (param) {
367                 debug_log("[Try to Push Last Queue]");
368                 g_async_queue_push(handle->property->queue, GINT_TO_POINTER(param));
369         } else {
370                 debug_error("Fail to create Last Queue");
371                 return MM_ERROR_INVALID_ARGUMENT;
372         }
373         ret = _mm_cleanup_signal(handle);
374         if (ret == MM_ERROR_NONE) {
375                 debug_log("Success - CleanUp Signal");
376         } else {
377                 debug_error("ERROR - CleanUp Signal");
378                 return ret;
379         }
380
381         ret = _mm_transcode_state_change(handle, GST_STATE_NULL);
382         if (ret != MM_ERROR_NONE) {
383                 debug_error("ERROR - Null Pipeline");
384                 return ret;
385         } else {
386                 debug_log("SUCCESS - Null Pipeline");
387         }
388
389         if ((handle->param) && (!handle->param->completed)) {
390                 g_cond_signal(handle->property->thread_cond);
391                 debug_log("===> send completed signal <-destroy");
392                 g_mutex_unlock(handle->property->thread_mutex);
393                 debug_log("unlock destory");
394                 if (strlen(handle->param->outputfile) > 0) {
395                         unlink(handle->param->outputfile);
396                         debug_log("[Cancel] unlink %s", handle->param->outputfile);
397                 }
398         }
399
400         ret = _mm_cleanup_pipeline(handle);
401         if (ret == MM_ERROR_NONE) {
402                 debug_log("Success - CleanUp Pipeline");
403         } else {
404                 debug_error("ERROR - CleanUp Pipeline");
405                 return ret;
406         }
407         TRANSCODE_FREE(param);
408         debug_log("[param] free");
409
410         return ret;
411 }
412
413 int mm_transcode_get_attrs(MMHandleType MMHandle, mm_containerformat_e * containerformat, mm_videoencoder_e * videoencoder, mm_audioencoder_e * audioencoder, unsigned long *current_pos, unsigned long *duration, unsigned int *resolution_width, unsigned int *resolution_height)
414 {
415
416         int ret = MM_ERROR_NONE;
417         handle_s *handle = (handle_s *)MMHandle;
418
419         if (!handle) {
420                 debug_error("[ERROR] - handle");
421                 return MM_ERROR_INVALID_ARGUMENT;
422         }
423
424         if (!handle->property) {
425                 debug_error("[ERROR] - handle property");
426                 return MM_ERROR_TRANSCODE_INTERNAL;
427         }
428
429         if (!containerformat || !videoencoder || !audioencoder || !current_pos || !duration || !resolution_width || !resolution_height) {
430                 debug_error("[ERROR] - Invalid argument pointer");
431                 return MM_ERROR_INVALID_ARGUMENT;
432         }
433
434         *containerformat = handle->property->containerformat;
435         *videoencoder = handle->property->videoencoder;
436         *audioencoder = handle->property->audioencoder;
437
438         if (!handle->property) {
439                 debug_error("[ERROR] - handle property");
440                 return MM_ERROR_TRANSCODE_INTERNAL;
441         }
442
443         if (handle->property->current_pos > handle->param->duration)
444                 *current_pos = handle->param->duration;
445         else
446                 *current_pos = handle->property->current_pos;
447         *duration = handle->property->real_duration;
448         *resolution_width = handle->param->resolution_width;
449         *resolution_height = handle->param->resolution_height;
450
451         debug_log("containerformat : %d, videoencoder : %d, audioencoder : %d, current_pos : %d, duration : %d, resolution_width : %d, resolution_height : %d", *containerformat, *videoencoder, *audioencoder, *current_pos, *duration, *resolution_width, *resolution_height);
452
453         return ret;
454 }
455
456 int mm_transcode_get_supported_container_format(mm_transcode_support_type_callback type_callback, void *user_param)
457 {
458         int idx = 0;
459
460         for (idx = 0; idx < MM_CONTAINER_NUM; idx++) {
461                 if (type_callback(idx, user_param) == false) {
462                         debug_error("error occured. idx[%d]", idx);
463                         break;
464                 }
465         }
466
467         return MM_ERROR_NONE;
468 }
469
470 int mm_transcode_get_supported_video_encoder(mm_transcode_support_type_callback type_callback, void *user_param)
471 {
472         int idx = 0;
473
474         for (idx = 0; idx < MM_VIDEOENCODER_H264; idx++) {
475                 if (type_callback(idx, user_param) == false) {
476                         debug_error("error occured. idx[%d]", idx);
477                         break;
478                 }
479         }
480
481         return MM_ERROR_NONE;
482 }
483
484 int mm_transcode_get_supported_audio_encoder(mm_transcode_support_type_callback type_callback, void *user_param)
485 {
486         int idx = 0;
487
488         for (idx = 0; idx < MM_AUDIOENCODER_NO_USE; idx++) {
489                 if (type_callback(idx, user_param) == false) {
490                         debug_error("error occured. idx[%d]", idx);
491                         break;
492                 }
493         }
494
495         return MM_ERROR_NONE;
496 }