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