Adds changes for mode of stream recoder
[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                         case GST_STATE_CHANGE_SUCCESS:
297                                 /* if we reached the final target state, exit */
298                                 if (pipeline_state == target_state) {
299                                         _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
300                                         return MM_ERROR_NONE;
301                                 }
302                                 break;
303                         case GST_STATE_CHANGE_ASYNC:
304                                 _mmstreamrec_dbg_log("status=GST_STATE_CHANGE_ASYNC.");
305                                 break;
306                         default:
307                                 _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
308                                 _mmstreamrec_dbg_log("status=GST_STATE_CHANGE_FAILURE.");
309                                 return MM_ERROR_STREAMRECORDER_GST_STATECHANGE;
310                         }
311
312                         _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
313                         _mmstreamrec_dbg_err("timeout of gst_element_get_state()!!");
314                         return MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT;
315                 }
316                 usleep(_MMSTREAMRECORDER_STATE_CHECK_INTERVAL);
317         }
318
319         _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
320
321         _mmstreamrec_dbg_err("Failure. gst_element_set_state timeout!!");
322
323         return MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT;
324 }
325
326 GstCaps *gst_set_videosrcpad_caps_sw(gint srcfmt, gint width, gint height, gint rate, gint scale)
327 {
328
329         GstCaps *caps = NULL;
330
331         switch (srcfmt) {
332         case MM_STREAMRECORDER_INPUT_FORMAT_NV12 :
333                 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);
334                 break;
335         case MM_STREAMRECORDER_INPUT_FORMAT_I420 :
336                 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);
337                 break;
338         case MM_STREAMRECORDER_INPUT_FORMAT_BGRA :
339                 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);
340                 break;
341         default :
342                 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);
343                 break;
344         }
345
346         if (!caps)
347                 _mmstreamrec_dbg_err("failed to alloc caps");
348
349         /* gchar *type = gst_caps_to_string(caps); */
350
351         /* _mmstreamrec_dbg_warn("Set srcpad caps: %s",type); */
352
353         /* g_free(type); */
354
355         return caps;
356 }
357
358 GstCaps *gst_set_videosrcpad_caps_hw(gchar* elem, gint width, gint height, gint rate, gint scale)
359 {
360
361         GstCaps *caps = NULL;
362         _mmstreamrec_dbg_err("Hardware Codec Element [%s]", elem);
363
364
365         if (!g_strcmp0(elem, "sprd"))
366                 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);
367
368         if (!caps)
369                 _mmstreamrec_dbg_err("failed to alloc caps");
370
371         return caps;
372 }
373
374 GstCaps *gst_set_audiosrcpad_caps(gint samplerate, gint channel, gint depth, gint width, gint datatype)
375 {
376
377         GstCaps *caps = gst_caps_new_simple("audio/x-raw",
378                                                                                 "rate", G_TYPE_INT, samplerate,
379                                                                                 "channels", G_TYPE_INT, 2,
380                                                                                 "depth", G_TYPE_INT, depth,
381                                                                                 "width", G_TYPE_INT, width,
382                                                                                 "signed", G_TYPE_BOOLEAN, TRUE,
383                                                                                 "endianness", G_TYPE_INT, 1234,
384                                                                                 NULL);
385
386         if (!caps) {
387                 _mmstreamrec_dbg_err("failed to alloc caps");
388                 return NULL;
389         }
390
391         /* gchar *type = gst_caps_to_string(caps); */
392
393         /* _mmstreamrec_dbg_log("Set srcpad caps: %s", type); */
394
395         /* g_free(type); */
396
397         return caps;
398 }