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