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