Fix coverity issue
[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                 LOGE("Invalid arguments [tag null]");
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                 LOGE("[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                 LOGE("[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                 LOGE("[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                 LOGE("[ERROR] - handle encodebin");
59                 goto ERROR2;
60         }
61
62         handle->property = g_new0(handle_property_s, 1);
63         if (!handle->property) {
64                 LOGE("[ERROR] - handle property");
65                 goto ERROR1;
66         }
67
68         *MMHandle = (MMHandleType)handle;
69
70         LOGD("MMHandle: %p", 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                 LOGE("[ERROR] - handle");
94                 return MM_ERROR_INVALID_ARGUMENT;
95         }
96
97         if (!handle->property) {
98                 LOGE("[ERROR] - handle property");
99                 return MM_ERROR_TRANSCODE_INTERNAL;
100         }
101
102         if ((in_Filename == NULL) || (strlen(in_Filename) == 0)) {
103                 LOGE("Invalid Input file");
104                 return MM_ERROR_INVALID_ARGUMENT;
105         }
106
107         if (videoencoder == MM_VIDEOENCODER_NO_USE && audioencoder == MM_AUDIOENCODER_NO_USE) {
108                 LOGE("No encoder resource");
109                 return MM_ERROR_INVALID_ARGUMENT;
110         }
111
112         if (videoencoder == MM_VIDEOENCODER_H264) {
113                 LOGE("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                 LOGE("ERROR -Set element");
121                 return ret;
122         }
123
124         LOGD("%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                         LOGD("Success - Setup Pipeline");
131                 } else {
132                         LOGE("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                         LOGD("Success - Get stream info");
140                 } else {
141                         LOGE("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                         LOGD("Success - Create Pipeline");
149                 } else {
150                         LOGE("ERROR -Create Pipeline");
151                         return ret;
152                 }
153
154                 /*link pipeline */
155                 ret = _mm_transcode_link(handle);
156                 if (ret == MM_ERROR_NONE) {
157                         LOGD("Success - Link pipeline");
158                 } else {
159                         LOGE("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                         LOGD("Success - Init parameter");
167                 } else {
168                         LOGE("ERROR - Init parameter");
169                         return ret;
170                 }
171
172                 /* create thread */
173                 ret = _mm_transcode_thread(handle);
174                 if (ret == MM_ERROR_NONE) {
175                         LOGD("Success - Link pipeline");
176                 } else {
177                         LOGE("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                 LOGD("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                 LOGE("[ERROR] - handle");
200                 return MM_ERROR_INVALID_ARGUMENT;
201         }
202
203         if (!handle->property) {
204                 LOGE("[ERROR] - handle property");
205                 return MM_ERROR_TRANSCODE_INTERNAL;
206         }
207
208         if (!completed_callback) {
209                 LOGE("[ERROR] - completed_callback");
210                 return MM_ERROR_INVALID_ARGUMENT;
211         }
212
213         if (!out_Filename) {
214                 LOGE("[ERROR] - out_Filename");
215                 return MM_ERROR_INVALID_ARGUMENT;
216         }
217
218         if (duration < MIN_DURATION && duration != 0) {
219                 LOGE("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         LOGD("[MMHandle] %p [progress_cb] %p [progress_cb_param] %p",
226                 MMHandle, handle->property->progress_cb, handle->property->progress_cb_param);
227
228         handle->property->completed_cb = completed_callback;
229         handle->property->completed_cb_param = user_param;
230         LOGD("[MMHandle] %p [completed_cb] %p [completed_cb_param] %p",
231                 MMHandle, handle->property->completed_cb, handle->property->completed_cb_param);
232
233         if (!handle->property) {
234                 LOGE("[ERROR] - handle property");
235                 return MM_ERROR_TRANSCODE_INTERNAL;
236         }
237         /* check if prepare is called during transcoding */
238         if (handle->property->_MMHandle == 1) {
239                 handle_param_s *param = g_new0(handle_param_s, 1);
240                 if (param) {
241                         /*g_value_init (param, G_TYPE_INT); */
242                         LOGD("[param] %p", param);
243                 }
244
245                 /* set parameter */
246                 ret = _mm_transcode_set_handle_parameter(param, resolution_width, resolution_height, fps_value, start_position, duration, seek_mode, out_Filename);
247                 if (ret != MM_ERROR_NONE) {
248                         LOGE("ERROR -Set parameter");
249                         TRANSCODE_FREE(param);
250                         return ret;
251                 }
252
253                 ret = _mm_transcode_preset_capsfilter(handle, resolution_width, resolution_height);
254                 if (ret == MM_ERROR_NONE) {
255                         LOGD("Success - Preset Capsfilter");
256                 } else {
257                         LOGE("ERROR - Preset Capsfilter");
258                         TRANSCODE_FREE(param);
259                         return ret;
260                 }
261
262                 handle->property->is_busy = TRUE;
263
264                 /*push data to handle */
265                 g_async_queue_push(handle->property->queue, GINT_TO_POINTER(param));
266         }
267
268         return ret;
269 }
270
271 int mm_transcode_is_busy(MMHandleType MMHandle, bool *is_busy)
272 {
273         int ret = MM_ERROR_NONE;
274
275         handle_s *handle = (handle_s *)MMHandle;
276
277         if (!handle) {
278                 LOGE("[ERROR] - handle");
279                 return MM_ERROR_INVALID_ARGUMENT;
280         }
281
282         if (!handle->property) {
283                 LOGE("[ERROR] - handle property");
284                 return MM_ERROR_TRANSCODE_INTERNAL;
285         }
286
287         if (!is_busy) {
288                 LOGE("[ERROR] - is_busy");
289                 return MM_ERROR_INVALID_ARGUMENT;
290         }
291
292         *is_busy = handle->property->is_busy;
293         LOGD("[Transcoding....] %d", *is_busy);
294
295         return ret;
296 }
297
298 int mm_transcode_cancel(MMHandleType MMHandle)
299 {
300         int ret = MM_ERROR_NONE;
301         handle_s *handle = (handle_s *)MMHandle;
302
303         if (!handle) {
304                 LOGE("[ERROR] - handle");
305                 return MM_ERROR_INVALID_ARGUMENT;
306         }
307
308         if (!handle->property) {
309                 LOGE("[ERROR] - handle property");
310                 return MM_ERROR_TRANSCODE_INTERNAL;
311         }
312
313         if (handle->property->is_busy) {
314                 LOGD("Cancel - [IS BUSY]");
315                 ret = _mm_transcode_state_change(handle, GST_STATE_NULL);
316                 if (ret != MM_ERROR_NONE) {
317                         LOGE("ERROR - Null Pipeline");
318                         return ret;
319                 }
320
321                 if ((handle->param) && (strlen(handle->param->outputfile) > 0)) {
322                         unlink(handle->param->outputfile);
323                         LOGD("[Cancel] unlink %s", handle->param->outputfile);
324                 } else {
325                         LOGE("unlink error");
326                         return MM_ERROR_TRANSCODE_INTERNAL;
327                 }
328                 g_mutex_lock(handle->property->thread_mutex);
329                 g_cond_signal(handle->property->thread_cond);
330                 LOGD("===> send completed signal <-cancel");
331                 g_mutex_unlock(handle->property->thread_mutex);
332         }
333
334         handle->property->is_busy = FALSE;
335
336         return ret;
337 }
338
339 int mm_transcode_destroy(MMHandleType MMHandle)
340 {
341         int ret = MM_ERROR_NONE;
342
343         handle_s *handle = (handle_s *)MMHandle;
344
345         if (!handle) {
346                 LOGE("[ERROR] - handle");
347                 return MM_ERROR_INVALID_ARGUMENT;
348         }
349
350         if (!handle->property) {
351                 LOGE("[ERROR] - handle property");
352                 return MM_ERROR_TRANSCODE_INTERNAL;
353         }
354
355         g_mutex_lock(handle->property->thread_exit_mutex);
356         handle->property->repeat_thread_exit = TRUE;
357         if (handle->property->is_busy) {
358                 ret = mm_transcode_cancel(MMHandle);
359                 if (ret == MM_ERROR_NONE) {
360                         LOGD("Success - Cancel Transcode");
361                 } else {
362                         LOGE("ERROR - Cancel Transcode");
363                         return FALSE;
364                 }
365         }
366         /* handle->property->is_busy = FALSE; */
367         g_mutex_unlock(handle->property->thread_exit_mutex);
368
369         handle_param_s *param = g_new0(handle_param_s, 1);
370         if (param) {
371                 LOGD("[Try to Push Last Queue]");
372                 g_async_queue_push(handle->property->queue, GINT_TO_POINTER(param));
373         } else {
374                 LOGE("Fail to create Last Queue");
375                 return MM_ERROR_INVALID_ARGUMENT;
376         }
377         ret = _mm_cleanup_signal(handle);
378         if (ret == MM_ERROR_NONE) {
379                 LOGD("Success - CleanUp Signal");
380         } else {
381                 LOGE("ERROR - CleanUp Signal");
382                 return ret;
383         }
384
385         ret = _mm_transcode_state_change(handle, GST_STATE_NULL);
386         if (ret != MM_ERROR_NONE) {
387                 LOGE("ERROR - Null Pipeline");
388                 return ret;
389         } else {
390                 LOGD("SUCCESS - Null Pipeline");
391         }
392
393         if ((handle->param) && (!handle->param->completed)) {
394                 g_cond_signal(handle->property->thread_cond);
395                 LOGD("===> send completed signal <-destroy");
396                 g_mutex_unlock(handle->property->thread_mutex);
397                 LOGD("unlock destory");
398                 if (strlen(handle->param->outputfile) > 0) {
399                         unlink(handle->param->outputfile);
400                         LOGD("[Cancel] unlink %s", handle->param->outputfile);
401                 }
402         }
403
404         ret = _mm_cleanup_pipeline(handle);
405         if (ret == MM_ERROR_NONE) {
406                 LOGD("Success - CleanUp Pipeline");
407         } else {
408                 LOGE("ERROR - CleanUp Pipeline");
409                 return ret;
410         }
411         TRANSCODE_FREE(param);
412         LOGD("[param] free");
413
414         return ret;
415 }
416
417 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)
418 {
419
420         int ret = MM_ERROR_NONE;
421         handle_s *handle = (handle_s *)MMHandle;
422
423         if (!handle) {
424                 LOGE("[ERROR] - handle");
425                 return MM_ERROR_INVALID_ARGUMENT;
426         }
427
428         if (!handle->property) {
429                 LOGE("[ERROR] - handle property");
430                 return MM_ERROR_TRANSCODE_INTERNAL;
431         }
432
433         if (!containerformat || !videoencoder || !audioencoder || !current_pos || !duration || !resolution_width || !resolution_height) {
434                 LOGE("[ERROR] - Invalid argument pointer");
435                 return MM_ERROR_INVALID_ARGUMENT;
436         }
437
438         *containerformat = handle->property->containerformat;
439         *videoencoder = handle->property->videoencoder;
440         *audioencoder = handle->property->audioencoder;
441
442         if (!handle->property) {
443                 LOGE("[ERROR] - handle property");
444                 return MM_ERROR_TRANSCODE_INTERNAL;
445         }
446
447         if (handle->property->current_pos > handle->param->duration)
448                 *current_pos = handle->param->duration;
449         else
450                 *current_pos = handle->property->current_pos;
451         *duration = handle->property->real_duration;
452         *resolution_width = handle->param->resolution_width;
453         *resolution_height = handle->param->resolution_height;
454
455         LOGD("containerformat : %d, videoencoder : %d, audioencoder : %d, current_pos : %lu, duration : %lu, resolution_width : %d, resolution_height : %d",
456                 *containerformat, *videoencoder, *audioencoder, *current_pos,
457                 *duration, *resolution_width, *resolution_height);
458
459         return ret;
460 }
461
462 int mm_transcode_get_supported_container_format(mm_transcode_support_type_callback type_callback, void *user_param)
463 {
464         int idx = 0;
465
466         for (idx = 0; idx < MM_CONTAINER_NUM; idx++) {
467                 if (type_callback(idx, user_param) == false) {
468                         LOGE("error occured. idx[%d]", idx);
469                         break;
470                 }
471         }
472
473         return MM_ERROR_NONE;
474 }
475
476 int mm_transcode_get_supported_video_encoder(mm_transcode_support_type_callback type_callback, void *user_param)
477 {
478         int idx = 0;
479
480         for (idx = 0; idx < MM_VIDEOENCODER_H264; idx++) {
481                 if (type_callback(idx, user_param) == false) {
482                         LOGE("error occured. idx[%d]", idx);
483                         break;
484                 }
485         }
486
487         return MM_ERROR_NONE;
488 }
489
490 int mm_transcode_get_supported_audio_encoder(mm_transcode_support_type_callback type_callback, void *user_param)
491 {
492         int idx = 0;
493
494         for (idx = 0; idx < MM_AUDIOENCODER_NO_USE; idx++) {
495                 if (type_callback(idx, user_param) == false) {
496                         LOGE("error occured. idx[%d]", idx);
497                         break;
498                 }
499         }
500
501         return MM_ERROR_NONE;
502 }