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