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