8070a89fc7bfd16a9e1bc723099b35436819c11d
[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
374         ret = _mm_transcode_state_change(handle, GST_STATE_NULL);
375         if (ret != MM_ERROR_NONE) {
376                 debug_error("ERROR - Null Pipeline");
377                 return ret;
378         } else {
379                 debug_log("SUCCESS - Null Pipeline");
380         }
381
382         if ((handle->param) && (!handle->param->completed)) {
383                 g_cond_signal(handle->property->thread_cond);
384                 debug_log("===> send completed signal <-destroy");
385                 g_mutex_unlock(handle->property->thread_mutex);
386                 debug_log("unlock destory");
387                 if (strlen(handle->param->outputfile) > 0) {
388                         unlink(handle->param->outputfile);
389                         debug_log("[Cancel] unlink %s", handle->param->outputfile);
390                 }
391         }
392
393         ret = _mm_cleanup_pipeline(handle);
394         if (ret == MM_ERROR_NONE) {
395                 debug_log("Success - CleanUp Pipeline");
396         } else {
397                 debug_error("ERROR - CleanUp Pipeline");
398                 return ret;
399         }
400         TRANSCODE_FREE(param);
401         debug_log("[param] free");
402
403         return ret;
404 }
405
406 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)
407 {
408
409         int ret = MM_ERROR_NONE;
410         handle_s *handle = (handle_s *)MMHandle;
411
412         if (!handle) {
413                 debug_error("[ERROR] - handle");
414                 return MM_ERROR_INVALID_ARGUMENT;
415         }
416
417         if (!handle->property) {
418                 debug_error("[ERROR] - handle property");
419                 return MM_ERROR_TRANSCODE_INTERNAL;
420         }
421
422         if (!containerformat || !videoencoder || !audioencoder || !current_pos || !duration || !resolution_width || !resolution_height) {
423                 debug_error("[ERROR] - Invalid argument pointer");
424                 return MM_ERROR_INVALID_ARGUMENT;
425         }
426
427         *containerformat = handle->property->containerformat;
428         *videoencoder = handle->property->videoencoder;
429         *audioencoder = handle->property->audioencoder;
430
431         if (!handle->property) {
432                 debug_error("[ERROR] - handle property");
433                 return MM_ERROR_TRANSCODE_INTERNAL;
434         }
435
436         if (handle->property->current_pos > handle->param->duration)
437                 *current_pos = handle->param->duration;
438         else
439                 *current_pos = handle->property->current_pos;
440         *duration = handle->property->real_duration;
441         *resolution_width = handle->param->resolution_width;
442         *resolution_height = handle->param->resolution_height;
443
444         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);
445
446         return ret;
447 }
448
449 int mm_transcode_get_supported_container_format(mm_transcode_support_type_callback type_callback, void *user_param)
450 {
451         int idx = 0;
452
453         for (idx = 0; idx < MM_CONTAINER_NUM; idx++) {
454                 if (type_callback(idx, user_param) == false) {
455                         debug_error("error occured. idx[%d]", idx);
456                         break;
457                 }
458         }
459
460         return MM_ERROR_NONE;
461 }
462
463 int mm_transcode_get_supported_video_encoder(mm_transcode_support_type_callback type_callback, void *user_param)
464 {
465         int idx = 0;
466
467         for (idx = 0; idx < MM_VIDEOENCODER_H264; idx++) {
468                 if (type_callback(idx, user_param) == false) {
469                         debug_error("error occured. idx[%d]", idx);
470                         break;
471                 }
472         }
473
474         return MM_ERROR_NONE;
475 }
476
477 int mm_transcode_get_supported_audio_encoder(mm_transcode_support_type_callback type_callback, void *user_param)
478 {
479         int idx = 0;
480
481         for (idx = 0; idx < MM_AUDIOENCODER_NO_USE; idx++) {
482                 if (type_callback(idx, user_param) == false) {
483                         debug_error("error occured. idx[%d]", idx);
484                         break;
485                 }
486         }
487
488         return MM_ERROR_NONE;
489 }