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