631f38981cae1a01d4fdc820ce20442071de6dff
[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 "mm_camcorder_internal.h"
26 #include "mm_camcorder_videorec.h"
27
28 /*---------------------------------------------------------------------------------------
29 |    GLOBAL VARIABLE DEFINITIONS for internal                                           |
30 ---------------------------------------------------------------------------------------*/
31 #define _MMCAMCORDER_LOCATION_INFO // for add gps information
32
33 /*---------------------------------------------------------------------------------------
34 |    LOCAL VARIABLE DEFINITIONS for internal                                            |
35 ---------------------------------------------------------------------------------------*/
36 #define _MMCAMCORDER_MINIMUM_FRAME              10
37 #define _MMCAMCORDER_RETRIAL_COUNT              10
38 #define _MMCAMCORDER_FRAME_WAIT_TIME            200000 /* ms */
39 #define _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL  5
40
41 /*---------------------------------------------------------------------------------------
42 |    LOCAL FUNCTION PROTOTYPES:                                                         |
43 ---------------------------------------------------------------------------------------*/
44 /* STATIC INTERNAL FUNCTION */
45 static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buffer, gpointer u_data);
46 static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data);
47 static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, gpointer u_data);
48 static gboolean __mmcamcorder_video_dataprobe_slow(GstPad *pad, GstBuffer *buffer, gpointer u_data);
49 static gboolean __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstBuffer *buffer, gpointer u_data);
50 static gboolean __mmcamcorder_add_locationinfo(MMHandleType handle, int fileformat);
51 static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle);
52 static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, gpointer u_data);
53
54 /*=======================================================================================
55 |  FUNCTION DEFINITIONS                                                                 |
56 =======================================================================================*/
57 /*---------------------------------------------------------------------------------------
58 |    GLOBAL FUNCTION DEFINITIONS:                                                       |
59 ---------------------------------------------------------------------------------------*/
60 int _mmcamcorder_add_recorder_pipeline(MMHandleType handle)
61 {
62         int err = MM_ERROR_NONE;
63         char* gst_element_rsink_name = NULL;
64
65         GstPad *srcpad = NULL;
66         GstPad *sinkpad = NULL;
67
68         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
69         _MMCamcorderSubContext *sc = NULL;
70
71         type_element *RecordsinkElement = NULL;
72
73         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
74
75         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
76         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
77         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
78         
79         _mmcam_dbg_log("");
80
81         err = _mmcamcorder_check_videocodec_fileformat_compatibility( handle );
82         if( err != MM_ERROR_NONE )
83         {
84                 return err;
85         }
86
87         /* Create gstreamer element */
88         /* Check main pipeline */
89         if (!sc->element[_MMCAMCORDER_MAIN_PIPE].gst) {
90                 err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
91                 goto pipeline_creation_error;
92         }
93
94         if (sc->is_slow == FALSE) {
95                 /* Sub pipeline */
96                 __ta__("        __mmcamcorder_create_audiosrc_bin",
97                 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
98                 );
99                 if (err != MM_ERROR_NONE) {
100                         return err;
101                 }
102
103                 gst_bin_add(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
104                             sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
105         }
106
107         __ta__("        _mmcamcorder_create_encodesink_bin",
108         err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder);
109         );
110         if (err != MM_ERROR_NONE) {
111                 return err;
112         }
113
114         gst_bin_add(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
115                     sc->element[_MMCAMCORDER_ENCSINK_BIN].gst);
116
117         /* Link each element */
118         srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, "src1");
119         sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
120         _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
121
122         if (sc->is_slow == FALSE) {
123                 srcpad = gst_element_get_static_pad (sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
124                 sinkpad = gst_element_get_static_pad (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
125                 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
126         }
127
128         _mmcamcorder_conf_get_element(hcamcorder->conf_main,
129                                       CONFIGURE_CATEGORY_MAIN_RECORD,
130                                       "RecordsinkElement",
131                                       &RecordsinkElement);
132         _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
133
134         /* set data probe function */
135
136         /* register message cb */
137
138         /* set data probe function for audio */
139
140         if (sc->is_slow == FALSE) {
141                 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
142                 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
143                                              __mmcamcorder_audioque_dataprobe, hcamcorder);
144                 gst_object_unref(sinkpad);
145                 sinkpad = NULL;
146                 
147                 /* for voice mute */
148                 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
149                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
150                                              __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
151                 gst_object_unref(srcpad);
152                 srcpad = NULL;
153
154                 if (sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
155                         srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
156                         MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
157                                                     __mmcamcorder_eventprobe_monitor, hcamcorder);
158                         gst_object_unref(srcpad);
159                         srcpad = NULL;
160                 }
161         }
162
163         if (sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
164                 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
165                 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
166                                             __mmcamcorder_eventprobe_monitor, hcamcorder);
167                 gst_object_unref(srcpad);
168                 srcpad = NULL;
169         }
170
171         if (sc->is_slow) {
172                 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
173                 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
174                                              __mmcamcorder_video_dataprobe_slow, hcamcorder);
175                 gst_object_unref(sinkpad);
176                 sinkpad = NULL;
177         }
178
179         if (!strcmp(gst_element_rsink_name, "filesink")) {
180                 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
181                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
182                                              __mmcamcorder_video_dataprobe_record, hcamcorder);
183                 gst_object_unref(srcpad);
184                 srcpad = NULL;
185
186                 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
187                 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
188                                              __mmcamcorder_audio_dataprobe_check, hcamcorder);
189                 gst_object_unref(srcpad);
190                 srcpad = NULL;
191         }
192
193         return MM_ERROR_NONE;
194
195 pipeline_creation_error:
196         return err;
197 }
198
199
200 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
201 {
202         int ret = MM_ERROR_NONE;
203         GstPad *srcpad = NULL;
204         GstPad *sinkpad = NULL;
205         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
206         _MMCamcorderSubContext *sc = NULL;
207
208         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
209
210         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
211         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
212         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
213
214         _mmcam_dbg_log("");
215
216         if (sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
217                 __ta__( "        AudiosrcBin Set NULL",
218                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, GST_STATE_NULL);
219                 );
220                 if (ret != MM_ERROR_NONE) {
221                         _mmcam_dbg_err("Faile to change audio source state[%d]", ret);
222                         return ret;
223                 }
224
225                 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
226                 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
227                 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
228
229                 gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
230                                sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
231
232                 /*
233                         To avoid conflicting between old elements and newly created elements,
234                         I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
235                         This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
236                         So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
237                         It's because the pipeline of audio recording destroys at the same time,
238                         and '_mmcamcorder_element_release_noti' will perfom removing handle.
239                 */
240                 _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_NS);
241
242                 _mmcam_dbg_log("Audio pipeline removed");
243         }
244
245         return MM_ERROR_NONE;
246 }
247
248
249 int _mmcamcorder_remove_encoder_pipeline(MMHandleType handle)
250 {
251         int ret = MM_ERROR_NONE;
252         GstPad *srcpad = NULL;
253         GstPad *sinkpad = NULL;
254         GstPad *reqpad = NULL;
255         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
256         _MMCamcorderSubContext *sc = NULL;
257         
258         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
259
260         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
261         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
262         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
263
264         _mmcam_dbg_log("");
265
266         if (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst != NULL) {
267                 __ta__( "        EncodeBin Set NULL",
268                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, GST_STATE_NULL);
269                 );
270                 if (ret != MM_ERROR_NONE) {
271                         _mmcam_dbg_err("Faile to change encode bin state[%d]", ret);
272                         return ret;
273                 }
274
275                 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, "src1");
276                 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
277                 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
278
279                 /* release request pad */
280                 reqpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
281                 if (reqpad) {
282                         gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
283                         gst_object_unref(reqpad);
284                         reqpad = NULL;
285                 }
286
287                 reqpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
288                 if (reqpad) {
289                         gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
290                         gst_object_unref(reqpad);
291                         reqpad = NULL;
292                 }
293
294                 gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
295                                sc->element[_MMCAMCORDER_ENCSINK_BIN].gst);
296
297                 /*
298                         To avoid conflicting between old elements and newly created elements,
299                         I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
300                         This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
301                         So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
302                         It's because the pipeline of audio recording destroys at the same time,
303                         and '_mmcamcorder_element_release_noti' will perfom removing handle.
304                 */
305                 _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_AUDIOSRC_QUE, _MMCAMCORDER_AUDIOSRC_ENC); /* Encode bin has audio encoder too. */
306                 _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_ENCSINK_BIN, _MMCAMCORDER_ENCSINK_SINK);
307
308                 _mmcam_dbg_log("Encoder pipeline removed");
309         }
310
311         return MM_ERROR_NONE;
312 }
313
314
315 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
316 {
317         int ret = MM_ERROR_NONE;
318         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
319         _MMCamcorderSubContext *sc = NULL;
320
321         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
322         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
323         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
324
325         _mmcam_dbg_log("");
326
327         if (!sc->element[_MMCAMCORDER_MAIN_PIPE].gst) {
328                 _mmcam_dbg_warn("pipeline is not existed.");
329                 return MM_ERROR_NONE;
330         }
331
332         _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
333
334         ret = _mmcamcorder_remove_encoder_pipeline(handle);
335         if (ret != MM_ERROR_NONE) {
336                 _mmcam_dbg_err("Fail to remove encoder pipeline");
337                 return ret;
338         }
339
340         ret = _mmcamcorder_remove_audio_pipeline(handle);
341         if (ret != MM_ERROR_NONE) {
342                 _mmcam_dbg_err("Fail to remove audio pipeline");
343                 return ret;
344         }
345
346         return ret;
347 }
348
349
350 void _mmcamcorder_destroy_video_pipeline(MMHandleType handle)
351 {
352         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
353         _MMCamcorderSubContext *sc = NULL;
354         GstPad *reqpad1 = NULL;
355         GstPad *reqpad2 = NULL;
356         
357         mmf_return_if_fail(hcamcorder);
358         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
359
360         mmf_return_if_fail(sc);
361         mmf_return_if_fail(sc->element);
362         
363         _mmcam_dbg_log("");
364
365         if (sc->element[_MMCAMCORDER_MAIN_PIPE].gst) {
366                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
367                 _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_NULL);
368
369                 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_CATEGORY_ALL);
370
371                 reqpad1 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src0");
372                 reqpad2 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src1");
373                 gst_element_release_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, reqpad1);
374                 gst_element_release_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, reqpad2);
375                 gst_object_unref(reqpad1);
376                 gst_object_unref(reqpad2);
377
378                 /* object disposing problem happen. */
379                 _mmcam_dbg_log("Reference count of pipeline(%d)", GST_OBJECT_REFCOUNT_VALUE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst));
380                 gst_object_unref(sc->element[_MMCAMCORDER_MAIN_PIPE].gst);
381         }
382 }
383
384
385 int _mmcamcorder_video_command(MMHandleType handle, int command)
386 {
387         int size = 0;
388         int fileformat = 0;
389         int ret = MM_ERROR_NONE;
390         char *temp_filename = NULL;
391         char *err_name = NULL;
392
393         gint fps = 0;
394         gint slow_fps = 0;
395         GstElement *pipeline = NULL;
396         GstPad *pad = NULL;
397
398         _MMCamcorderVideoInfo *info = NULL;
399         _MMCamcorderSubContext *sc = NULL;
400         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
401
402         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
403
404         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
405         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
406         mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
407         mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
408
409         info = sc->info;
410
411         _mmcam_dbg_log("Command(%d)", command);
412
413         pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
414
415         switch (command) {
416         case _MMCamcorder_CMD_RECORD:
417         {
418                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
419                         guint imax_time = 0;
420
421                         /* Play record start sound */
422                         _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_START_SND, TRUE);
423
424                         /* Recording */
425                         _mmcam_dbg_log("Record Start");
426
427                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
428                         if (ret != MM_ERROR_NONE) {
429                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
430                         }
431
432                         _mmcamcorder_conf_get_value_int(hcamcorder->conf_main,
433                                                         CONFIGURE_CATEGORY_MAIN_RECORD,
434                                                         "DropVideoFrame",
435                                                         &(sc->drop_vframe));
436
437                         _mmcamcorder_conf_get_value_int(hcamcorder->conf_main,
438                                                         CONFIGURE_CATEGORY_MAIN_RECORD,
439                                                         "PassFirstVideoFrame",
440                                                         &(sc->pass_first_vframe));
441
442                         _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
443                                        sc->drop_vframe, sc->pass_first_vframe);
444
445                         ret = mm_camcorder_get_attributes(handle, &err_name,
446                                                           MMCAM_CAMERA_FPS, &fps,
447                                                           "camera-slow-motion-fps", &slow_fps,
448                                                           MMCAM_FILE_FORMAT, &fileformat,
449                                                           MMCAM_TARGET_FILENAME, &temp_filename, &size,
450                                                           MMCAM_TARGET_TIME_LIMIT, &imax_time,
451                                                           MMCAM_FILE_FORMAT, &(info->fileformat),
452                                                           NULL);
453                         if (ret != MM_ERROR_NONE) {
454                                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
455                                 SAFE_FREE (err_name);
456                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
457                         }
458
459                         /* set max time */
460                         if (imax_time <= 0) {
461                                 info->max_time = 0; /* do not check */
462                         } else {
463                                 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
464                         }
465
466                         if (sc->is_slow) {
467                                 info->multiple_fps = fps/slow_fps;
468                                 _mmcam_dbg_log("high speed recording fps:%d,slow_fps:%d,multiple_fps:%d",
469                                                fps, slow_fps, info->multiple_fps);
470                         }
471
472                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", TRUE);
473                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "req-negotiation", TRUE);
474
475                         ret =_mmcamcorder_add_recorder_pipeline((MMHandleType)hcamcorder);
476                         if (ret != MM_ERROR_NONE) {
477                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
478                         }
479
480                         info->filename = strdup(temp_filename);
481                         if (!info->filename) {
482                                 _mmcam_dbg_err("strdup was failed");
483                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
484                         }
485
486                         _mmcam_dbg_log("Record start : set file name using attribute - %s ",info->filename);
487
488                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
489                         MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
490
491                         /* Adjust display FPS */
492                         sc->display_interval = 0;
493                         sc->previous_slot_time = 0;
494
495                         /* gst_element_set_base_time(GST_ELEMENT(pipeline), (GstClockTime)0);
496                            if you want to use audio clock, enable this block
497                            for change recorder_pipeline state to paused. */
498                         __ta__("        _MMCamcorder_CMD_RECORD:GST_STATE_PAUSED2",
499                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
500                         );
501                         if (ret != MM_ERROR_NONE) {
502                                 /* Remove recorder pipeline and recording file which size maybe zero */
503                                 __ta__("        record fail:remove_recorder_pipeline",
504                                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
505                                 );
506                                 if (info->filename) {
507                                         _mmcam_dbg_log("file delete(%s)", info->filename);
508                                         unlink(info->filename);
509                                         g_free(info->filename);
510                                         info->filename = NULL;
511                                 }
512                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
513                         }
514
515                         /**< To fix video recording hanging
516                                 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
517                                 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
518                                  basetime wouldn't change if you set (GstClockTime)0.
519                                 3. Move set start time position below PAUSED of pipeline.
520                         */
521                         gst_element_set_start_time(GST_ELEMENT(pipeline), (GstClockTime)1);
522                         info->video_frame_count = 0;
523                         info->audio_frame_count = 0;
524                         info->filesize = 0;
525                         sc->ferror_send = FALSE;
526                         sc->ferror_count = 0;
527                         sc->error_occurs = FALSE;
528                         sc->bget_eos = FALSE;
529
530                         __ta__("        _MMCamcorder_CMD_RECORD:GST_STATE_PLAYING2",
531                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
532                         );
533                         if (ret != MM_ERROR_NONE) {
534                                 /* Remove recorder pipeline and recording file which size maybe zero */
535                                 __ta__("        record fail:remove_recorder_pipeline",
536                                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
537                                 );
538                                 if (info->filename) {
539                                         _mmcam_dbg_log("file delete(%s)", info->filename);
540                                         unlink(info->filename);
541                                         g_free(info->filename);
542                                         info->filename = NULL;
543                                 }
544                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
545                         }
546                 } else {
547                         /* Resume case */
548                         int video_enc = 0;
549
550                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
551
552                         mm_camcorder_get_attributes(handle, NULL, MMCAM_VIDEO_ENCODER, &video_enc, NULL);
553                         if (video_enc == MM_VIDEO_CODEC_MPEG4) {
554                                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "force-intra", TRUE);
555                         }
556
557                         _mmcam_dbg_log("Object property settings done");
558                 }
559         }
560                 break;
561         case _MMCamcorder_CMD_PAUSE:
562         {
563                 int count = 0;
564
565                 if (info->b_commiting) {
566                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
567                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
568                 }
569
570                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
571                         if (sc->is_slow) {
572                                 /* check only video frame */
573                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
574                                         break;
575                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
576                                         _mmcam_dbg_err("Pause fail, frame count %" G_GUINT64_FORMAT "",
577                                                        info->video_frame_count);
578                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
579                                 } else {
580                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %" G_GUINT64_FORMAT "",
581                                                         count, info->video_frame_count);
582                                 }
583
584                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
585                         } else {
586                                 /* check both of video and audio frame */
587                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
588                                         break;
589                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
590                                         _mmcam_dbg_err("Pause fail, frame count VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
591                                                        info->video_frame_count, info->audio_frame_count);
592                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
593                                 } else {
594                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
595                                                         count, info->video_frame_count, info->audio_frame_count);
596                                 }
597
598                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
599                         }
600                 }
601                 /* tee block */
602                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
603
604                 break;
605         }
606         case _MMCamcorder_CMD_CANCEL:
607         {
608                 if (info->b_commiting) {
609                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
610                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
611                 }
612
613                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
614                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", FALSE);
615
616                 if (sc->now_continuous_af) {
617                         sc->now_continuous_af = FALSE;
618                         _mmcam_dbg_log("Set now_continuous_af as FALSE when CANCEL recording");
619                 }
620
621                 __ta__("        _MMCamcorder_CMD_CANCEL:GST_STATE_READY",
622                 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
623                 );
624                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
625                 if (ret != MM_ERROR_NONE) {
626                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
627                 }
628
629                 __ta__("        __mmcamcorder_remove_recorder_pipeline",
630                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
631                 );
632
633                 /* remove target file */
634                 if (info->filename) {
635                         _mmcam_dbg_log("file delete(%s)", info->filename);
636                         unlink(info->filename);
637                         g_free(info->filename);
638                         info->filename = NULL;
639                 }
640
641                 sc->isMaxsizePausing = FALSE;
642                 sc->isMaxtimePausing = FALSE;
643
644                 sc->display_interval = 0;
645                 sc->previous_slot_time = 0;
646                 info->video_frame_count = 0;
647                 info->audio_frame_count = 0;
648                 info->filesize =0;
649
650                 __ta__("        _MMCamcorder_CMD_CANCEL:GST_STATE_PLAYING",
651                 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
652                 );
653                 if (ret != MM_ERROR_NONE) {
654                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
655                 }
656
657                 break;
658         }
659         case _MMCamcorder_CMD_COMMIT:
660         {
661                 int count = 0;
662
663                 if (info->b_commiting) {
664                         _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
665                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
666                 } else {
667                         _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
668                         info->b_commiting = TRUE;
669                 }
670
671                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
672                         if (sc->is_slow) {
673                                 /* check only video frame */
674                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
675                                         break;
676                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
677                                         _mmcam_dbg_err("Commit fail, frame count is %" G_GUINT64_FORMAT "",
678                                                        info->video_frame_count);
679                                         info->b_commiting = FALSE;
680                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
681                                 } else {
682                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %" G_GUINT64_FORMAT "",
683                                                         count, info->video_frame_count);
684                                 }
685
686                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
687                         } else {
688                                 /* check both of video and audio frame */
689                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
690                                         break;
691                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
692                                         _mmcam_dbg_err("Commit fail, VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
693                                                        info->video_frame_count, info->audio_frame_count);
694
695                                         info->b_commiting = FALSE;
696                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
697                                 } else {
698                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
699                                                         count, info->video_frame_count, info->audio_frame_count);
700                                 }
701
702                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
703                         }
704                 }
705
706                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", FALSE);
707
708                 if (sc->now_continuous_af) {
709                         sc->now_continuous_af = FALSE;
710                         _mmcam_dbg_log("Set now_continuous_af as FALSE when COMMIT recording");
711                 }
712
713                 if (sc->error_occurs) {
714                         GstPad *video= NULL;
715                         GstPad *audio = NULL;
716                         int ret = 0;
717
718                         _mmcam_dbg_err("Committing Error case");
719
720                         video = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "sink");
721                         ret = gst_pad_send_event (video, gst_event_new_eos());
722                         _mmcam_dbg_err("Sending EOS video sink  : %d", ret);
723                         gst_object_unref(video);
724
725                         video = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
726                         gst_pad_push_event (video, gst_event_new_flush_start());
727                         gst_pad_push_event (video, gst_event_new_flush_stop());
728                         ret = gst_pad_push_event (video, gst_event_new_eos());
729                         _mmcam_dbg_err("Sending EOS video encoder src pad  : %d", ret);
730                         gst_object_unref(video);
731
732                         if (!sc->is_slow) {
733                                 audio = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
734                                 gst_pad_push_event (audio, gst_event_new_flush_start());
735                                 gst_pad_push_event (audio, gst_event_new_flush_stop());
736                                 ret = gst_element_send_event(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
737                                 _mmcam_dbg_err("Sending EOS audio encoder src pad  : %d", ret);
738                                 gst_object_unref(audio);
739                         }
740                 } else {
741                         if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst != NULL) {
742                                 ret = gst_element_send_event(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, gst_event_new_eos());
743                                 _mmcam_dbg_warn("send eos to videosrc result : %d", ret);
744                         }
745
746                         if (sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
747                                 pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
748                                 ret = gst_element_send_event(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
749                                 gst_object_unref(pad);
750                                 pad = NULL;
751
752                                 _mmcam_dbg_warn("send eos to audiosrc result : %d", ret);
753                         }
754                 }
755
756                 if (hcamcorder->quick_device_close) {
757                         _mmcam_dbg_warn("quick_device_close");
758                         /* close device quickly */
759                         MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "quick-device-close",TRUE);
760                 }
761
762                 /* sc */
763                 sc->display_interval = 0;
764                 sc->previous_slot_time = 0;
765
766                 /* Wait EOS */
767                 _mmcam_dbg_log("Start to wait EOS");
768                 ret =_mmcamcorder_get_eos_message(handle);
769                 if (ret != MM_ERROR_NONE) {
770                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
771                 }
772         }
773                 break;
774         case _MMCamcorder_CMD_PREVIEW_START:
775         {
776                 int fps_auto = 0;
777
778                 _mmcamcorder_vframe_stablize((MMHandleType)hcamcorder);
779
780                 /* sc */
781                 sc->display_interval = 0;
782                 sc->previous_slot_time = 0;
783
784                 mm_camcorder_get_attributes(handle, NULL, MMCAM_CAMERA_FPS_AUTO, &fps_auto, NULL);
785
786                 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "fps-auto", fps_auto);
787
788                 __ta__("        _MMCamcorder_CMD_PREVIEW_START:GST_STATE_PLAYING",
789                 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
790                 );
791                 if (ret != MM_ERROR_NONE) {
792                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
793                 }
794
795                 /* I place this function last because it miscalculates a buffer that sents in GST_STATE_PAUSED */
796                 _mmcamcorder_video_current_framerate_init(handle);
797         }
798                 break;
799         case _MMCamcorder_CMD_PREVIEW_STOP:
800                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
801                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
802                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
803                 if (ret != MM_ERROR_NONE) {
804                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
805                 }
806
807                 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
808                         int op_status = 0;
809                         MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "operation-status", &op_status);
810                         _mmcam_dbg_err("Current Videosrc status[0x%x]", op_status);
811                 }
812
813                 break;
814         default:
815                 ret =  MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
816                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
817         }
818
819         return MM_ERROR_NONE;
820
821 _ERR_CAMCORDER_VIDEO_COMMAND:
822         if (ret != MM_ERROR_NONE && sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst != NULL) {
823                 int op_status = 0;
824                 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "operation-status", &op_status);
825                 _mmcam_dbg_err("Current Videosrc status[0x%x]", op_status);
826         }
827
828         return ret;
829 }
830
831
832 int _mmcamcorder_video_handle_eos(MMHandleType handle)
833 {
834         int ret = MM_ERROR_NONE;
835         int enabletag = 0;
836         int camcorder_rotate = MM_VIDEO_INPUT_ROTATION_NONE;
837         int camera_rotate = MM_VIDEO_INPUT_ROTATION_NONE;
838         int display_rotate = MM_DISPLAY_ROTATION_NONE;
839         guint64 file_size = 0;
840
841         GstPad *pad = NULL;
842         GstElement *pipeline = NULL;
843
844         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
845         _MMCamcorderSubContext *sc = NULL;
846         _MMCamcorderVideoInfo *info = NULL;
847         _MMCamcorderMsgItem msg;
848         MMCamRecordingReport *report = NULL;
849
850         mmf_return_val_if_fail(hcamcorder, FALSE);
851
852         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
853         mmf_return_val_if_fail(sc, FALSE);
854         mmf_return_val_if_fail(sc->info, FALSE);
855
856         info = sc->info;
857
858         _mmcam_dbg_err("");
859
860         MMTA_ACUM_ITEM_BEGIN("    _mmcamcorder_video_handle_eos", 0);
861
862         pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
863
864         /* remove blocking part */
865         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
866         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
867
868         _mmcam_dbg_log("Set state of pipeline as PAUSED");
869         __ta__("        _MMCamcorder_CMD_COMMIT:GST_STATE_PAUSED",
870         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
871         );
872         if (ret != MM_ERROR_NONE) {
873                 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:GST_STATE_PAUSED failed. error[%x]", ret);
874         }
875
876         MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
877
878         __ta__("        _MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline",
879         ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
880         );
881         if (ret != MM_ERROR_NONE) {
882                 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
883         }
884
885         if (enabletag && !(sc->ferror_send)) {
886                 __ta__( "        _MMCamcorder_CMD_COMMIT:__mmcamcorder_add_locationinfo",
887                 ret = __mmcamcorder_add_locationinfo((MMHandleType)hcamcorder, info->fileformat);
888                 );
889                 if (ret) {
890                         _mmcam_dbg_log("Writing location information SUCCEEDED !!");
891                 } else {
892                         _mmcam_dbg_err("Writing location information FAILED !!");
893                 }
894         }
895
896         /* Recovering camera-rotation and display-rotation when start recording */
897         if (camcorder_rotate != camera_rotate &&
898             camera_rotate < MM_VIDEO_INPUT_ROTATION_FLIP_HORZ) {
899                 _mmcamcorder_set_videosrc_rotation(handle, camera_rotate);
900                 _mmcamcorder_set_display_rotation(handle, display_rotate);
901                 _mmcam_dbg_log("## Recovering camcorder rotation is done. camcorder_rotate=%d, camera_rotate=%d, display_rotate=%d",
902                                camcorder_rotate,camera_rotate,display_rotate);
903         } else {
904                 _mmcam_dbg_log("## No need to recover camcorder rotation. camcorder_rotate=%d, camera_rotate=%d, display_rotate=%d",
905                                camcorder_rotate,camera_rotate,display_rotate);
906
907                 /* Flush EOS event to avoid pending pipeline */
908                 pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "sink");
909                 gst_pad_push_event(pad, gst_event_new_flush_start());
910                 gst_pad_push_event(pad, gst_event_new_flush_stop());
911                 gst_object_unref(pad);
912                 pad = NULL;
913
914                 pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "src");
915                 gst_pad_push_event(pad, gst_event_new_flush_start());
916                 gst_pad_push_event(pad, gst_event_new_flush_stop());
917                 gst_object_unref(pad);
918                 pad = NULL;
919         }
920
921         _mmcam_dbg_log("Set state as PLAYING");
922         __ta__("        _MMCamcorder_CMD_COMMIT:GST_STATE_PLAYING",
923         ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
924         );
925         /* Do not return when error is occurred.
926            Recording file was created successfully, but starting pipeline failed */
927         if (ret != MM_ERROR_NONE) {
928                 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
929                 msg.param.code = ret;
930                 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
931                 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
932         }
933
934         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
935                 /* Play record stop sound */
936                 __ta__("        _MMCamcorder_CMD_COMMIT:_mmcamcorder_sound_solo_play",
937                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND, TRUE);
938                 );
939         } else {
940                 _mmcam_dbg_log("Do NOT play recording stop sound because of ASM stop");
941         }
942
943         /* Send recording report to application */
944         msg.id = MM_MESSAGE_CAMCORDER_CAPTURED;
945         report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport));
946         if (!report) {
947                 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
948         } else {
949                 report->recording_filename = strdup(info->filename);
950                 msg.param.data= report;
951                 msg.param.code = 1;
952                 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
953         }
954
955         /* Finishing */
956         sc->pipeline_time = 0;
957         sc->pause_time = 0;
958         sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
959         sc->isMaxtimePausing = FALSE;
960         sc->error_occurs = FALSE;
961
962         info->video_frame_count = 0;
963         info->audio_frame_count = 0;
964         info->filesize = 0;
965         g_free(info->filename);
966         info->filename = NULL;
967         info->b_commiting = FALSE;
968
969         MMTA_ACUM_ITEM_END("    _mmcamcorder_video_handle_eos", 0);
970         MMTA_ACUM_ITEM_END("Real Commit Time", 0);
971
972         _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
973
974         return TRUE;
975 }
976
977 /**
978  * This function is record video data probing function.
979  * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
980  * this function will be called when data stream pass through the pad.
981  *
982  * @param[in]   pad             probing pad which calls this function.
983  * @param[in]   buffer          buffer which contains stream data.
984  * @param[in]   u_data          user data.
985  * @return      This function returns true on success, or false value with error
986  * @remarks
987  * @see
988  */
989 static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, gpointer u_data)
990 {
991         switch (GST_EVENT_TYPE(event)) {
992         case GST_EVENT_UNKNOWN:
993         /* upstream events */
994         case GST_EVENT_QOS:
995         case GST_EVENT_SEEK:
996         case GST_EVENT_NAVIGATION:
997         case GST_EVENT_LATENCY:
998         /* downstream serialized events */
999         case GST_EVENT_NEWSEGMENT :
1000         case GST_EVENT_TAG:
1001         case GST_EVENT_BUFFERSIZE:
1002                 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1003                 break;
1004         case GST_EVENT_EOS:
1005                 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1006                 break;
1007         /* bidirectional events */
1008         case GST_EVENT_FLUSH_START:
1009         case GST_EVENT_FLUSH_STOP:
1010                 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1011                 break;
1012         default:
1013                 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1014                 break;
1015         }
1016
1017         return TRUE;
1018 }
1019
1020
1021 static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1022 {
1023         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1024         _MMCamcorderSubContext *sc = NULL;
1025         _MMCamcorderVideoInfo * info = NULL;
1026
1027         mmf_return_val_if_fail(hcamcorder, TRUE);
1028         mmf_return_val_if_fail(buffer, FALSE);
1029         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1030
1031         mmf_return_val_if_fail(sc && sc->info, TRUE);
1032         info = sc->info;
1033
1034         /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1035
1036         if (info->audio_frame_count == 0) {
1037                 info->filesize += (guint64)GST_BUFFER_SIZE(buffer);
1038                 info->audio_frame_count++;
1039                 return TRUE;
1040         }
1041
1042         if (sc->ferror_send || sc->isMaxsizePausing) {
1043                 _mmcam_dbg_warn("Recording is paused, drop frames");
1044                 return FALSE;
1045         }
1046
1047         info->filesize += (guint64)GST_BUFFER_SIZE(buffer);
1048         info->audio_frame_count++;
1049
1050         return TRUE;
1051 }
1052
1053
1054 static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1055 {
1056         static int count = 0;
1057         gint ret = 0;
1058         guint vq_size = 0;
1059         guint aq_size = 0;
1060         guint64 free_space = 0;
1061         guint64 buffer_size = 0;
1062         guint64 trailer_size = 0;
1063         guint64 queued_buffer = 0;
1064         char *filename = NULL;
1065
1066         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1067         _MMCamcorderMsgItem msg;
1068         _MMCamcorderSubContext *sc = NULL;
1069         _MMCamcorderVideoInfo *info = NULL;
1070
1071         mmf_return_val_if_fail(hcamcorder, TRUE);
1072         mmf_return_val_if_fail(buffer, FALSE);
1073
1074         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1075         mmf_return_val_if_fail(sc && sc->info, TRUE);
1076         info = sc->info;
1077
1078         /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1079         if (sc->ferror_send) {
1080                 _mmcam_dbg_warn("file write error, drop frames");
1081                 return FALSE;
1082         }
1083
1084         info->video_frame_count++;
1085         if (info->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1086                 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1087                                 info->video_frame_count); */
1088                 info->filesize += (guint64)GST_BUFFER_SIZE(buffer);
1089                 return TRUE;
1090         }
1091
1092         buffer_size = GST_BUFFER_SIZE(buffer);
1093
1094         if (sc->now_continuous_af) {
1095                 _mmcam_dbg_log("Start continuous AF when START recording");
1096                 __ta__("        _MMCamcorder_CMD_RECORD:START CAF",
1097                 ret = _mmcamcorder_adjust_auto_focus((MMHandleType)hcamcorder);
1098                 );
1099                 sc->now_continuous_af = FALSE;
1100                 if (ret != MM_ERROR_NONE) {
1101                         _mmcam_dbg_warn("Failed continuous AF when START recording");
1102                 }
1103         }
1104
1105         /* get trailer size */
1106         if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1107                 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1108         } else {
1109                 trailer_size = 0;
1110         }
1111
1112         /* to minimizing free space check overhead */
1113         count = count % _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL;
1114         if (count++ == 0) {
1115                 filename = info->filename;
1116                 ret = _mmcamcorder_get_freespace(filename, &free_space);
1117
1118                 /*_mmcam_dbg_log("check free space for recording");*/
1119
1120                 switch (ret) {
1121                 case -2: /* file not exist */
1122                 case -1: /* failed to get free space */
1123                         _mmcam_dbg_err("Error occured. [%d]", ret);
1124                         if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1125                                 sc->ferror_send = TRUE;
1126                                 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1127                                 if (ret == -2) {
1128                                         msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1129                                 } else {
1130                                         msg.param.code = MM_ERROR_FILE_READ;
1131                                 }
1132                                 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1133                         } else {
1134                                 sc->ferror_count++;
1135                         }
1136
1137                         return FALSE; /* skip this buffer */
1138                         break;
1139                 default: /* succeeded to get free space */
1140                         /* check free space for recording */
1141                         /* get queued buffer size */
1142                         MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1143                         MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1144                         queued_buffer = aq_size + vq_size;
1145
1146                         /* check free space */
1147                         if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1148                                 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1149                                 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1150                                                 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1151                                                 free_space, trailer_size, buffer_size, queued_buffer);
1152
1153                                 if (!sc->isMaxsizePausing) {
1154                                         MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1155                                         sc->isMaxsizePausing = TRUE;
1156
1157                                         msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1158                                         _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1159                                 }
1160
1161                                 return FALSE;
1162                         }
1163                         break;
1164                 }
1165         }
1166
1167         info->filesize += (guint64)buffer_size;
1168
1169         return TRUE;
1170 }
1171
1172
1173 static gboolean __mmcamcorder_video_dataprobe_slow(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1174 {
1175         guint min_fps = 15;
1176         guint64 trailer_size = 0;
1177         static guint count = 0;
1178
1179         GstClockTime b_time;
1180
1181         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1182         _MMCamcorderMsgItem msg;
1183         _MMCamcorderSubContext *sc = NULL;
1184         _MMCamcorderVideoInfo *info = NULL;
1185
1186         mmf_return_val_if_fail(buffer, FALSE);
1187         mmf_return_val_if_fail(hcamcorder, TRUE);
1188
1189         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1190         mmf_return_val_if_fail(sc, TRUE);
1191         mmf_return_val_if_fail(sc->info, TRUE);
1192
1193         info = sc->info;
1194         count %= min_fps;
1195         b_time = GST_BUFFER_TIMESTAMP(buffer);
1196
1197         if (!count) {
1198                 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1199                         MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1200                 } else {
1201                         trailer_size = 0;
1202                 }
1203
1204                 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1205                 msg.param.recording_status.elapsed = (unsigned int)GST_TIME_AS_MSECONDS(b_time);
1206                 msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10);
1207                 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1208         }
1209
1210         count++;
1211
1212         GST_BUFFER_TIMESTAMP(buffer) = b_time * (info->multiple_fps);
1213
1214         return TRUE;
1215 }
1216
1217
1218 static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1219 {
1220         _MMCamcorderMsgItem msg;
1221         guint64 trailer_size = 0;
1222         guint64 rec_pipe_time = 0;
1223         _MMCamcorderSubContext *sc = NULL;
1224         GstElement *pipeline = NULL;
1225         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1226         _MMCamcorderVideoInfo *info = NULL;
1227
1228         mmf_return_val_if_fail(buffer, FALSE);
1229         mmf_return_val_if_fail(hcamcorder, TRUE);
1230         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1231
1232         mmf_return_val_if_fail(sc, TRUE);
1233         mmf_return_val_if_fail(sc->info, TRUE);
1234         mmf_return_val_if_fail(sc->element, TRUE);
1235
1236         info = sc->info;
1237         pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1238
1239         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buffer))) {
1240                 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1241                 return TRUE;
1242         }
1243
1244         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1245
1246         if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1247                 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1248         } else {
1249                 trailer_size = 0;
1250         }
1251
1252         if (info->max_time > 0 && rec_pipe_time > info->max_time) {
1253                 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1254                                 rec_pipe_time, info->max_time);
1255
1256                 if (!sc->isMaxtimePausing) {
1257                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1258
1259                         sc->isMaxtimePausing = TRUE;
1260
1261                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1262                         msg.param.recording_status.elapsed = (unsigned int)rec_pipe_time;
1263                         msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10);
1264                         _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1265
1266                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1267                         _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1268                 }
1269
1270                 return FALSE;
1271         }
1272
1273         /*_mmcam_dbg_log("_mmcamcorder_audioque_dataprobe :: time [%" GST_TIME_FORMAT "], size [%d]",
1274                        GST_TIME_ARGS(rec_pipe_time), (info->filesize + trailer_size) >> 10);*/
1275
1276         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1277         msg.param.recording_status.elapsed = (unsigned int)rec_pipe_time;
1278         msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10);
1279         _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1280
1281         return TRUE;
1282 }
1283
1284
1285 static gboolean __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1286 {
1287         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1288         double volume = 0.0;
1289         int format = 0;
1290         int channel = 0;
1291         int err = MM_ERROR_UNKNOWN;
1292         char *err_name = NULL;
1293
1294         mmf_return_val_if_fail(buffer, FALSE);
1295         mmf_return_val_if_fail(hcamcorder, FALSE);
1296
1297         /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1298         err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1299                                           MMCAM_AUDIO_VOLUME, &volume,
1300                                           MMCAM_AUDIO_FORMAT, &format,
1301                                           MMCAM_AUDIO_CHANNEL, &channel,
1302                                           NULL);
1303         if (err != MM_ERROR_NONE) {
1304                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1305                 SAFE_FREE(err_name);
1306                 return err;
1307         }
1308
1309         /* Set audio stream NULL */
1310         if (volume == 0.0) {
1311                 memset(GST_BUFFER_DATA(buffer), 0, GST_BUFFER_SIZE(buffer));
1312         }
1313
1314         /* CALL audio stream callback */
1315         if (hcamcorder->astream_cb && buffer && GST_BUFFER_DATA(buffer)) {
1316                 MMCamcorderAudioStreamDataType stream;
1317
1318                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1319                         _mmcam_dbg_warn("Not ready for stream callback");
1320                         return TRUE;
1321                 }
1322
1323                 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1324                                GST_BUFFER_DATA(buffer), width, height, format);*/
1325
1326                 stream.data = (void *)GST_BUFFER_DATA(buffer);
1327                 stream.format = format;
1328                 stream.channel = channel;
1329                 stream.length = GST_BUFFER_SIZE(buffer);
1330                 stream.timestamp = (unsigned int)(GST_BUFFER_TIMESTAMP(buffer)/1000000); /* nano -> milli second */
1331
1332                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1333
1334                 if (hcamcorder->astream_cb) {
1335                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1336                 }
1337
1338                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1339         }
1340
1341         return TRUE;
1342 }
1343
1344
1345 static gboolean __mmcamcorder_add_locationinfo(MMHandleType handle, int fileformat)
1346 {
1347         gboolean bret = FALSE;
1348
1349         switch (fileformat) {
1350         case MM_FILE_FORMAT_3GP:
1351         case MM_FILE_FORMAT_MP4:
1352                 bret = __mmcamcorder_add_locationinfo_mp4(handle);
1353                 break;
1354         default:
1355                 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1356                 break;
1357         }
1358
1359         return bret;
1360 }
1361
1362
1363 static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle)
1364 {
1365         FILE *f = NULL;
1366         guchar buf[4];
1367         guint64 udta_size = 0;
1368         gint64 current_pos = 0;
1369         gint64 moov_pos = 0;
1370         gint64 udta_pos = 0;
1371         gdouble longitude = 0;
1372         gdouble latitude = 0;
1373         gdouble altitude = 0;
1374         int err = 0;
1375         char *err_name = NULL;
1376         _MMCamcorderLocationInfo location_info = {0,};
1377
1378         _MMCamcorderVideoInfo *info = NULL;
1379         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1380         _MMCamcorderSubContext *sc = NULL;
1381
1382         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1383         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1384
1385         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1386         mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1387
1388         _mmcam_dbg_log("");
1389
1390         info = sc->info;
1391
1392         f = fopen(info->filename, "rb+");
1393         if (f == NULL) {
1394                 return FALSE;
1395         }
1396
1397         err = mm_camcorder_get_attributes(handle, &err_name,
1398                                           MMCAM_TAG_LATITUDE, &latitude,
1399                                           MMCAM_TAG_LONGITUDE, &longitude,
1400                                           MMCAM_TAG_ALTITUDE, &altitude,
1401                                           NULL);
1402         if (err != MM_ERROR_NONE) {
1403                 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1404                 SAFE_FREE (err_name);
1405                 fclose(f);
1406                 f = NULL;
1407                 return FALSE;
1408         }
1409
1410         location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1411         location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1412         location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1413
1414         /* find udta container.
1415            if, there are udta container, write loci box after that
1416            else, make udta container and write loci box. */
1417         if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('u','d','t','a'))) {
1418                 _mmcam_dbg_log("find udta container");
1419
1420                 /* read size */
1421                 if (fseek(f, -8L, SEEK_CUR) != 0) {
1422                         goto fail;
1423                 }
1424
1425                 udta_pos = ftell(f);
1426                 if (udta_pos < 0) {
1427                         goto ftell_fail;
1428                 }
1429
1430                 fread(&buf, sizeof(char), sizeof(buf), f);
1431                 udta_size = _mmcamcorder_get_container_size(buf);
1432
1433                 /* goto end of udta and write 'loci' box */
1434                 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1435                         goto fail;
1436                 }
1437
1438                 if (!_mmcamcorder_write_loci(f, location_info)) {
1439                         goto fail;
1440                 }
1441
1442                 current_pos = ftell(f);
1443                 if (current_pos < 0) {
1444                         goto ftell_fail;
1445                 }
1446
1447                 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1448                         goto fail;
1449                 }
1450         } else {
1451                 _mmcam_dbg_log("No udta container");
1452                 if (fseek(f, 0, SEEK_END) != 0) {
1453                         goto fail;
1454                 }
1455
1456                 if (!_mmcamcorder_write_udta(f, location_info)) {
1457                         goto fail;
1458                 }
1459         }
1460
1461         /* find moov container.
1462            update moov container size. */
1463         if((current_pos = ftell(f))<0)
1464                 goto ftell_fail;
1465         
1466         if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'))) {
1467                 _mmcam_dbg_log("find moov container");
1468                 if (fseek(f, -8L, SEEK_CUR) !=0) {
1469                         goto fail;
1470                 }
1471
1472                 moov_pos = ftell(f);
1473                 if (moov_pos < 0) {
1474                         goto ftell_fail;
1475                 }
1476
1477                 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1478                         goto fail;
1479                 }
1480         } else {
1481                 _mmcam_dbg_err("No 'moov' container");
1482                 goto fail;
1483         }
1484
1485         fclose(f);
1486         return TRUE;
1487
1488 fail:
1489         fclose(f);
1490         return FALSE;
1491
1492 ftell_fail:
1493         _mmcam_dbg_err("ftell() returns negative value.");
1494         fclose(f);
1495         return FALSE;
1496 }