[libmm-camcorder] Add for muse Daemonizer
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_videorec.c
1 /*
2  * libmm-camcorder
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jeongmo Yang <jm80.yang@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 <gst/video/cameracontrol.h>
26 #include <gst/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
29
30 /*---------------------------------------------------------------------------------------
31 |    GLOBAL VARIABLE DEFINITIONS for internal                                           |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_LOCATION_INFO // for add gps information
34 #define MAX_ERROR_MESSAGE_LEN         128
35
36 /*---------------------------------------------------------------------------------------
37 |    LOCAL VARIABLE DEFINITIONS for internal                                            |
38 ---------------------------------------------------------------------------------------*/
39 #define _MMCAMCORDER_MINIMUM_FRAME              5
40 #define _MMCAMCORDER_RETRIAL_COUNT              10
41 #define _MMCAMCORDER_FRAME_WAIT_TIME            200000 /* ms */
42 #define _OFFSET_COMPOSITION_MATRIX              40L
43 #define _GOP_GEN_INTERVAL                       1000000000  /*nano seconds*/
44
45 /*---------------------------------------------------------------------------------------
46 |    LOCAL FUNCTION PROTOTYPES:                                                         |
47 ---------------------------------------------------------------------------------------*/
48 /* STATIC INTERNAL FUNCTION */
49 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
54 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
55 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
56 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
57 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
58
59 /*=======================================================================================
60 |  FUNCTION DEFINITIONS                                                                 |
61 =======================================================================================*/
62 /*---------------------------------------------------------------------------------------
63 |    GLOBAL FUNCTION DEFINITIONS:                                                       |
64 ---------------------------------------------------------------------------------------*/
65 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
66 {
67         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
68         _MMCamcorderSubContext *sc = NULL;
69
70         GstBuffer *buffer = gst_sample_get_buffer(sample);
71         mmf_return_if_fail(buffer);
72         mmf_return_if_fail(gst_buffer_n_memory(buffer));
73         mmf_return_if_fail(hcamcorder);
74
75         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
76         mmf_return_if_fail(sc);
77
78         /*
79         _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
80                        sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
81         */
82
83         /* push buffer in appsrc to encode */
84         if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
85             sc->info_video->record_dual_stream &&
86             sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
87                 GstFlowReturn ret = 0;
88                 GstClock *pipe_clock = NULL;
89
90                 if(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
91                         if(sc->info_video->is_firstframe) {
92                                 sc->info_video->is_firstframe = FALSE;
93                                 pipe_clock = GST_ELEMENT_CLOCK(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
94                                 if (pipe_clock) {
95                                         gst_object_ref(pipe_clock);
96                                         sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer) - (gst_clock_get_time(pipe_clock) - GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
97                                         gst_object_unref(pipe_clock);
98                                 }
99                         }
100                 } else {
101                         if(sc->info_video->is_firstframe) {
102                                 sc->info_video->is_firstframe = FALSE;
103                                 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer);
104                         }
105                 }
106
107                 GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS (buffer) - sc->info_video->base_video_ts;
108
109                 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
110                 if (ret != GST_FLOW_OK &&
111                     ret != GST_FLOW_FLUSHING) {
112                         _mmcam_dbg_err("gst_app_src_push_buffer failed [0x%x]", ret);
113                         gst_buffer_unref(buffer);
114                         buffer = NULL;
115                 }
116
117                 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
118         } else {
119                 _mmcam_dbg_warn("unref video buffer immediately - push encoding buffer %d",
120                                 sc->info_video->push_encoding_buffer);
121
122                 gst_buffer_unref(buffer);
123                 buffer = NULL;
124         }
125
126         return;
127 }
128
129
130 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
131 {
132         int i = 0;
133         int err = MM_ERROR_NONE;
134         int audio_disable = FALSE;
135         const char* gst_element_rsink_name = NULL;
136
137         GstBus *bus = NULL;
138         GstPad *srcpad = NULL;
139         GstPad *sinkpad = NULL;
140
141         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
142         _MMCamcorderSubContext *sc = NULL;
143
144         type_element *RecordsinkElement = NULL;
145
146         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
147
148         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
149         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
150         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
151
152         _mmcam_dbg_warn("start");
153
154         err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
155         if (err != MM_ERROR_NONE) {
156                 return err;
157         }
158
159         /* Main pipeline */
160         if(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
161                 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
162                                sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
163                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
164         }
165
166         _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
167
168         /* get audio disable */
169         mm_camcorder_get_attributes(handle, NULL,
170                                     MMCAM_AUDIO_DISABLE, &audio_disable,
171                                     NULL);
172
173         if (sc->is_modified_rate || audio_disable) {
174                 sc->audio_disable = TRUE;
175         } else {
176                 sc->audio_disable = FALSE;
177         }
178         _mmcam_dbg_log("AUDIO DISABLE : %d (is_modified_rate %d, audio_disable %d)",
179                        sc->audio_disable, sc->is_modified_rate, audio_disable);
180
181         if (sc->audio_disable == FALSE) {
182                 /* create audiosrc bin */
183                 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
184                 if (err != MM_ERROR_NONE) {
185                         return err;
186                 }
187         }
188
189         err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
190         if (err != MM_ERROR_NONE) {
191                 return err;
192         }
193
194         if (sc->audio_disable == FALSE) {
195                 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
196                             sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
197         }
198
199         /* add element and encodesink bin to encode main pipeline */
200         gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
201                          sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
202                          sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
203                          sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
204                          NULL);
205
206         /* Link each element : appsrc - capsfilter - encodesink bin */
207         srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
208         sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
209         _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
210
211         srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
212         sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
213         _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
214
215         if (sc->audio_disable == FALSE) {
216                 srcpad = gst_element_get_static_pad (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
217                 sinkpad = gst_element_get_static_pad (sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
218                 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
219         }
220
221         _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
222                                       CONFIGURE_CATEGORY_MAIN_RECORD,
223                                       "RecordsinkElement",
224                                       &RecordsinkElement);
225         _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
226
227         /* set data probe function */
228
229         /* register message cb */
230
231         /* set data probe function for audio */
232
233         if (sc->audio_disable == FALSE) {
234                 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
235                 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
236                                              __mmcamcorder_audioque_dataprobe, hcamcorder);
237                 gst_object_unref(sinkpad);
238                 sinkpad = NULL;
239
240                 /* for voice mute */
241                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
242                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
243                                              __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
244                 gst_object_unref(srcpad);
245                 srcpad = NULL;
246
247                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
248                         srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
249                         MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
250                                                     __mmcamcorder_eventprobe_monitor, hcamcorder);
251                         gst_object_unref(srcpad);
252                         srcpad = NULL;
253                 }
254         }
255
256         if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
257                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
258                 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
259                                             __mmcamcorder_eventprobe_monitor, hcamcorder);
260                 gst_object_unref(srcpad);
261                 srcpad = NULL;
262         }
263
264         if (sc->audio_disable) {
265                 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
266                 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
267                                              __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
268                 gst_object_unref(sinkpad);
269                 sinkpad = NULL;
270         }
271
272         if (!strcmp(gst_element_rsink_name, "filesink")) {
273                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
274                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
275                                              __mmcamcorder_video_dataprobe_record, hcamcorder);
276                 gst_object_unref(srcpad);
277                 srcpad = NULL;
278
279                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
280                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
281                                              __mmcamcorder_audio_dataprobe_check, hcamcorder);
282                 gst_object_unref(srcpad);
283                 srcpad = NULL;
284         }
285
286         bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
287
288         /* register pipeline message callback */
289         hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
290
291         gst_object_unref(bus);
292         bus = NULL;
293
294         return MM_ERROR_NONE;
295
296 pipeline_creation_error:
297         for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++) {
298                 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
299         }
300         _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
301         return err;
302 }
303
304
305 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
306 {
307         GstPad *srcpad = NULL;
308         GstPad *sinkpad = NULL;
309         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
310         _MMCamcorderSubContext *sc = NULL;
311
312         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
313
314         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
315         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
316         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
317
318         _mmcam_dbg_log("");
319
320         if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
321                 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
322                 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
323                 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
324
325                 /* release audiosrc bin */
326                 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
327                                sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
328
329                 /*
330                         To avoid conflicting between old elements and newly created elements,
331                         I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
332                         This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
333                         So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
334                         It's because the pipeline of audio recording destroys at the same time,
335                         and '_mmcamcorder_element_release_noti' will perfom removing handle.
336                 */
337                 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
338
339                 _mmcam_dbg_log("Audio pipeline removed");
340         }
341
342         return MM_ERROR_NONE;
343 }
344
345
346 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
347 {
348         GstPad *reqpad = NULL;
349         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
350         _MMCamcorderSubContext *sc = NULL;
351
352         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
353
354         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
355         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
356         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
357
358         _mmcam_dbg_log("");
359
360         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
361                 /* release request pad */
362                 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
363                 if (reqpad) {
364                         gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
365                         gst_object_unref(reqpad);
366                         reqpad = NULL;
367                 }
368
369                 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
370                 if (reqpad) {
371                         gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
372                         gst_object_unref(reqpad);
373                         reqpad = NULL;
374                 }
375
376                 /* release encode main pipeline */
377                 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
378
379                 /*
380                         To avoid conflicting between old elements and newly created elements,
381                         I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
382                         This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
383                         So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
384                         It's because the pipeline of audio recording destroys at the same time,
385                         and '_mmcamcorder_element_release_noti' will perfom removing handle.
386                 */
387                 //_mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK);
388
389                 _mmcam_dbg_log("Encoder pipeline removed");
390         }
391
392         return MM_ERROR_NONE;
393 }
394
395
396 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
397 {
398         int ret = MM_ERROR_NONE;
399         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
400         _MMCamcorderSubContext *sc = NULL;
401
402         GstBus *bus = NULL;
403
404         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
405         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
406         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
407
408         _mmcam_dbg_log("start");
409
410         if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
411                 _mmcam_dbg_warn("pipeline is not existed.");
412                 return MM_ERROR_NONE;
413         }
414
415         _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
416
417         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
418         if (ret != MM_ERROR_NONE) {
419                 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
420                 return ret;
421         }
422
423         bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
424
425         /* remove audio pipeline first */
426         ret = _mmcamcorder_remove_audio_pipeline(handle);
427         if (ret != MM_ERROR_NONE) {
428                 _mmcam_dbg_err("Fail to remove audio pipeline");
429                 return ret;
430         }
431
432         ret = _mmcamcorder_remove_encode_pipeline(handle);
433         if (ret != MM_ERROR_NONE) {
434                 _mmcam_dbg_err("Fail to remove encoder pipeline");
435                 return ret;
436         }
437
438         /* Remove pipeline message callback */
439         if (hcamcorder->encode_pipeline_cb_event_id != 0) {
440                 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
441                 hcamcorder->encode_pipeline_cb_event_id = 0;
442         }
443
444         /* Remove remained message */
445         if (bus) {
446                 GstMessage *gst_msg = NULL;
447                 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
448                         _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
449                         gst_message_unref(gst_msg);
450                         gst_msg = NULL;
451                 }
452                 gst_object_unref(bus);
453                 bus = NULL;
454         }
455
456         _mmcam_dbg_log("done");
457
458         return ret;
459 }
460
461
462 int _mmcamcorder_video_command(MMHandleType handle, int command)
463 {
464         int size = 0;
465         int fileformat = 0;
466         int ret = MM_ERROR_NONE;
467         double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
468         char *err_name = NULL;
469         char *temp_filename = NULL;
470         GstCameraControl *CameraControl = NULL;
471         GstCameraControlChannel *CameraControlChannel = NULL;
472         const GList *controls = NULL;
473         const GList *item = NULL;
474
475         gint fps = 0;
476         GstElement *pipeline = NULL;
477
478         _MMCamcorderVideoInfo *info = NULL;
479         _MMCamcorderSubContext *sc = NULL;
480         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
481
482         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
483
484         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
485         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
486         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
487         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
488
489         info = sc->info_video;
490
491         _mmcam_dbg_log("Command(%d)", command);
492
493         pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
494
495         switch (command) {
496         case _MMCamcorder_CMD_RECORD:
497         {
498                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
499                         /**
500                          * start recording
501                          */
502                         guint imax_size = 0;
503                         guint imax_time = 0;
504                         int ret_free_space = 0;
505                         char *dir_name = NULL;
506                         guint64 free_space = 0;
507                         guint64 free_space_exceptsystem = 0;
508                         int file_system_type = 0;
509
510                         /* Recording */
511                         _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
512
513                         /* init record_dual_stream */
514                         info->record_dual_stream = FALSE;
515
516                         ret = mm_camcorder_get_attributes(handle, &err_name,
517                                                           MMCAM_CAMERA_FPS, &fps,
518                                                           MMCAM_CAMERA_WIDTH, &(info->preview_width),
519                                                           MMCAM_CAMERA_HEIGHT, &(info->preview_height),
520                                                           MMCAM_VIDEO_WIDTH, &(info->video_width),
521                                                           MMCAM_VIDEO_HEIGHT, &(info->video_height),
522                                                           MMCAM_FILE_FORMAT, &fileformat,
523                                                           MMCAM_TARGET_FILENAME, &temp_filename, &size,
524                                                           MMCAM_TARGET_MAX_SIZE, &imax_size,
525                                                           MMCAM_TARGET_TIME_LIMIT, &imax_time,
526                                                           MMCAM_FILE_FORMAT, &(info->fileformat),
527                                                           MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
528                                                           NULL);
529                         if (ret != MM_ERROR_NONE) {
530                                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
531                                 SAFE_FREE (err_name);
532                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
533                         }
534
535                         if (temp_filename == NULL) {
536                                 _mmcam_dbg_err("filename is not set");
537                                 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
538                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
539                         }
540
541                         /* set max size */
542                         if (imax_size <= 0) {
543                                 info->max_size = 0; /* do not check */
544                         } else {
545                                 info->max_size = ((guint64)imax_size) << 10; /* to byte */
546                         }
547
548                         /* set max time */
549                         if (imax_time <= 0) {
550                                 info->max_time = 0; /* do not check */
551                         } else {
552                                 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
553                         }
554
555                         dir_name = g_path_get_dirname(temp_filename);
556                         if (dir_name) {
557                                 ret_free_space = _mmcamcorder_get_freespace(dir_name, &free_space);
558                                 if(_mmcamcorder_check_file_path(dir_name)) {
559                                         if (_mmcamcorder_get_freespace_except_system(&free_space_exceptsystem) == MM_ERROR_NONE) {
560                                                 hcamcorder->system_memory = free_space - free_space_exceptsystem;
561                                                 free_space = free_space - hcamcorder->system_memory;
562                                         } else {
563                                                 hcamcorder->system_memory = 0;
564                                         }
565                                 }
566
567                                 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "], system [%" G_GUINT64_FORMAT "]",
568                                                 dir_name, free_space, hcamcorder->system_memory);
569
570                                 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
571                                         /* MSDOS_SUPER_MAGIC : 0x4d44 */
572                                         if (file_system_type == MSDOS_SUPER_MAGIC &&
573                                             (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
574                                                 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
575                                                                 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
576                                                 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
577                                         } else {
578                                                 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
579                                                                 file_system_type, info->max_size);
580                                         }
581                                 } else {
582                                         _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
583                                 }
584
585                                 g_free(dir_name);
586                                 dir_name = NULL;
587                         } else {
588                                 _mmcam_dbg_err("failed to get directory name");
589                                 ret_free_space = -1;
590                         }
591
592                         if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
593                                 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
594                                                ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
595                                 return MM_ERROR_OUT_OF_STORAGE;
596                         }
597
598                         pthread_mutex_lock(&(hcamcorder->task_thread_lock));
599                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
600                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
601                                 /* Play record start sound */
602                                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_START_SND, FALSE);
603                         }
604                         pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
605
606                         _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
607
608                         if (info->video_width == 0 || info->video_height == 0) {
609                                 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
610                                                 info->video_width, info->video_height, info->preview_width, info->preview_height);
611                                 info->video_width = info->preview_width;
612                                 info->video_height = info->preview_height;
613                         }
614
615                         if (info->support_dual_stream) {
616                                 _mmcam_dbg_warn("DUAL STREAM MODE");
617
618                                 info->record_dual_stream = TRUE;
619
620                                 /* No need to restart preview */
621                                 info->restart_preview = FALSE;
622
623                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
624                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
625                         } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
626                                    info->preview_width == info->video_width &&
627                                    info->preview_height == info->video_height) {
628                                 _mmcam_dbg_log("H264 preview mode and same resolution");
629
630                                 /* No need to restart preview */
631                                 info->restart_preview = FALSE;
632                         } else {
633                                 /* always need to restart preview  */
634                                 info->restart_preview = TRUE;
635                         }
636
637                         /* set recording hint */
638                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
639
640                         if (info->restart_preview) {
641                                 /* stop preview and set new size */
642                                 _mmcam_dbg_log("restart preview");
643
644                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
645                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
646
647                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
648
649                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
650                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
651
652                                 if (ret != MM_ERROR_NONE) {
653                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
654                                 }
655
656                                 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
657                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
658                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
659                                 }
660
661                                 /* Start preview again with new setting */
662                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
663                                 if (ret != MM_ERROR_NONE) {
664                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
665                                 }
666
667                                 if (motion_rate < 1.0) {
668                                         _mmcam_dbg_warn("wait for stabilization of frame");
669                                         usleep(300000);
670                                 }
671                         } else {
672                                 _mmcam_dbg_log("no need to restart preview");
673                         }
674
675                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
676                                                         CONFIGURE_CATEGORY_MAIN_RECORD,
677                                                         "DropVideoFrame",
678                                                         &(sc->drop_vframe));
679
680                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
681                                                         CONFIGURE_CATEGORY_MAIN_RECORD,
682                                                         "PassFirstVideoFrame",
683                                                         &(sc->pass_first_vframe));
684
685                         _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
686                                        sc->drop_vframe, sc->pass_first_vframe);
687
688                         info->record_drop_count = (guint)motion_rate;
689                         info->record_motion_rate = motion_rate;
690                         if (sc->is_modified_rate) {
691                                 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
692                         } else {
693                                 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
694                         }
695
696                         _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
697                                        fps, info->record_motion_rate, info->record_timestamp_ratio);
698
699                         /* set push buffer flag */
700                         info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
701                         info->base_video_ts = 0;
702
703                         /* connect video stream cb signal */
704                         /*130826 Connect video stream cb for handling fast record frame cb*/
705                         if (info->record_dual_stream) {
706                                 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE) {
707                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
708                                 }
709                         }
710
711                         /* start video stream */
712                         if (info->record_dual_stream) {
713                                 CameraControl =  GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
714                                 if (CameraControl) {
715                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
716
717                                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
718                                         gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
719
720                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
721                                 } else {
722                                         _mmcam_dbg_err("could not get camera control");
723                                 }
724                         }
725
726                         /* check pre-created encode pipeline */
727                         pthread_mutex_lock(&(hcamcorder->task_thread_lock));
728                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
729                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
730                                 /* create encoding pipeline */
731                                 ret =_mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
732                                 if (ret != MM_ERROR_NONE) {
733                                         pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
734                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
735                                 }
736                         }
737                         pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
738
739                         /* check recording start sound */
740                         _mmcamcorder_sound_solo_play_wait(handle);
741
742                         /**< To fix video recording hanging
743                                 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
744                                 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
745                                  basetime wouldn't change if you set (GstClockTime)0.
746                                 3. Move set start time position below PAUSED of pipeline.
747                         */
748                         //gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
749                         //gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
750
751                         info->video_frame_count = 0;
752                         info->is_firstframe = TRUE;
753                         info->audio_frame_count = 0;
754                         info->filesize = 0;
755                         sc->ferror_send = FALSE;
756                         sc->ferror_count = 0;
757                         hcamcorder->error_occurs = FALSE;
758                         sc->bget_eos = FALSE;
759
760                         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
761                         if (ret != MM_ERROR_NONE) {
762                                 /* stop video stream */
763                                 if (info->record_dual_stream) {
764                                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
765                                         if (CameraControl) {
766                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
767
768                                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
769                                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
770
771                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
772                                         } else {
773                                                 _mmcam_dbg_err("failed to get camera control");
774                                         }
775                                 }
776
777                                 /* Remove recorder pipeline and recording file which size maybe zero */
778                                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
779                                 if (info->filename) {
780                                         _mmcam_dbg_log("file delete(%s)", info->filename);
781                                         unlink(info->filename);
782                                 }
783                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
784                         }
785
786                         /*set the camera control to create the GOP so that video record will get a new key frame*/
787                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
788                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
789                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
790                                 controls = gst_camera_control_list_channels(CameraControl);
791                                 if (controls != NULL) {
792                                         for (item = controls ; item && item->data ; item = item->next) {
793                                                 CameraControlChannel = item->data;
794                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
795                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
796                                                         //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
797                                                         break;
798                                                 }
799                                         }
800
801                                         if (item == NULL) {
802                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
803                                         }
804                                 }
805                         } else {
806                                 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
807                                                 sc->info_image->preview_format);
808                         }
809                 } else {
810                         /* Resume case */
811
812                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
813                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
814                                 /* generate and I-frame on resuming */
815                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
816                                 controls = gst_camera_control_list_channels(CameraControl);
817                                 if (controls != NULL) {
818                                         for (item = controls ; item && item->data ; item = item->next) {
819                                                 CameraControlChannel = item->data;
820                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
821                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
822                                                         //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
823                                                         break;
824                                                 }
825                                         }
826
827                                         if (item == NULL) {
828                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
829                                         }
830                                 }
831                         }
832
833                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
834
835                         _mmcam_dbg_log("Object property settings done");
836                 }
837         }
838                 break;
839         case _MMCamcorder_CMD_PAUSE:
840         {
841                 int count = 0;
842
843                 if (info->b_commiting) {
844                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
845                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
846                 }
847
848                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
849                         if (sc->audio_disable) {
850                                 /* check only video frame */
851                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
852                                         break;
853                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
854                                         _mmcam_dbg_err("Pause fail, frame count %" G_GUINT64_FORMAT "",
855                                                        info->video_frame_count);
856                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
857                                 } else {
858                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %" G_GUINT64_FORMAT "",
859                                                         count, info->video_frame_count);
860                                 }
861
862                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
863                         } else {
864                                 /* check both of video and audio frame */
865                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
866                                         break;
867                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
868                                         _mmcam_dbg_err("Pause fail, frame count VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
869                                                        info->video_frame_count, info->audio_frame_count);
870                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
871                                 } else {
872                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
873                                                         count, info->video_frame_count, info->audio_frame_count);
874                                 }
875
876                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
877                         }
878                 }
879
880                 /* block encodebin */
881                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
882                 break;
883         }
884         case _MMCamcorder_CMD_CANCEL:
885         {
886                 if (info->b_commiting) {
887                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
888                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
889                 }
890
891                 /* block push buffer */
892                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
893
894                 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
895                 if (ret != MM_ERROR_NONE) {
896                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
897                 }
898
899                 /* set recording hint */
900                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
901
902                 /* stop video stream */
903                 if (info->record_dual_stream) {
904                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
905                         if (CameraControl) {
906                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
907
908                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
909                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
910
911                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
912                         } else {
913                                 _mmcam_dbg_err("failed to get camera control");
914                         }
915                 }
916
917                 if (info->restart_preview) {
918                         /* restart preview */
919                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
920                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
921
922                         ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
923
924                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
925                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
926                         if (ret != MM_ERROR_NONE) {
927                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
928                         }
929
930                         /* reset restart_preview for inset window layout */
931                         info->restart_preview = FALSE;
932
933                         if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
934                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
935                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
936                         }
937
938                         ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
939                         if (ret != MM_ERROR_NONE) {
940                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
941                         }
942                 }
943
944                 /* remove target file */
945                 if (info->filename) {
946                         _mmcam_dbg_log("file delete(%s)", info->filename);
947                         unlink(info->filename);
948                 }
949
950                 sc->isMaxsizePausing = FALSE;
951                 sc->isMaxtimePausing = FALSE;
952
953                 sc->display_interval = 0;
954                 sc->previous_slot_time = 0;
955                 info->video_frame_count = 0;
956                 info->audio_frame_count = 0;
957                 info->filesize = 0;
958                 break;
959         }
960         case _MMCamcorder_CMD_COMMIT:
961         {
962                 int count = 0;
963
964                 if (info->b_commiting) {
965                         _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
966                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
967                 } else {
968                         _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
969                         info->b_commiting = TRUE;
970                         sc->bget_eos = FALSE;
971                 }
972
973                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
974                         if (sc->audio_disable) {
975                                 /* check only video frame */
976                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
977                                         break;
978                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
979                                         _mmcam_dbg_err("Commit fail, frame count is %" G_GUINT64_FORMAT "",
980                                                        info->video_frame_count);
981                                         info->b_commiting = FALSE;
982                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
983                                 } else {
984                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %" G_GUINT64_FORMAT "",
985                                                         count, info->video_frame_count);
986                                 }
987
988                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
989                         } else {
990                                 /* check both of video and audio frame */
991                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
992                                         break;
993                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
994                                         _mmcam_dbg_err("Commit fail, VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
995                                                        info->video_frame_count, info->audio_frame_count);
996
997                                         info->b_commiting = FALSE;
998                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
999                                 } else {
1000                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
1001                                                         count, info->video_frame_count, info->audio_frame_count);
1002                                 }
1003
1004                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1005                         }
1006                 }
1007
1008                 /* block push buffer */
1009                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1010                 _mmcam_dbg_log("block push buffer to appsrc");
1011
1012                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1013                         ret = gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos());
1014                         _mmcam_dbg_warn("send eos to appsrc result : %d", ret);
1015                 }
1016
1017                 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1018                         ret = gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
1019                         _mmcam_dbg_warn("send eos to audiosrc result : %d", ret);
1020                 }
1021
1022                 /* sc */
1023                 sc->display_interval = 0;
1024                 sc->previous_slot_time = 0;
1025
1026                 /* init system memory size */
1027                 hcamcorder->system_memory = 0;
1028
1029                 /* Wait EOS */
1030                 _mmcam_dbg_log("Start to wait EOS");
1031                 ret =_mmcamcorder_get_eos_message(handle);
1032                 if (ret != MM_ERROR_NONE) {
1033                         info->b_commiting = FALSE;
1034                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1035                 }
1036         }
1037                 break;
1038         default:
1039                 ret =  MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1040                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1041         }
1042
1043         return MM_ERROR_NONE;
1044
1045 _ERR_CAMCORDER_VIDEO_COMMAND:
1046         if (command == _MMCamcorder_CMD_RECORD) {
1047                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1048         }
1049
1050         return ret;
1051 }
1052
1053
1054 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1055 {
1056         int ret = MM_ERROR_NONE;
1057         int enabletag = 0;
1058         guint64 file_size = 0;
1059
1060         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1061         _MMCamcorderSubContext *sc = NULL;
1062         _MMCamcorderVideoInfo *info = NULL;
1063         _MMCamcorderMsgItem msg;
1064         MMCamRecordingReport *report = NULL;
1065
1066         mmf_return_val_if_fail(hcamcorder, FALSE);
1067
1068         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1069         mmf_return_val_if_fail(sc, FALSE);
1070         mmf_return_val_if_fail(sc->info_video, FALSE);
1071
1072         info = sc->info_video;
1073
1074         _mmcam_dbg_err("");
1075
1076         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1077                 /* Play record stop sound */
1078                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND, FALSE);
1079         } else {
1080                 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1081
1082 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
1083                 _mmcamcorder_sound_init(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND);
1084 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
1085                 _mmcamcorder_sound_init(handle);
1086 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
1087
1088                 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1089
1090                 _mmcamcorder_sound_finalize(handle);
1091         }
1092
1093         /* remove blocking part */
1094         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1095
1096         mm_camcorder_get_attributes(handle, NULL,
1097                                     MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1098                                     NULL);
1099
1100         ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1101         if (ret != MM_ERROR_NONE) {
1102                 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1103         }
1104
1105         /* set recording hint */
1106         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1107
1108         /* stop video stream */
1109         if (info->record_dual_stream) {
1110                 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1111                 if (control) {
1112                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1113
1114                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1115                         gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1116
1117                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1118                 } else {
1119                         _mmcam_dbg_err("failed to get camera control");
1120                 }
1121         }
1122
1123         if (enabletag && !(sc->ferror_send)) {
1124                 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1125                 if (ret) {
1126                         _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1127                 } else {
1128                         _mmcam_dbg_err("Writing location information FAILED !!");
1129                 }
1130         }
1131
1132         /* Check file size */
1133         if (info->max_size > 0) {
1134                 _mmcamcorder_get_file_size(info->filename, &file_size);
1135                 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1136                                info->max_size, file_size);
1137
1138                 if (file_size > info->max_size) {
1139                         _MMCamcorderMsgItem message;
1140                         _mmcam_dbg_err("File size is greater than max size !!");
1141                         message.id = MM_MESSAGE_CAMCORDER_ERROR;
1142                         message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1143                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1144                 }
1145         }
1146
1147         if (info->restart_preview) {
1148                 /* block queue */
1149                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1150                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1151
1152                 _mmcam_dbg_log("Set state of pipeline as READY");
1153                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1154
1155                 /* unblock queue */
1156                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1157                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1158                 if (ret != MM_ERROR_NONE) {
1159                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1160                         msg.param.code = ret;
1161                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1162                         _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1163                 }
1164
1165                 /* reset restart_preview for inset window layout */
1166                 info->restart_preview = FALSE;
1167
1168                 /* recover preview size */
1169                 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1170
1171                 ret =_mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1172                 /* Do not return when error is occurred.
1173                    Recording file was created successfully, but starting pipeline failed */
1174                 if (ret != MM_ERROR_NONE) {
1175                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1176                         msg.param.code = ret;
1177                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1178                         _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1179                 }
1180         } else {
1181                 _mmcam_dbg_log("No need to restart preview");
1182         }
1183
1184         /* Send recording report to application */
1185         msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1186         report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport));
1187         if (!report) {
1188                 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1189         } else {
1190                 report->recording_filename = strdup(info->filename);
1191                 msg.param.data= report;
1192                 msg.param.code = 1;
1193                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1194         }
1195
1196         /* Finishing */
1197         sc->pipeline_time = 0;
1198         sc->pause_time = 0;
1199         sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1200         sc->isMaxtimePausing = FALSE;
1201         hcamcorder->error_occurs = FALSE;
1202
1203         info->video_frame_count = 0;
1204         info->audio_frame_count = 0;
1205         info->filesize = 0;
1206         info->b_commiting = FALSE;
1207
1208         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1209                 /* check recording stop sound */
1210                 _mmcamcorder_sound_solo_play_wait(handle);
1211         }
1212
1213         _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1214
1215         return TRUE;
1216 }
1217
1218
1219 /**
1220  * This function is record video data probing function.
1221  * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1222  * this function will be called when data stream pass through the pad.
1223  *
1224  * @param[in]   pad             probing pad which calls this function.
1225  * @param[in]   buffer          buffer which contains stream data.
1226  * @param[in]   u_data          user data.
1227  * @return      This function returns true on success, or false value with error
1228  * @remarks
1229  * @see
1230  */
1231 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data){
1232         GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1233         switch (GST_EVENT_TYPE(event)) {
1234         case GST_EVENT_UNKNOWN:
1235         /* upstream events */
1236         case GST_EVENT_QOS:
1237         case GST_EVENT_SEEK:
1238         case GST_EVENT_NAVIGATION:
1239         case GST_EVENT_LATENCY:
1240         /* downstream serialized events */
1241         case GST_EVENT_SEGMENT :
1242         case GST_EVENT_TAG:
1243         case GST_EVENT_BUFFERSIZE:
1244                 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1245                 break;
1246         case GST_EVENT_EOS:
1247                 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1248                 break;
1249         /* bidirectional events */
1250         case GST_EVENT_FLUSH_START:
1251         case GST_EVENT_FLUSH_STOP:
1252                 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1253                 break;
1254         default:
1255                 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1256                 break;
1257         }
1258
1259         return GST_PAD_PROBE_OK;
1260 }
1261
1262
1263 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1264 {
1265         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1266         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1267         GstMapInfo mapinfo;
1268         _MMCamcorderSubContext *sc = NULL;
1269         _MMCamcorderVideoInfo *videoinfo = NULL;
1270         _MMCamcorderMsgItem msg;
1271         guint64 buffer_size = 0;
1272         guint64 trailer_size = 0;
1273
1274         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1275         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1276         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1277
1278         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1279         videoinfo = sc->info_video;
1280
1281         /* get buffer size */
1282         if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1283                 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1284                 return GST_PAD_PROBE_OK;
1285         }
1286
1287         buffer_size = mapinfo.size;
1288         gst_buffer_unmap(buffer, &mapinfo);
1289
1290         /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1291
1292         pthread_mutex_lock(&(videoinfo->size_check_lock));
1293
1294         if (videoinfo->audio_frame_count == 0) {
1295                 videoinfo->filesize += buffer_size;
1296                 videoinfo->audio_frame_count++;
1297                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1298                 return GST_PAD_PROBE_OK;
1299         }
1300
1301         if (sc->ferror_send || sc->isMaxsizePausing) {
1302                 _mmcam_dbg_warn("Recording is paused, drop frames");
1303                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1304                 return GST_PAD_PROBE_DROP;
1305         }
1306
1307         /* get trailer size */
1308         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1309                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1310         } else {
1311                 trailer_size = 0;
1312         }
1313
1314         /* check max size of recorded file */
1315         if (videoinfo->max_size > 0 &&
1316             videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1317                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1318                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1319                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1320                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1321                                 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1322                                 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1323
1324                 if (!sc->isMaxsizePausing) {
1325                         sc->isMaxsizePausing = TRUE;
1326                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1327                         if (pipeline_state == GST_STATE_PLAYING) {
1328                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1329                         }
1330
1331                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1332                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1333                 }
1334
1335                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1336
1337                 return FALSE;
1338         }
1339
1340         videoinfo->filesize += buffer_size;
1341         videoinfo->audio_frame_count++;
1342
1343         pthread_mutex_unlock(&(videoinfo->size_check_lock));
1344
1345         return GST_PAD_PROBE_OK;
1346 }
1347
1348
1349 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1350 {
1351         gint ret = 0;
1352         guint vq_size = 0;
1353         guint aq_size = 0;
1354         guint64 free_space = 0;
1355         guint64 buffer_size = 0;
1356         guint64 trailer_size = 0;
1357         guint64 queued_buffer = 0;
1358         char *filename = NULL;
1359         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1360         GstMapInfo mapinfo;
1361
1362         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1363         _MMCamcorderMsgItem msg;
1364         _MMCamcorderSubContext *sc = NULL;
1365         _MMCamcorderVideoInfo *videoinfo = NULL;
1366
1367         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1368         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1369
1370         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1371         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1372         videoinfo = sc->info_video;
1373
1374         /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1375         if (sc->ferror_send) {
1376                 _mmcam_dbg_warn("file write error, drop frames");
1377                 return GST_PAD_PROBE_DROP;
1378         }
1379
1380         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1381         buffer_size = mapinfo.size;
1382         gst_buffer_unmap(buffer, &mapinfo);
1383
1384         videoinfo->video_frame_count++;
1385         if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1386                 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1387                                 info->video_frame_count); */
1388                 pthread_mutex_lock(&(videoinfo->size_check_lock));
1389                 videoinfo->filesize += buffer_size;
1390                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1391                 return GST_PAD_PROBE_OK;
1392         }
1393
1394         /* get trailer size */
1395         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1396                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1397         } else {
1398                 trailer_size = 0;
1399         }
1400
1401         filename = videoinfo->filename;
1402         ret = _mmcamcorder_get_freespace(filename, &free_space);
1403
1404         if(_mmcamcorder_check_file_path(filename) && hcamcorder->system_memory) {
1405                 free_space = free_space - hcamcorder->system_memory;
1406         }
1407
1408         /*_mmcam_dbg_log("check free space for recording");*/
1409
1410         switch (ret) {
1411         case -2: /* file not exist */
1412         case -1: /* failed to get free space */
1413                 _mmcam_dbg_err("Error occured. [%d]", ret);
1414                 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1415                         sc->ferror_send = TRUE;
1416                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1417                         if (ret == -2) {
1418                                 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1419                         } else {
1420                                 msg.param.code = MM_ERROR_FILE_READ;
1421                         }
1422                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1423                 } else {
1424                         sc->ferror_count++;
1425                 }
1426
1427                 return GST_PAD_PROBE_DROP; /* skip this buffer */
1428                 break;
1429         default: /* succeeded to get free space */
1430                 /* check free space for recording */
1431                 /* get queued buffer size */
1432                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1433                         MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1434                 }
1435                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1436                         MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1437                 }
1438
1439                 queued_buffer = aq_size + vq_size;
1440
1441                 /* check free space */
1442                 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1443                         _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1444                         _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1445                                         " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1446                                         free_space, trailer_size, buffer_size, queued_buffer);
1447
1448                         if (!sc->isMaxsizePausing) {
1449                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1450                                 sc->isMaxsizePausing = TRUE;
1451
1452                                 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1453                                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1454                         }
1455
1456                         return GST_PAD_PROBE_DROP;
1457                 }
1458                 break;
1459         }
1460
1461         pthread_mutex_lock(&(videoinfo->size_check_lock));
1462
1463         /* check max size of recorded file */
1464         if (videoinfo->max_size > 0 &&
1465             videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1466                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1467                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1468                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1469                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1470                                 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1471                                                 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1472
1473                 if (!sc->isMaxsizePausing) {
1474                         sc->isMaxsizePausing = TRUE;
1475                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1476                         if (pipeline_state == GST_STATE_PLAYING) {
1477                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1478                         }
1479
1480                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1481                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1482                 }
1483
1484                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1485
1486                 return GST_PAD_PROBE_DROP;
1487         }
1488
1489         videoinfo->filesize += (guint64)buffer_size;
1490
1491         /*
1492         _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1493         */
1494
1495         pthread_mutex_unlock(&(videoinfo->size_check_lock));
1496
1497         return GST_PAD_PROBE_OK;
1498 }
1499
1500
1501 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1502 {
1503         guint64 trailer_size = 0;
1504         guint64 rec_pipe_time = 0;
1505         unsigned int remained_time = 0;
1506
1507         GstClockTime b_time;
1508
1509         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1510         _MMCamcorderMsgItem msg;
1511         _MMCamcorderSubContext *sc = NULL;
1512         _MMCamcorderVideoInfo *videoinfo = NULL;
1513
1514         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1515
1516         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1517         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1518
1519         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1520         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1521         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1522
1523         videoinfo = sc->info_video;
1524
1525         b_time = GST_BUFFER_PTS(buffer);
1526
1527         rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1528
1529         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1530                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1531         } else {
1532                 trailer_size = 0;
1533         }
1534
1535         /* check max time */
1536         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1537                 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1538                                 rec_pipe_time, videoinfo->max_time);
1539
1540                 if (!sc->isMaxtimePausing) {
1541                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1542
1543                         sc->isMaxtimePausing = TRUE;
1544
1545                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1546                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1547                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1548                         msg.param.recording_status.remained_time = 0;
1549                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1550
1551                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1552                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1553                 }
1554
1555                 return GST_PAD_PROBE_DROP;
1556         }
1557
1558         /* calculate remained time can be recorded */
1559         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1560                 remained_time = videoinfo->max_time - rec_pipe_time;
1561         } else if (videoinfo->max_size > 0) {
1562                 long double max_size = (long double)videoinfo->max_size;
1563                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1564
1565                 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1566         }
1567
1568         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1569         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1570         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1571         msg.param.recording_status.remained_time = remained_time;
1572         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1573
1574         /*
1575         _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1576                        GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1577         */
1578
1579         if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1580                 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1581
1582                 /*
1583                 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1584                                record_motion_rate, videoinfo->record_drop_count);
1585                 */
1586
1587                 /* drop some frame if fast motion */
1588                 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1589                         if (record_motion_rate != (videoinfo->record_drop_count++)) {
1590                                 /*
1591                                 _mmcam_dbg_warn("drop frame");
1592                                 */
1593                                 return GST_PAD_PROBE_DROP;
1594                         }
1595
1596                         videoinfo->record_drop_count = 1;
1597                         /*
1598                         _mmcam_dbg_warn("pass frame");
1599                         */
1600                 }
1601
1602                 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1603         }
1604
1605         return GST_PAD_PROBE_OK;
1606 }
1607
1608
1609 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1610 {
1611         _MMCamcorderMsgItem msg;
1612         guint64 trailer_size = 0;
1613         guint64 rec_pipe_time = 0;
1614         _MMCamcorderSubContext *sc = NULL;
1615         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1616         _MMCamcorderVideoInfo *videoinfo = NULL;
1617         unsigned int remained_time = 0;
1618         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1619
1620         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1621         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1622         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1623
1624         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1625         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1626         mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1627
1628         videoinfo = sc->info_video;
1629
1630         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1631                 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1632                 return GST_PAD_PROBE_OK;
1633         }
1634
1635         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1636
1637         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1638                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1639         } else {
1640                 trailer_size = 0;
1641         }
1642
1643         /* calculate remained time can be recorded */
1644         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1645                 remained_time = videoinfo->max_time - rec_pipe_time;
1646         } else if (videoinfo->max_size > 0) {
1647                 long double max_size = (long double)videoinfo->max_size;
1648                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1649
1650                 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1651         }
1652
1653         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1654                 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1655                                 rec_pipe_time, videoinfo->max_time);
1656
1657                 if (!sc->isMaxtimePausing) {
1658                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1659
1660                         sc->isMaxtimePausing = TRUE;
1661
1662                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1663                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1664                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1665                         msg.param.recording_status.remained_time = 0;
1666                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1667
1668                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1669                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1670                 }
1671
1672                 return GST_PAD_PROBE_DROP;
1673         }
1674
1675         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1676         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1677         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1678         msg.param.recording_status.remained_time = remained_time;
1679         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1680
1681         /*
1682         _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1683                        GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1684         */
1685
1686         return GST_PAD_PROBE_OK;
1687 }
1688
1689
1690 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1691 {
1692         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1693         double volume = 0.0;
1694         int format = 0;
1695         int channel = 0;
1696         int err = MM_ERROR_UNKNOWN;
1697         char *err_name = NULL;
1698         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1699         GstMapInfo mapinfo;
1700
1701         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1702         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1703
1704         /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1705         err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1706                                           MMCAM_AUDIO_VOLUME, &volume,
1707                                           MMCAM_AUDIO_FORMAT, &format,
1708                                           MMCAM_AUDIO_CHANNEL, &channel,
1709                                           NULL);
1710         if (err != MM_ERROR_NONE) {
1711                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1712                 SAFE_FREE(err_name);
1713                 return err;
1714         }
1715
1716         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1717
1718         gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1719
1720         /* Set audio stream NULL */
1721         if (volume == 0.0) {
1722                 memset(mapinfo.data, 0, mapinfo.size);
1723         }
1724
1725         /* CALL audio stream callback */
1726         if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1727                 MMCamcorderAudioStreamDataType stream;
1728
1729                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1730                         _mmcam_dbg_warn("Not ready for stream callback");
1731                         gst_buffer_unmap(buffer, &mapinfo);
1732                         return GST_PAD_PROBE_OK;
1733                 }
1734
1735                 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1736                                GST_BUFFER_DATA(buffer), width, height, format);*/
1737
1738                 stream.data = (void *)mapinfo.data;
1739                 stream.format = format;
1740                 stream.channel = channel;
1741                 stream.length = mapinfo.size;
1742                 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1743
1744                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1745
1746                 if (hcamcorder->astream_cb) {
1747                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1748                 }
1749
1750                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1751         }
1752
1753         gst_buffer_unmap(buffer, &mapinfo);
1754         return GST_PAD_PROBE_OK;
1755 }
1756
1757
1758 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1759 {
1760         gboolean bret = FALSE;
1761
1762         switch (fileformat) {
1763         case MM_FILE_FORMAT_3GP:
1764         case MM_FILE_FORMAT_MP4:
1765                 bret = __mmcamcorder_add_metadata_mp4(handle);
1766                 break;
1767         default:
1768                 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1769                 break;
1770         }
1771
1772         return bret;
1773 }
1774
1775
1776 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1777 {
1778         FILE *f = NULL;
1779         guchar buf[4];
1780         guint64 udta_size = 0;
1781         gint64 current_pos = 0;
1782         gint64 moov_pos = 0;
1783         gint64 udta_pos = 0;
1784         gdouble longitude = 0;
1785         gdouble latitude = 0;
1786         gdouble altitude = 0;
1787         int err = 0;
1788         int orientation = 0;
1789         int gps_enable = 0;
1790         char *err_name = NULL;
1791         char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1792         _MMCamcorderLocationInfo location_info = {0,0,0};
1793         _MMCamcorderLocationInfo geo_info = {0,0,0};
1794
1795         _MMCamcorderVideoInfo *info = NULL;
1796         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1797         _MMCamcorderSubContext *sc = NULL;
1798
1799         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1800         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1801
1802         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1803         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1804
1805         _mmcam_dbg_log("");
1806
1807         info = sc->info_video;
1808
1809         f = fopen64(info->filename, "rb+");
1810         if (f == NULL) {
1811                 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1812                 _mmcam_dbg_err("file open failed [%s]", err_msg);
1813                 return FALSE;
1814         }
1815
1816         mm_camcorder_get_attributes(handle, &err_name,
1817                                     MMCAM_TAG_LATITUDE, &latitude,
1818                                     MMCAM_TAG_LONGITUDE, &longitude,
1819                                     MMCAM_TAG_ALTITUDE, &altitude,
1820                                     MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1821                                     MMCAM_TAG_GPS_ENABLE, &gps_enable,
1822                                     NULL);
1823         if (err_name) {
1824                 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1825                 SAFE_FREE (err_name);
1826         }
1827
1828         location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1829         location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1830         location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1831         geo_info.longitude = longitude *10000;
1832         geo_info.latitude = latitude *10000;
1833         geo_info.altitude = altitude *10000;
1834         /* find udta container.
1835            if, there are udta container, write loci box after that
1836            else, make udta container and write loci box. */
1837         if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) {
1838                 size_t nread = 0;
1839
1840                 _mmcam_dbg_log("find udta container");
1841
1842                 /* read size */
1843                 if (fseek(f, -8L, SEEK_CUR) != 0) {
1844                         goto fail;
1845                 }
1846
1847                 udta_pos = ftello(f);
1848                 if (udta_pos < 0) {
1849                         goto ftell_fail;
1850                 }
1851
1852                 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1853
1854                 _mmcam_dbg_log("recorded file fread %d", nread);
1855
1856                 udta_size = _mmcamcorder_get_container_size(buf);
1857
1858                 /* goto end of udta and write 'loci' box */
1859                 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1860                         goto fail;
1861                 }
1862
1863                 if (gps_enable) {
1864                         if (!_mmcamcorder_write_loci(f, location_info)) {
1865                                 _mmcam_dbg_err("failed to write loci");
1866                                 goto fail;
1867                         }
1868
1869                         if (!_mmcamcorder_write_geodata(f, geo_info)) {
1870                                 _mmcam_dbg_err("failed to write geodata");
1871                                 goto fail;
1872                         }
1873                 }
1874
1875                 current_pos = ftello(f);
1876                 if (current_pos < 0) {
1877                         goto ftell_fail;
1878                 }
1879
1880                 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1881                         goto fail;
1882                 }
1883         } else {
1884                 _mmcam_dbg_log("No udta container");
1885                 if (fseek(f, 0, SEEK_END) != 0) {
1886                         goto fail;
1887                 }
1888
1889                 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1890                         _mmcam_dbg_err("failed to write udta");
1891                         goto fail;
1892                 }
1893         }
1894
1895         /* find moov container.
1896            update moov container size. */
1897         if((current_pos = ftello(f))<0)
1898                 goto ftell_fail;
1899
1900         if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) {
1901                 gint64 internal_pos = ftello(f);
1902
1903                 _mmcam_dbg_log("found moov container");
1904                 if (fseek(f, -8L, SEEK_CUR) !=0) {
1905                         goto fail;
1906                 }
1907
1908                 moov_pos = ftello(f);
1909                 if (moov_pos < 0) {
1910                         goto ftell_fail;
1911                 }
1912
1913                 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1914                         goto fail;
1915                 }
1916
1917                 /* add orientation info */
1918                 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1919                         _mmcam_dbg_err("fseek failed : errno %d", errno);
1920                         goto fail;
1921                 }
1922
1923                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','r','a','k'), FALSE)) {
1924                         _mmcam_dbg_err("failed to find [trak] tag");
1925                         goto fail;
1926                 }
1927
1928                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','k','h','d'), FALSE)) {
1929                         _mmcam_dbg_err("failed to find [tkhd] tag");
1930                         goto fail;
1931                 }
1932
1933                 _mmcam_dbg_log("found [tkhd] tag");
1934
1935                 /* seek to start position of composition matrix */
1936                 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
1937
1938                 /* update composition matrix for orientation */
1939                 _mmcamcorder_update_composition_matrix(f, orientation);
1940         } else {
1941                 _mmcam_dbg_err("No 'moov' container");
1942                 goto fail;
1943         }
1944
1945         fclose(f);
1946         return TRUE;
1947
1948 fail:
1949         fclose(f);
1950         return FALSE;
1951
1952 ftell_fail:
1953         _mmcam_dbg_err("ftell() returns negative value.");
1954         fclose(f);
1955         return FALSE;
1956 }
1957
1958
1959 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
1960 {
1961         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1962         _MMCamcorderSubContext *sc = NULL;
1963
1964         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1965
1966         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1967         mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1968
1969         /* check video source element */
1970         if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
1971                 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
1972                 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
1973                                            _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
1974                                            G_CALLBACK(__mmcamcorder_video_stream_cb),
1975                                            hcamcorder);
1976                 return MM_ERROR_NONE;
1977         } else {
1978                 _mmcam_dbg_err("videosrc element is not created yet");
1979                 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
1980         }
1981 }
1982
1983
1984 int _mmcamcorder_video_prepare_record(MMHandleType handle)
1985 {
1986         int ret = MM_ERROR_NONE;
1987
1988         _MMCamcorderVideoInfo *info = NULL;
1989         _MMCamcorderSubContext *sc = NULL;
1990         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1991
1992         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1993
1994         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1995         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1996         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1997
1998         info = sc->info_video;
1999
2000         _mmcam_dbg_warn("start");
2001
2002         /* create encoding pipeline */
2003         ret =_mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2004         if (ret != MM_ERROR_NONE) {
2005                 goto _ERR_PREPARE_RECORD;
2006         }
2007
2008         if (info->filename == NULL) {
2009                 char *temp_filename = NULL;
2010                 int size = 0;
2011
2012                 mm_camcorder_get_attributes(handle, NULL,
2013                                             MMCAM_TARGET_FILENAME, &temp_filename, &size,
2014                                             NULL);
2015                 if (temp_filename) {
2016                         info->filename = strdup(temp_filename);
2017                 }
2018
2019                 if (!info->filename) {
2020                         _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2021                         goto _ERR_PREPARE_RECORD;
2022                 }
2023         }
2024
2025         _mmcam_dbg_log("Record file name [%s]", info->filename);
2026
2027         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2028         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2029
2030         /* Adjust display FPS */
2031         sc->display_interval = 0;
2032         sc->previous_slot_time = 0;
2033
2034         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2035         if (ret != MM_ERROR_NONE) {
2036                 goto _ERR_PREPARE_RECORD;
2037         }
2038
2039         _mmcam_dbg_warn("done");
2040
2041         return ret;
2042
2043 _ERR_PREPARE_RECORD:
2044         /* Remove recorder pipeline and recording file which size maybe zero */
2045         _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2046         if (info && info->filename) {
2047                 _mmcam_dbg_log("file delete(%s)", info->filename);
2048                 unlink(info->filename);
2049         }
2050
2051         return ret;
2052 }