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