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