Add tool package to separate testsuite binary
[platform/core/multimedia/libmm-streamrecorder.git] / src / mm_streamrecorder_gstcommon.c
1 /*
2  * libmm-streamrecorder
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hyuntae Kim <ht1211.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
22 /*=======================================================================================
23 |  INCLUDE FILES                                                                        |
24 =======================================================================================*/
25 #include <sys/time.h>
26 #include <unistd.h>
27
28 #include "mm_streamrecorder_internal.h"
29 #include "mm_streamrecorder_gstcommon.h"
30 #include "mm_streamrecorder_gstdispatch.h"
31 #include "mm_streamrecorder_util.h"
32 #include "mm_streamrecorder.h"
33
34 /*-----------------------------------------------------------------------
35 |    GLOBAL VARIABLE DEFINITIONS for internal                           |
36 -----------------------------------------------------------------------*/
37
38 /*-----------------------------------------------------------------------
39 |    LOCAL VARIABLE DEFINITIONS for internal                            |
40 -----------------------------------------------------------------------*/
41 #define USE_AUDIO_CLOCK_TUNE
42 #define _MMSTREAMRECORDER_WAIT_EOS_TIME              5.0        /* sec */
43 #define _MMSTREAMRECORDER_STATE_SET_COUNT                       3
44
45 /*-----------------------------------------------------------------------
46 |    LOCAL FUNCTION PROTOTYPES:                                         |
47 -----------------------------------------------------------------------*/
48 /* STATIC INTERNAL FUNCTION */
49
50 /*=======================================================================================
51 |  FUNCTION DEFINITIONS                                                                 |
52 =======================================================================================*/
53 /*-----------------------------------------------------------------------
54 |    GLOBAL FUNCTION DEFINITIONS:                                       |
55 -----------------------------------------------------------------------*/
56 gboolean _mmstreamrecorder_gstreamer_init()
57 {
58         static const int max_argc = 10;
59         int i = 0;
60         gint *argc = NULL;
61         gchar **argv = NULL;
62         GError *err = NULL;
63         gboolean ret = FALSE;
64         /* type_string_array *GSTInitOption = NULL; */
65
66         /* mmf_return_val_if_fail(conf, FALSE); */
67
68         _mmstreamrec_dbg_log("");
69
70         /* alloc */
71         argc = malloc(sizeof(int));
72         argv = malloc(sizeof(gchar *) * max_argc);
73
74         if (!argc || !argv)
75                 goto ERROR;
76
77         memset(argv, 0, sizeof(gchar *) * max_argc);
78
79         /* add initial */
80         *argc = 1;
81         argv[0] = g_strdup("mmstreamrecorder");
82
83         _mmstreamrec_dbg_log("initializing gstreamer with following parameter[argc:%d]", *argc);
84
85         for (i = 0; i < *argc; i++)
86                 _mmstreamrec_dbg_log("argv[%d] : %s", i, argv[i]);
87
88         /* initializing gstreamer */
89         ret = gst_init_check(argc, &argv, &err);
90
91         if (!ret) {
92                 _mmstreamrec_dbg_err("Could not initialize GStreamer: %s ", err ? err->message : "unknown error occurred");
93                 if (err)
94                         g_error_free(err);
95         }
96
97         /* release */
98
99         for (i = 0; i < *argc; i++) {
100                 if (argv[i]) {
101                         g_free(argv[i]);
102                         argv[i] = NULL;
103                 }
104         }
105
106         if (argv) {
107                 g_free(argv);
108                 argv = NULL;
109         }
110
111         if (argc) {
112                 g_free(argc);
113                 argc = NULL;
114         }
115
116         return ret;
117
118  ERROR:
119         _mmstreamrec_dbg_err("failed to initialize gstreamer");
120
121         if (argv) {
122                 g_free(argv);
123                 argv = NULL;
124         }
125
126         if (argc) {
127                 g_free(argc);
128                 argc = NULL;
129         }
130
131         return FALSE;
132 }
133
134 int _mmstreamrecorder_get_eos_message(MMHandleType handle)
135 {
136         double elapsed = 0.0;
137
138         GstMessage *gMessage = NULL;
139         GstBus *bus = NULL;
140         GstClockTime timeout = 1 * GST_SECOND;  /* maximum waiting time */
141         GTimer *timer = NULL;
142
143         mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
144         _MMStreamRecorderSubContext *sc = NULL;
145
146         mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
147         sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
148
149         _mmstreamrec_dbg_log("");
150         if (sc) {
151                 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst));
152                 timer = g_timer_new();
153
154                 if (!(sc->bget_eos)) {
155                         while (TRUE) {
156                                 elapsed = g_timer_elapsed(timer, NULL);
157
158                                 /*_mmstreamrec_dbg_log("elapsed:%f sec", elapsed);*/
159
160                                 if (elapsed > _MMSTREAMRECORDER_WAIT_EOS_TIME) {
161                                         _mmstreamrec_dbg_warn("Timeout. EOS isn't received.");
162                                         g_timer_destroy(timer);
163                                         gst_object_unref(bus);
164                                         return MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT;
165                                 }
166
167                                 gMessage = gst_bus_timed_pop(bus, timeout);
168                                 if (gMessage != NULL) {
169                                         _mmstreamrec_dbg_log("Get message(%x).", GST_MESSAGE_TYPE(gMessage));
170                                         _mmstreamrecorder_pipeline_cb_message(bus, gMessage, (void *)hstreamrecorder);
171
172                                         if (GST_MESSAGE_TYPE(gMessage) == GST_MESSAGE_EOS || sc->bget_eos) {
173                                                 gst_message_unref(gMessage);
174                                                 break;
175                                         }
176                                         gst_message_unref(gMessage);
177                                 } else {
178                                         _mmstreamrec_dbg_log("timeout of gst_bus_timed_pop()");
179                                         if (sc->bget_eos) {
180                                                 _mmstreamrec_dbg_log("Get EOS in another thread.");
181                                                 break;
182                                         }
183                                 }
184                         }
185                 }
186
187                 g_timer_destroy(timer);
188                 timer = NULL;
189                 gst_object_unref(bus);
190                 bus = NULL;
191         } else {
192                 _mmstreamrec_dbg_err("subcontext error NULL");
193         }
194         _mmstreamrec_dbg_log("END");
195
196         return MM_ERROR_NONE;
197 }
198
199 void _mmstreamrecorder_remove_element_handle(MMHandleType handle, void *element, int first_elem, int last_elem)
200 {
201         int i = 0;
202         _MMStreamRecorderGstElement *remove_element = (_MMStreamRecorderGstElement *) element;
203
204         mmf_return_if_fail(handle && remove_element);
205         mmf_return_if_fail((first_elem >= 0) && (last_elem > 0) && (last_elem > first_elem));
206
207         _mmstreamrec_dbg_log("");
208
209         for (i = first_elem; i <= last_elem; i++) {
210                 remove_element[i].gst = NULL;
211                 remove_element[i].id = _MMSTREAMRECORDER_ENCODE_NONE;
212         }
213
214         return;
215 }
216
217 gboolean _mmstreamrecorder_add_elements_to_bin(GstBin *bin, GList *element_list)
218 {
219         GList *local_list = element_list;
220         _MMStreamRecorderGstElement *element = NULL;
221
222         mmf_return_val_if_fail(bin && local_list, FALSE);
223
224         while (local_list) {
225                 element = (_MMStreamRecorderGstElement *) local_list->data;
226                 if (element && element->gst) {
227                         if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
228                                 _mmstreamrec_dbg_err("Add element [%s] to bin [%s] FAILED", GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(bin)));
229                                 return FALSE;
230                         } else {
231                                 _mmstreamrec_dbg_log("Add element [%s] to bin [%s] OK", GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(bin)));
232                         }
233                 }
234                 local_list = local_list->next;
235         }
236
237         return TRUE;
238 }
239
240 gboolean _mmstreamrecorder_link_elements(GList * element_list)
241 {
242         GList *local_list = element_list;
243         _MMStreamRecorderGstElement *element = NULL;
244         _MMStreamRecorderGstElement *pre_element = NULL;
245
246         mmf_return_val_if_fail(local_list, FALSE);
247
248         pre_element = (_MMStreamRecorderGstElement *) local_list->data;
249         local_list = local_list->next;
250
251         while (local_list) {
252                 element = (_MMStreamRecorderGstElement *) local_list->data;
253                 if (element && element->gst) {
254                         if (pre_element != NULL) {
255                                 if (_MM_GST_ELEMENT_LINK(GST_ELEMENT(pre_element->gst), GST_ELEMENT(element->gst))) {
256                                         _mmstreamrec_dbg_log("Link [%s] to [%s] OK", GST_ELEMENT_NAME(GST_ELEMENT(pre_element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
257                                 } else {
258                                         _mmstreamrec_dbg_err("Link [%s] to [%s] FAILED", GST_ELEMENT_NAME(GST_ELEMENT(pre_element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
259                                         return FALSE;
260                                 }
261                         } else {
262                                 _mmstreamrec_dbg_err("pre_element is null");
263                                 return FALSE;
264                         }
265                 }
266
267                 pre_element = element;
268                 local_list = local_list->next;
269         }
270
271         return TRUE;
272 }
273
274 int _mmstreamrecorder_gst_set_state(MMHandleType handle, GstElement *pipeline, GstState target_state)
275 {
276         unsigned int k = 0;
277         GstState pipeline_state = GST_STATE_VOID_PENDING;
278         GstStateChangeReturn setChangeReturn = GST_STATE_CHANGE_FAILURE;
279         GstStateChangeReturn getChangeReturn = GST_STATE_CHANGE_FAILURE;
280         GstClockTime get_timeout = __MMSTREAMRECORDER_SET_GST_STATE_TIMEOUT * GST_SECOND;
281
282         mmf_return_val_if_fail(handle, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
283
284         _mmstreamrec_dbg_log("Set state to %d", target_state);
285
286         _MMSTREAMRECORDER_LOCK_GST_STATE(handle);
287
288         for (k = 0; k < _MMSTREAMRECORDER_STATE_SET_COUNT; k++) {
289                 setChangeReturn = gst_element_set_state(pipeline, target_state);
290                 _mmstreamrec_dbg_log("gst_element_set_state[%d] return %d", target_state, setChangeReturn);
291                 if (setChangeReturn != GST_STATE_CHANGE_FAILURE) {
292                         getChangeReturn = gst_element_get_state(pipeline, &pipeline_state, NULL, get_timeout);
293                         switch (getChangeReturn) {
294                         case GST_STATE_CHANGE_NO_PREROLL:
295                                 _mmstreamrec_dbg_log("status=GST_STATE_CHANGE_NO_PREROLL.");
296                                 /* fall through */
297                         case GST_STATE_CHANGE_SUCCESS:
298                                 /* if we reached the final target state, exit */
299                                 if (pipeline_state == target_state) {
300                                         _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
301                                         return MM_ERROR_NONE;
302                                 }
303                                 break;
304                         case GST_STATE_CHANGE_ASYNC:
305                                 _mmstreamrec_dbg_log("status=GST_STATE_CHANGE_ASYNC.");
306                                 break;
307                         default:
308                                 _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
309                                 _mmstreamrec_dbg_log("status=GST_STATE_CHANGE_FAILURE.");
310                                 return MM_ERROR_STREAMRECORDER_GST_STATECHANGE;
311                         }
312
313                         _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
314                         _mmstreamrec_dbg_err("timeout of gst_element_get_state()!!");
315                         return MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT;
316                 }
317                 usleep(_MMSTREAMRECORDER_STATE_CHECK_INTERVAL);
318         }
319
320         _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
321
322         _mmstreamrec_dbg_err("Failure. gst_element_set_state timeout!!");
323
324         return MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT;
325 }
326
327 GstCaps *gst_set_videosrcpad_caps_sw(gint srcfmt, gint width, gint height, gint rate, gint scale)
328 {
329
330         GstCaps *caps = NULL;
331         gchar *type  = NULL;
332         switch (srcfmt) {
333         case MM_STREAMRECORDER_INPUT_FORMAT_NV12 :
334                 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "NV12", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
335                 break;
336         case MM_STREAMRECORDER_INPUT_FORMAT_NV21 :
337                 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "NV21", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
338                 break;
339         case MM_STREAMRECORDER_INPUT_FORMAT_I420 :
340                 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "I420", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
341                 break;
342         case MM_STREAMRECORDER_INPUT_FORMAT_BGRA :
343                 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGRA", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
344                 break;
345         default :
346                 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGRA", "bpp", G_TYPE_INT, 32, "depth", G_TYPE_INT, 24, "endianness", G_TYPE_INT, 4321, "red_mask", G_TYPE_INT, 65280, "green_mask", G_TYPE_INT, 16711680, "blue_mask", G_TYPE_INT, -16777216, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
347                 break;
348         }
349
350         if (!caps)
351                 _mmstreamrec_dbg_err("failed to alloc caps");
352
353         type = gst_caps_to_string(caps);
354
355         _mmstreamrec_dbg_warn("Set srcfmt %d caps: %s",srcfmt, type);
356
357         g_free(type);
358
359         return caps;
360 }
361
362 GstCaps *gst_set_videosrcpad_caps_hw(gchar* elem, gint width, gint height, gint rate, gint scale)
363 {
364
365         GstCaps *caps = NULL;
366         _mmstreamrec_dbg_err("Hardware Codec Element [%s]", elem);
367
368
369         if (!g_strcmp0(elem, "sprd"))
370                 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
371
372         if (!caps)
373                 _mmstreamrec_dbg_err("failed to alloc caps");
374
375         return caps;
376 }
377
378 GstCaps *gst_set_audiosrcpad_caps(gint samplerate, gint channel, gint depth, gint width, gint datatype)
379 {
380
381         GstCaps *caps = gst_caps_new_simple("audio/x-raw",
382                                                                                 "rate", G_TYPE_INT, samplerate,
383                                                                                 "channels", G_TYPE_INT, 2,
384                                                                                 "depth", G_TYPE_INT, depth,
385                                                                                 "width", G_TYPE_INT, width,
386                                                                                 "signed", G_TYPE_BOOLEAN, TRUE,
387                                                                                 "endianness", G_TYPE_INT, 1234,
388                                                                                 NULL);
389
390         if (!caps) {
391                 _mmstreamrec_dbg_err("failed to alloc caps");
392                 return NULL;
393         }
394
395         /* gchar *type = gst_caps_to_string(caps); */
396
397         /* _mmstreamrec_dbg_log("Set srcpad caps: %s", type); */
398
399         /* g_free(type); */
400
401         return caps;
402 }