Adjust default value for flip setting
[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                         int file_system_type = 0;
508
509                         /* Recording */
510                         _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
511
512                         /* init record_dual_stream */
513                         info->record_dual_stream = FALSE;
514
515                         ret = mm_camcorder_get_attributes(handle, &err_name,
516                                                           MMCAM_CAMERA_FPS, &fps,
517                                                           MMCAM_CAMERA_WIDTH, &(info->preview_width),
518                                                           MMCAM_CAMERA_HEIGHT, &(info->preview_height),
519                                                           MMCAM_VIDEO_WIDTH, &(info->video_width),
520                                                           MMCAM_VIDEO_HEIGHT, &(info->video_height),
521                                                           MMCAM_FILE_FORMAT, &fileformat,
522                                                           MMCAM_TARGET_FILENAME, &temp_filename, &size,
523                                                           MMCAM_TARGET_MAX_SIZE, &imax_size,
524                                                           MMCAM_TARGET_TIME_LIMIT, &imax_time,
525                                                           MMCAM_FILE_FORMAT, &(info->fileformat),
526                                                           MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
527                                                           NULL);
528                         if (ret != MM_ERROR_NONE) {
529                                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
530                                 SAFE_FREE (err_name);
531                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
532                         }
533
534                         if (temp_filename == NULL) {
535                                 _mmcam_dbg_err("filename is not set");
536                                 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
537                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
538                         }
539
540                         /* set max size */
541                         if (imax_size <= 0) {
542                                 info->max_size = 0; /* do not check */
543                         } else {
544                                 info->max_size = ((guint64)imax_size) << 10; /* to byte */
545                         }
546
547                         /* set max time */
548                         if (imax_time <= 0) {
549                                 info->max_time = 0; /* do not check */
550                         } else {
551                                 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
552                         }
553
554                         dir_name = g_path_get_dirname(temp_filename);
555                         if (dir_name) {
556                                 ret_free_space = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
557
558                                 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
559
560                                 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
561                                         /* MSDOS_SUPER_MAGIC : 0x4d44 */
562                                         if (file_system_type == MSDOS_SUPER_MAGIC &&
563                                             (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
564                                                 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
565                                                                 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
566                                                 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
567                                         } else {
568                                                 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
569                                                                 file_system_type, info->max_size);
570                                         }
571                                 } else {
572                                         _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
573                                 }
574
575                                 g_free(dir_name);
576                                 dir_name = NULL;
577                         } else {
578                                 _mmcam_dbg_err("failed to get directory name");
579                                 ret_free_space = -1;
580                         }
581
582                         if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
583                                 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
584                                                ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
585                                 return MM_ERROR_OUT_OF_STORAGE;
586                         }
587
588                         pthread_mutex_lock(&(hcamcorder->task_thread_lock));
589                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
590                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
591                                 /* Play record start sound */
592                                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_START_SND, FALSE);
593                         }
594                         pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
595
596                         _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
597
598                         if (info->video_width == 0 || info->video_height == 0) {
599                                 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
600                                                 info->video_width, info->video_height, info->preview_width, info->preview_height);
601                                 info->video_width = info->preview_width;
602                                 info->video_height = info->preview_height;
603                         }
604
605                         if (info->support_dual_stream) {
606                                 _mmcam_dbg_warn("DUAL STREAM MODE");
607
608                                 info->record_dual_stream = TRUE;
609
610                                 /* No need to restart preview */
611                                 info->restart_preview = FALSE;
612
613                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
614                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
615                         } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
616                                    info->preview_width == info->video_width &&
617                                    info->preview_height == info->video_height) {
618                                 _mmcam_dbg_log("H264 preview mode and same resolution");
619
620                                 /* No need to restart preview */
621                                 info->restart_preview = FALSE;
622                         } else {
623                                 /* always need to restart preview  */
624                                 info->restart_preview = TRUE;
625                         }
626
627                         /* set recording hint */
628                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
629
630                         if (info->restart_preview) {
631                                 /* stop preview and set new size */
632                                 _mmcam_dbg_log("restart preview");
633
634                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
635                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
636
637                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
638
639                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
640                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
641
642                                 if (ret != MM_ERROR_NONE) {
643                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
644                                 }
645
646                                 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
647                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
648                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
649                                 }
650
651                                 /* Start preview again with new setting */
652                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
653                                 if (ret != MM_ERROR_NONE) {
654                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
655                                 }
656
657                                 if (motion_rate < 1.0) {
658                                         _mmcam_dbg_warn("wait for stabilization of frame");
659                                         usleep(300000);
660                                 }
661                         } else {
662                                 _mmcam_dbg_log("no need to restart preview");
663                         }
664
665                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
666                                                         CONFIGURE_CATEGORY_MAIN_RECORD,
667                                                         "DropVideoFrame",
668                                                         &(sc->drop_vframe));
669
670                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
671                                                         CONFIGURE_CATEGORY_MAIN_RECORD,
672                                                         "PassFirstVideoFrame",
673                                                         &(sc->pass_first_vframe));
674
675                         _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
676                                        sc->drop_vframe, sc->pass_first_vframe);
677
678                         info->record_drop_count = (guint)motion_rate;
679                         info->record_motion_rate = motion_rate;
680                         if (sc->is_modified_rate) {
681                                 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
682                         } else {
683                                 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
684                         }
685
686                         _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
687                                        fps, info->record_motion_rate, info->record_timestamp_ratio);
688
689                         /* set push buffer flag */
690                         info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
691                         info->base_video_ts = 0;
692
693                         /* connect video stream cb signal */
694                         /*130826 Connect video stream cb for handling fast record frame cb*/
695                         if (info->record_dual_stream) {
696                                 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE) {
697                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
698                                 }
699                         }
700
701                         /* start video stream */
702                         if (info->record_dual_stream) {
703                                 CameraControl =  GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
704                                 if (CameraControl) {
705                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
706
707                                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
708                                         gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
709
710                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
711                                 } else {
712                                         _mmcam_dbg_err("could not get camera control");
713                                 }
714                         }
715
716                         /* check pre-created encode pipeline */
717                         pthread_mutex_lock(&(hcamcorder->task_thread_lock));
718                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
719                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
720                                 /* create encoding pipeline */
721                                 ret =_mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
722                                 if (ret != MM_ERROR_NONE) {
723                                         pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
724                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
725                                 }
726                         }
727                         pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
728
729                         /* check recording start sound */
730                         _mmcamcorder_sound_solo_play_wait(handle);
731
732                         /**< To fix video recording hanging
733                                 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
734                                 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
735                                  basetime wouldn't change if you set (GstClockTime)0.
736                                 3. Move set start time position below PAUSED of pipeline.
737                         */
738                         //gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
739                         //gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
740
741                         info->video_frame_count = 0;
742                         info->is_firstframe = TRUE;
743                         info->audio_frame_count = 0;
744                         info->filesize = 0;
745                         sc->ferror_send = FALSE;
746                         sc->ferror_count = 0;
747                         hcamcorder->error_occurs = FALSE;
748                         sc->bget_eos = FALSE;
749
750                         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
751                         if (ret != MM_ERROR_NONE) {
752                                 /* stop video stream */
753                                 if (info->record_dual_stream) {
754                                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
755                                         if (CameraControl) {
756                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
757
758                                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
759                                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
760
761                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
762                                         } else {
763                                                 _mmcam_dbg_err("failed to get camera control");
764                                         }
765                                 }
766
767                                 /* Remove recorder pipeline and recording file which size maybe zero */
768                                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
769                                 if (info->filename) {
770                                         _mmcam_dbg_log("file delete(%s)", info->filename);
771                                         unlink(info->filename);
772                                 }
773                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
774                         }
775
776                         /*set the camera control to create the GOP so that video record will get a new key frame*/
777                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
778                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
779                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
780                                 controls = gst_camera_control_list_channels(CameraControl);
781                                 if (controls != NULL) {
782                                         for (item = controls ; item && item->data ; item = item->next) {
783                                                 CameraControlChannel = item->data;
784                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
785                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
786                                                         //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
787                                                         break;
788                                                 }
789                                         }
790
791                                         if (item == NULL) {
792                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
793                                         }
794                                 }
795                         } else {
796                                 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
797                                                 sc->info_image->preview_format);
798                         }
799                 } else {
800                         /* Resume case */
801
802                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
803                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
804                                 /* generate and I-frame on resuming */
805                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
806                                 controls = gst_camera_control_list_channels(CameraControl);
807                                 if (controls != NULL) {
808                                         for (item = controls ; item && item->data ; item = item->next) {
809                                                 CameraControlChannel = item->data;
810                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
811                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
812                                                         //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
813                                                         break;
814                                                 }
815                                         }
816
817                                         if (item == NULL) {
818                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
819                                         }
820                                 }
821                         }
822
823                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
824
825                         _mmcam_dbg_log("Object property settings done");
826                 }
827         }
828                 break;
829         case _MMCamcorder_CMD_PAUSE:
830         {
831                 int count = 0;
832
833                 if (info->b_commiting) {
834                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
835                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
836                 }
837
838                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
839                         if (sc->audio_disable) {
840                                 /* check only video frame */
841                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
842                                         break;
843                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
844                                         _mmcam_dbg_err("Pause fail, frame count %" G_GUINT64_FORMAT "",
845                                                        info->video_frame_count);
846                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
847                                 } else {
848                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %" G_GUINT64_FORMAT "",
849                                                         count, info->video_frame_count);
850                                 }
851
852                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
853                         } else {
854                                 /* check both of video and audio frame */
855                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
856                                         break;
857                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
858                                         _mmcam_dbg_err("Pause fail, frame count VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
859                                                        info->video_frame_count, info->audio_frame_count);
860                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
861                                 } else {
862                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
863                                                         count, info->video_frame_count, info->audio_frame_count);
864                                 }
865
866                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
867                         }
868                 }
869
870                 /* block encodebin */
871                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
872                 break;
873         }
874         case _MMCamcorder_CMD_CANCEL:
875         {
876                 if (info->b_commiting) {
877                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
878                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
879                 }
880
881                 /* block push buffer */
882                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
883
884                 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
885                 if (ret != MM_ERROR_NONE) {
886                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
887                 }
888
889                 /* set recording hint */
890                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
891
892                 /* stop video stream */
893                 if (info->record_dual_stream) {
894                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
895                         if (CameraControl) {
896                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
897
898                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
899                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
900
901                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
902                         } else {
903                                 _mmcam_dbg_err("failed to get camera control");
904                         }
905                 }
906
907                 if (info->restart_preview) {
908                         /* restart preview */
909                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
910                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
911
912                         ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
913
914                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
915                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
916                         if (ret != MM_ERROR_NONE) {
917                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
918                         }
919
920                         /* reset restart_preview for inset window layout */
921                         info->restart_preview = FALSE;
922
923                         if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
924                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
925                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
926                         }
927
928                         ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
929                         if (ret != MM_ERROR_NONE) {
930                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
931                         }
932                 }
933
934                 /* remove target file */
935                 if (info->filename) {
936                         _mmcam_dbg_log("file delete(%s)", info->filename);
937                         unlink(info->filename);
938                 }
939
940                 sc->isMaxsizePausing = FALSE;
941                 sc->isMaxtimePausing = FALSE;
942
943                 sc->display_interval = 0;
944                 sc->previous_slot_time = 0;
945                 info->video_frame_count = 0;
946                 info->audio_frame_count = 0;
947                 info->filesize = 0;
948                 break;
949         }
950         case _MMCamcorder_CMD_COMMIT:
951         {
952                 int count = 0;
953
954                 if (info->b_commiting) {
955                         _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
956                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
957                 } else {
958                         _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
959                         info->b_commiting = TRUE;
960                         sc->bget_eos = FALSE;
961                 }
962
963                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
964                         if (sc->audio_disable) {
965                                 /* check only video frame */
966                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
967                                         break;
968                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
969                                         _mmcam_dbg_err("Commit fail, frame count is %" G_GUINT64_FORMAT "",
970                                                        info->video_frame_count);
971                                         info->b_commiting = FALSE;
972                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
973                                 } else {
974                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %" G_GUINT64_FORMAT "",
975                                                         count, info->video_frame_count);
976                                 }
977
978                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
979                         } else {
980                                 /* check both of video and audio frame */
981                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
982                                         break;
983                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
984                                         _mmcam_dbg_err("Commit fail, VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
985                                                        info->video_frame_count, info->audio_frame_count);
986
987                                         info->b_commiting = FALSE;
988                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
989                                 } else {
990                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
991                                                         count, info->video_frame_count, info->audio_frame_count);
992                                 }
993
994                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
995                         }
996                 }
997
998                 /* block push buffer */
999                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1000                 _mmcam_dbg_log("block push buffer to appsrc");
1001
1002                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1003                         ret = gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos());
1004                         _mmcam_dbg_warn("send eos to appsrc result : %d", ret);
1005                 }
1006
1007                 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1008                         ret = gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
1009                         _mmcam_dbg_warn("send eos to audiosrc result : %d", ret);
1010                 }
1011
1012                 /* sc */
1013                 sc->display_interval = 0;
1014                 sc->previous_slot_time = 0;
1015
1016                 /* Wait EOS */
1017                 _mmcam_dbg_log("Start to wait EOS");
1018                 ret =_mmcamcorder_get_eos_message(handle);
1019                 if (ret != MM_ERROR_NONE) {
1020                         info->b_commiting = FALSE;
1021                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1022                 }
1023         }
1024                 break;
1025         default:
1026                 ret =  MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1027                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1028         }
1029
1030         return MM_ERROR_NONE;
1031
1032 _ERR_CAMCORDER_VIDEO_COMMAND:
1033         if (command == _MMCamcorder_CMD_RECORD) {
1034                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1035         }
1036
1037         return ret;
1038 }
1039
1040
1041 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1042 {
1043         int ret = MM_ERROR_NONE;
1044         int enabletag = 0;
1045         guint64 file_size = 0;
1046
1047         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1048         _MMCamcorderSubContext *sc = NULL;
1049         _MMCamcorderVideoInfo *info = NULL;
1050         _MMCamcorderMsgItem msg;
1051         MMCamRecordingReport *report = NULL;
1052
1053         mmf_return_val_if_fail(hcamcorder, FALSE);
1054
1055         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1056         mmf_return_val_if_fail(sc, FALSE);
1057         mmf_return_val_if_fail(sc->info_video, FALSE);
1058
1059         info = sc->info_video;
1060
1061         _mmcam_dbg_err("");
1062
1063         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1064                 /* Play record stop sound */
1065                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND, FALSE);
1066         } else {
1067                 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1068
1069 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
1070                 _mmcamcorder_sound_init(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND);
1071 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
1072                 _mmcamcorder_sound_init(handle);
1073 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
1074
1075                 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1076
1077                 _mmcamcorder_sound_finalize(handle);
1078         }
1079
1080         /* remove blocking part */
1081         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1082
1083         mm_camcorder_get_attributes(handle, NULL,
1084                                     MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1085                                     NULL);
1086
1087         ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1088         if (ret != MM_ERROR_NONE) {
1089                 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1090         }
1091
1092         /* set recording hint */
1093         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1094
1095         /* stop video stream */
1096         if (info->record_dual_stream) {
1097                 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1098                 if (control) {
1099                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1100
1101                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1102                         gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1103
1104                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1105                 } else {
1106                         _mmcam_dbg_err("failed to get camera control");
1107                 }
1108         }
1109
1110         if (enabletag && !(sc->ferror_send)) {
1111                 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1112                 if (ret) {
1113                         _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1114                 } else {
1115                         _mmcam_dbg_err("Writing location information FAILED !!");
1116                 }
1117         }
1118
1119         /* Check file size */
1120         if (info->max_size > 0) {
1121                 _mmcamcorder_get_file_size(info->filename, &file_size);
1122                 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1123                                info->max_size, file_size);
1124
1125                 if (file_size > info->max_size) {
1126                         _MMCamcorderMsgItem message;
1127                         _mmcam_dbg_err("File size is greater than max size !!");
1128                         message.id = MM_MESSAGE_CAMCORDER_ERROR;
1129                         message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1130                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1131                 }
1132         }
1133
1134         if (info->restart_preview) {
1135                 /* block queue */
1136                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1137                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1138
1139                 _mmcam_dbg_log("Set state of pipeline as READY");
1140                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1141
1142                 /* unblock queue */
1143                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1144                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1145                 if (ret != MM_ERROR_NONE) {
1146                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1147                         msg.param.code = ret;
1148                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1149                         _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1150                 }
1151
1152                 /* reset restart_preview for inset window layout */
1153                 info->restart_preview = FALSE;
1154
1155                 /* recover preview size */
1156                 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1157
1158                 ret =_mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1159                 /* Do not return when error is occurred.
1160                    Recording file was created successfully, but starting pipeline failed */
1161                 if (ret != MM_ERROR_NONE) {
1162                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1163                         msg.param.code = ret;
1164                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1165                         _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1166                 }
1167         } else {
1168                 _mmcam_dbg_log("No need to restart preview");
1169         }
1170
1171         /* Send recording report to application */
1172         msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1173         report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport));
1174         if (!report) {
1175                 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1176         } else {
1177                 report->recording_filename = strdup(info->filename);
1178                 msg.param.data= report;
1179                 msg.param.code = 1;
1180                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1181         }
1182
1183         /* Finishing */
1184         sc->pipeline_time = 0;
1185         sc->pause_time = 0;
1186         sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1187         sc->isMaxtimePausing = FALSE;
1188         hcamcorder->error_occurs = FALSE;
1189
1190         info->video_frame_count = 0;
1191         info->audio_frame_count = 0;
1192         info->filesize = 0;
1193         info->b_commiting = FALSE;
1194
1195         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1196                 /* check recording stop sound */
1197                 _mmcamcorder_sound_solo_play_wait(handle);
1198         }
1199
1200         _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1201
1202         return TRUE;
1203 }
1204
1205
1206 /**
1207  * This function is record video data probing function.
1208  * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1209  * this function will be called when data stream pass through the pad.
1210  *
1211  * @param[in]   pad             probing pad which calls this function.
1212  * @param[in]   buffer          buffer which contains stream data.
1213  * @param[in]   u_data          user data.
1214  * @return      This function returns true on success, or false value with error
1215  * @remarks
1216  * @see
1217  */
1218 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data){
1219         GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1220         switch (GST_EVENT_TYPE(event)) {
1221         case GST_EVENT_UNKNOWN:
1222         /* upstream events */
1223         case GST_EVENT_QOS:
1224         case GST_EVENT_SEEK:
1225         case GST_EVENT_NAVIGATION:
1226         case GST_EVENT_LATENCY:
1227         /* downstream serialized events */
1228         case GST_EVENT_SEGMENT :
1229         case GST_EVENT_TAG:
1230         case GST_EVENT_BUFFERSIZE:
1231                 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1232                 break;
1233         case GST_EVENT_EOS:
1234                 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1235                 break;
1236         /* bidirectional events */
1237         case GST_EVENT_FLUSH_START:
1238         case GST_EVENT_FLUSH_STOP:
1239                 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1240                 break;
1241         default:
1242                 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1243                 break;
1244         }
1245
1246         return GST_PAD_PROBE_OK;
1247 }
1248
1249
1250 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1251 {
1252         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1253         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1254         GstMapInfo mapinfo;
1255         _MMCamcorderSubContext *sc = NULL;
1256         _MMCamcorderVideoInfo *videoinfo = NULL;
1257         _MMCamcorderMsgItem msg;
1258         guint64 buffer_size = 0;
1259         guint64 trailer_size = 0;
1260
1261         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1262         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1263         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1264
1265         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1266         videoinfo = sc->info_video;
1267
1268         /* get buffer size */
1269         if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1270                 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1271                 return GST_PAD_PROBE_OK;
1272         }
1273
1274         buffer_size = mapinfo.size;
1275         gst_buffer_unmap(buffer, &mapinfo);
1276
1277         /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1278
1279         pthread_mutex_lock(&(videoinfo->size_check_lock));
1280
1281         if (videoinfo->audio_frame_count == 0) {
1282                 videoinfo->filesize += buffer_size;
1283                 videoinfo->audio_frame_count++;
1284                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1285                 return GST_PAD_PROBE_OK;
1286         }
1287
1288         if (sc->ferror_send || sc->isMaxsizePausing) {
1289                 _mmcam_dbg_warn("Recording is paused, drop frames");
1290                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1291                 return GST_PAD_PROBE_DROP;
1292         }
1293
1294         /* get trailer size */
1295         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1296                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1297         } else {
1298                 trailer_size = 0;
1299         }
1300
1301         /* check max size of recorded file */
1302         if (videoinfo->max_size > 0 &&
1303             videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1304                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1305                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1306                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1307                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1308                                 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1309                                 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1310
1311                 if (!sc->isMaxsizePausing) {
1312                         sc->isMaxsizePausing = TRUE;
1313                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1314                         if (pipeline_state == GST_STATE_PLAYING) {
1315                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1316                         }
1317
1318                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1319                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1320                 }
1321
1322                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1323
1324                 return FALSE;
1325         }
1326
1327         videoinfo->filesize += buffer_size;
1328         videoinfo->audio_frame_count++;
1329
1330         pthread_mutex_unlock(&(videoinfo->size_check_lock));
1331
1332         return GST_PAD_PROBE_OK;
1333 }
1334
1335
1336 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1337 {
1338         gint ret = 0;
1339         guint vq_size = 0;
1340         guint aq_size = 0;
1341         guint64 free_space = 0;
1342         guint64 buffer_size = 0;
1343         guint64 trailer_size = 0;
1344         guint64 queued_buffer = 0;
1345         char *dir_name = NULL;
1346         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1347         GstMapInfo mapinfo;
1348
1349         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1350         _MMCamcorderMsgItem msg;
1351         _MMCamcorderSubContext *sc = NULL;
1352         _MMCamcorderVideoInfo *videoinfo = NULL;
1353
1354         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1355         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1356
1357         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1358         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1359         videoinfo = sc->info_video;
1360
1361         /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1362         if (sc->ferror_send) {
1363                 _mmcam_dbg_warn("file write error, drop frames");
1364                 return GST_PAD_PROBE_DROP;
1365         }
1366
1367         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1368         buffer_size = mapinfo.size;
1369         gst_buffer_unmap(buffer, &mapinfo);
1370
1371         videoinfo->video_frame_count++;
1372         if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1373                 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1374                                 info->video_frame_count); */
1375                 pthread_mutex_lock(&(videoinfo->size_check_lock));
1376                 videoinfo->filesize += buffer_size;
1377                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1378                 return GST_PAD_PROBE_OK;
1379         }
1380
1381         /* get trailer size */
1382         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1383                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1384         } else {
1385                 trailer_size = 0;
1386         }
1387
1388         dir_name = g_path_get_dirname(videoinfo->filename);
1389         if (dir_name) {
1390                 ret = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
1391                 g_free(dir_name);
1392                 dir_name = NULL;
1393         } else {
1394                 _mmcam_dbg_err("failed to get dir name from [%s]", videoinfo->filename);
1395                 ret = -1;
1396         }
1397
1398         /*_mmcam_dbg_log("check free space for recording");*/
1399
1400         switch (ret) {
1401         case -2: /* file not exist */
1402         case -1: /* failed to get free space */
1403                 _mmcam_dbg_err("Error occured. [%d]", ret);
1404                 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1405                         sc->ferror_send = TRUE;
1406                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1407                         if (ret == -2) {
1408                                 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1409                         } else {
1410                                 msg.param.code = MM_ERROR_FILE_READ;
1411                         }
1412                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1413                 } else {
1414                         sc->ferror_count++;
1415                 }
1416
1417                 return GST_PAD_PROBE_DROP; /* skip this buffer */
1418                 break;
1419         default: /* succeeded to get free space */
1420                 /* check free space for recording */
1421                 /* get queued buffer size */
1422                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1423                         MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1424                 }
1425                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1426                         MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1427                 }
1428
1429                 queued_buffer = aq_size + vq_size;
1430
1431                 /* check free space */
1432                 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1433                         _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1434                         _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1435                                         " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1436                                         free_space, trailer_size, buffer_size, queued_buffer);
1437
1438                         if (!sc->isMaxsizePausing) {
1439                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1440                                 sc->isMaxsizePausing = TRUE;
1441
1442                                 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1443                                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1444                         }
1445
1446                         return GST_PAD_PROBE_DROP;
1447                 }
1448                 break;
1449         }
1450
1451         pthread_mutex_lock(&(videoinfo->size_check_lock));
1452
1453         /* check max size of recorded file */
1454         if (videoinfo->max_size > 0 &&
1455             videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1456                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1457                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1458                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1459                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1460                                 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1461                                                 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1462
1463                 if (!sc->isMaxsizePausing) {
1464                         sc->isMaxsizePausing = TRUE;
1465                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1466                         if (pipeline_state == GST_STATE_PLAYING) {
1467                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1468                         }
1469
1470                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1471                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1472                 }
1473
1474                 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1475
1476                 return GST_PAD_PROBE_DROP;
1477         }
1478
1479         videoinfo->filesize += (guint64)buffer_size;
1480
1481         /*
1482         _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1483         */
1484
1485         pthread_mutex_unlock(&(videoinfo->size_check_lock));
1486
1487         return GST_PAD_PROBE_OK;
1488 }
1489
1490
1491 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1492 {
1493         guint64 trailer_size = 0;
1494         guint64 rec_pipe_time = 0;
1495         unsigned int remained_time = 0;
1496
1497         GstClockTime b_time;
1498
1499         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1500         _MMCamcorderMsgItem msg;
1501         _MMCamcorderSubContext *sc = NULL;
1502         _MMCamcorderVideoInfo *videoinfo = NULL;
1503
1504         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1505
1506         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1507         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1508
1509         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1510         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1511         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1512
1513         videoinfo = sc->info_video;
1514
1515         b_time = GST_BUFFER_PTS(buffer);
1516
1517         rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1518
1519         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1520                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1521         } else {
1522                 trailer_size = 0;
1523         }
1524
1525         /* check max time */
1526         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1527                 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1528                                 rec_pipe_time, videoinfo->max_time);
1529
1530                 if (!sc->isMaxtimePausing) {
1531                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1532
1533                         sc->isMaxtimePausing = TRUE;
1534
1535                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1536                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1537                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1538                         msg.param.recording_status.remained_time = 0;
1539                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1540
1541                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1542                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1543                 }
1544
1545                 return GST_PAD_PROBE_DROP;
1546         }
1547
1548         /* calculate remained time can be recorded */
1549         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1550                 remained_time = videoinfo->max_time - rec_pipe_time;
1551         } else if (videoinfo->max_size > 0) {
1552                 long double max_size = (long double)videoinfo->max_size;
1553                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1554
1555                 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1556         }
1557
1558         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1559         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1560         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1561         msg.param.recording_status.remained_time = remained_time;
1562         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1563
1564         /*
1565         _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1566                        GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1567         */
1568
1569         if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1570                 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1571
1572                 /*
1573                 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1574                                record_motion_rate, videoinfo->record_drop_count);
1575                 */
1576
1577                 /* drop some frame if fast motion */
1578                 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1579                         if (record_motion_rate != (videoinfo->record_drop_count++)) {
1580                                 /*
1581                                 _mmcam_dbg_warn("drop frame");
1582                                 */
1583                                 return GST_PAD_PROBE_DROP;
1584                         }
1585
1586                         videoinfo->record_drop_count = 1;
1587                         /*
1588                         _mmcam_dbg_warn("pass frame");
1589                         */
1590                 }
1591
1592                 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1593         }
1594
1595         return GST_PAD_PROBE_OK;
1596 }
1597
1598
1599 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1600 {
1601         _MMCamcorderMsgItem msg;
1602         guint64 trailer_size = 0;
1603         guint64 rec_pipe_time = 0;
1604         _MMCamcorderSubContext *sc = NULL;
1605         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1606         _MMCamcorderVideoInfo *videoinfo = NULL;
1607         unsigned int remained_time = 0;
1608         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1609
1610         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1611         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1612         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1613
1614         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1615         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1616         mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1617
1618         videoinfo = sc->info_video;
1619
1620         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1621                 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1622                 return GST_PAD_PROBE_OK;
1623         }
1624
1625         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1626
1627         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1628                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1629         } else {
1630                 trailer_size = 0;
1631         }
1632
1633         /* calculate remained time can be recorded */
1634         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1635                 remained_time = videoinfo->max_time - rec_pipe_time;
1636         } else if (videoinfo->max_size > 0) {
1637                 long double max_size = (long double)videoinfo->max_size;
1638                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1639
1640                 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1641         }
1642
1643         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1644                 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1645                                 rec_pipe_time, videoinfo->max_time);
1646
1647                 if (!sc->isMaxtimePausing) {
1648                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1649
1650                         sc->isMaxtimePausing = TRUE;
1651
1652                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1653                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1654                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1655                         msg.param.recording_status.remained_time = 0;
1656                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1657
1658                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1659                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1660                 }
1661
1662                 return GST_PAD_PROBE_DROP;
1663         }
1664
1665         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1666         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1667         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1668         msg.param.recording_status.remained_time = remained_time;
1669         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1670
1671         /*
1672         _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1673                        GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1674         */
1675
1676         return GST_PAD_PROBE_OK;
1677 }
1678
1679
1680 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1681 {
1682         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1683         double volume = 0.0;
1684         int format = 0;
1685         int channel = 0;
1686         int err = MM_ERROR_UNKNOWN;
1687         char *err_name = NULL;
1688         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1689         GstMapInfo mapinfo;
1690
1691         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1692         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1693
1694         /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1695         err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1696                                           MMCAM_AUDIO_VOLUME, &volume,
1697                                           MMCAM_AUDIO_FORMAT, &format,
1698                                           MMCAM_AUDIO_CHANNEL, &channel,
1699                                           NULL);
1700         if (err != MM_ERROR_NONE) {
1701                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1702                 SAFE_FREE(err_name);
1703                 return err;
1704         }
1705
1706         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1707
1708         gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1709
1710         /* Set audio stream NULL */
1711         if (volume == 0.0) {
1712                 memset(mapinfo.data, 0, mapinfo.size);
1713         }
1714
1715         /* CALL audio stream callback */
1716         if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1717                 MMCamcorderAudioStreamDataType stream;
1718
1719                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1720                         _mmcam_dbg_warn("Not ready for stream callback");
1721                         gst_buffer_unmap(buffer, &mapinfo);
1722                         return GST_PAD_PROBE_OK;
1723                 }
1724
1725                 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1726                                GST_BUFFER_DATA(buffer), width, height, format);*/
1727
1728                 stream.data = (void *)mapinfo.data;
1729                 stream.format = format;
1730                 stream.channel = channel;
1731                 stream.length = mapinfo.size;
1732                 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1733
1734                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1735
1736                 if (hcamcorder->astream_cb) {
1737                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1738                 }
1739
1740                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1741         }
1742
1743         gst_buffer_unmap(buffer, &mapinfo);
1744         return GST_PAD_PROBE_OK;
1745 }
1746
1747
1748 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1749 {
1750         gboolean bret = FALSE;
1751
1752         switch (fileformat) {
1753         case MM_FILE_FORMAT_3GP:
1754         case MM_FILE_FORMAT_MP4:
1755                 bret = __mmcamcorder_add_metadata_mp4(handle);
1756                 break;
1757         default:
1758                 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1759                 break;
1760         }
1761
1762         return bret;
1763 }
1764
1765
1766 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1767 {
1768         FILE *f = NULL;
1769         guchar buf[4];
1770         guint64 udta_size = 0;
1771         gint64 current_pos = 0;
1772         gint64 moov_pos = 0;
1773         gint64 udta_pos = 0;
1774         gdouble longitude = 0;
1775         gdouble latitude = 0;
1776         gdouble altitude = 0;
1777         int err = 0;
1778         int orientation = 0;
1779         int gps_enable = 0;
1780         char *err_name = NULL;
1781         char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1782         _MMCamcorderLocationInfo location_info = {0,0,0};
1783         _MMCamcorderLocationInfo geo_info = {0,0,0};
1784
1785         _MMCamcorderVideoInfo *info = NULL;
1786         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1787         _MMCamcorderSubContext *sc = NULL;
1788
1789         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1790         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1791
1792         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1793         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1794
1795         _mmcam_dbg_log("");
1796
1797         info = sc->info_video;
1798
1799         f = fopen64(info->filename, "rb+");
1800         if (f == NULL) {
1801                 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1802                 _mmcam_dbg_err("file open failed [%s]", err_msg);
1803                 return FALSE;
1804         }
1805
1806         mm_camcorder_get_attributes(handle, &err_name,
1807                                     MMCAM_TAG_LATITUDE, &latitude,
1808                                     MMCAM_TAG_LONGITUDE, &longitude,
1809                                     MMCAM_TAG_ALTITUDE, &altitude,
1810                                     MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1811                                     MMCAM_TAG_GPS_ENABLE, &gps_enable,
1812                                     NULL);
1813         if (err_name) {
1814                 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1815                 SAFE_FREE (err_name);
1816         }
1817
1818         location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1819         location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1820         location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1821         geo_info.longitude = longitude *10000;
1822         geo_info.latitude = latitude *10000;
1823         geo_info.altitude = altitude *10000;
1824         /* find udta container.
1825            if, there are udta container, write loci box after that
1826            else, make udta container and write loci box. */
1827         if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) {
1828                 size_t nread = 0;
1829
1830                 _mmcam_dbg_log("find udta container");
1831
1832                 /* read size */
1833                 if (fseek(f, -8L, SEEK_CUR) != 0) {
1834                         goto fail;
1835                 }
1836
1837                 udta_pos = ftello(f);
1838                 if (udta_pos < 0) {
1839                         goto ftell_fail;
1840                 }
1841
1842                 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1843
1844                 _mmcam_dbg_log("recorded file fread %d", nread);
1845
1846                 udta_size = _mmcamcorder_get_container_size(buf);
1847
1848                 /* goto end of udta and write 'loci' box */
1849                 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1850                         goto fail;
1851                 }
1852
1853                 if (gps_enable) {
1854                         if (!_mmcamcorder_write_loci(f, location_info)) {
1855                                 _mmcam_dbg_err("failed to write loci");
1856                                 goto fail;
1857                         }
1858
1859                         if (!_mmcamcorder_write_geodata(f, geo_info)) {
1860                                 _mmcam_dbg_err("failed to write geodata");
1861                                 goto fail;
1862                         }
1863                 }
1864
1865                 current_pos = ftello(f);
1866                 if (current_pos < 0) {
1867                         goto ftell_fail;
1868                 }
1869
1870                 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1871                         goto fail;
1872                 }
1873         } else {
1874                 _mmcam_dbg_log("No udta container");
1875                 if (fseek(f, 0, SEEK_END) != 0) {
1876                         goto fail;
1877                 }
1878
1879                 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1880                         _mmcam_dbg_err("failed to write udta");
1881                         goto fail;
1882                 }
1883         }
1884
1885         /* find moov container.
1886            update moov container size. */
1887         if((current_pos = ftello(f))<0)
1888                 goto ftell_fail;
1889
1890         if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) {
1891                 gint64 internal_pos = ftello(f);
1892
1893                 _mmcam_dbg_log("found moov container");
1894                 if (fseek(f, -8L, SEEK_CUR) !=0) {
1895                         goto fail;
1896                 }
1897
1898                 moov_pos = ftello(f);
1899                 if (moov_pos < 0) {
1900                         goto ftell_fail;
1901                 }
1902
1903                 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1904                         goto fail;
1905                 }
1906
1907                 /* add orientation info */
1908                 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1909                         _mmcam_dbg_err("fseek failed : errno %d", errno);
1910                         goto fail;
1911                 }
1912
1913                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','r','a','k'), FALSE)) {
1914                         _mmcam_dbg_err("failed to find [trak] tag");
1915                         goto fail;
1916                 }
1917
1918                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','k','h','d'), FALSE)) {
1919                         _mmcam_dbg_err("failed to find [tkhd] tag");
1920                         goto fail;
1921                 }
1922
1923                 _mmcam_dbg_log("found [tkhd] tag");
1924
1925                 /* seek to start position of composition matrix */
1926                 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
1927
1928                 /* update composition matrix for orientation */
1929                 _mmcamcorder_update_composition_matrix(f, orientation);
1930         } else {
1931                 _mmcam_dbg_err("No 'moov' container");
1932                 goto fail;
1933         }
1934
1935         fclose(f);
1936         return TRUE;
1937
1938 fail:
1939         fclose(f);
1940         return FALSE;
1941
1942 ftell_fail:
1943         _mmcam_dbg_err("ftell() returns negative value.");
1944         fclose(f);
1945         return FALSE;
1946 }
1947
1948
1949 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
1950 {
1951         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1952         _MMCamcorderSubContext *sc = NULL;
1953
1954         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1955
1956         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1957         mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1958
1959         /* check video source element */
1960         if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
1961                 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
1962                 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
1963                                            _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
1964                                            G_CALLBACK(__mmcamcorder_video_stream_cb),
1965                                            hcamcorder);
1966                 return MM_ERROR_NONE;
1967         } else {
1968                 _mmcam_dbg_err("videosrc element is not created yet");
1969                 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
1970         }
1971 }
1972
1973
1974 int _mmcamcorder_video_prepare_record(MMHandleType handle)
1975 {
1976         int ret = MM_ERROR_NONE;
1977
1978         _MMCamcorderVideoInfo *info = NULL;
1979         _MMCamcorderSubContext *sc = NULL;
1980         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1981
1982         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1983
1984         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1985         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1986         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1987
1988         info = sc->info_video;
1989
1990         _mmcam_dbg_warn("start");
1991
1992         /* create encoding pipeline */
1993         ret =_mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
1994         if (ret != MM_ERROR_NONE) {
1995                 goto _ERR_PREPARE_RECORD;
1996         }
1997
1998         if (info->filename == NULL) {
1999                 char *temp_filename = NULL;
2000                 int size = 0;
2001
2002                 mm_camcorder_get_attributes(handle, NULL,
2003                                             MMCAM_TARGET_FILENAME, &temp_filename, &size,
2004                                             NULL);
2005                 if (temp_filename) {
2006                         info->filename = strdup(temp_filename);
2007                 }
2008
2009                 if (!info->filename) {
2010                         _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2011                         goto _ERR_PREPARE_RECORD;
2012                 }
2013         }
2014
2015         _mmcam_dbg_log("Record file name [%s]", info->filename);
2016
2017         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2018         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2019
2020         /* Adjust display FPS */
2021         sc->display_interval = 0;
2022         sc->previous_slot_time = 0;
2023
2024         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2025         if (ret != MM_ERROR_NONE) {
2026                 goto _ERR_PREPARE_RECORD;
2027         }
2028
2029         _mmcam_dbg_warn("done");
2030
2031         return ret;
2032
2033 _ERR_PREPARE_RECORD:
2034         /* Remove recorder pipeline and recording file which size maybe zero */
2035         _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2036         if (info && info->filename) {
2037                 _mmcam_dbg_log("file delete(%s)", info->filename);
2038                 unlink(info->filename);
2039         }
2040
2041         return ret;
2042 }