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