5acb1efb75d32b219d242bdcbd49f7b353343dd0
[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                                         g_free(dir_name);
561                                         dir_name = NULL;
562                                         return MM_ERROR_OUT_OF_STORAGE;
563                                 }
564
565                                 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
566
567                                 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
568
569                                 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
570                                         /* MSDOS_SUPER_MAGIC : 0x4d44 */
571                                         if (file_system_type == MSDOS_SUPER_MAGIC &&
572                                             (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
573                                                 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
574                                                         info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
575                                                 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
576                                         } else {
577                                                 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
578                                                         file_system_type, info->max_size);
579                                         }
580                                 } else {
581                                         _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
582                                 }
583
584                                 g_free(dir_name);
585                                 dir_name = NULL;
586                         } else {
587                                 _mmcam_dbg_err("failed to get directory name");
588                                 ret_free_space = -1;
589                         }
590
591                         if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
592                                 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
593                                         ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
594                                 return MM_ERROR_OUT_OF_STORAGE;
595                         }
596
597                         g_mutex_lock(&hcamcorder->task_thread_lock);
598                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
599                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
600                                 /* Play record start sound */
601                                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
602                         }
603                         g_mutex_unlock(&hcamcorder->task_thread_lock);
604
605                         _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
606
607                         if (info->video_width == 0 || info->video_height == 0) {
608                                 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
609                                         info->video_width, info->video_height, info->preview_width, info->preview_height);
610                                 info->video_width = info->preview_width;
611                                 info->video_height = info->preview_height;
612                         }
613
614                         if (info->support_dual_stream) {
615                                 _mmcam_dbg_warn("DUAL STREAM MODE");
616
617                                 info->record_dual_stream = TRUE;
618
619                                 /* No need to restart preview */
620                                 info->restart_preview = FALSE;
621
622                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
623                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
624                         } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
625                                 info->preview_width == info->video_width &&
626                                 info->preview_height == info->video_height) {
627                                 _mmcam_dbg_log("H264 preview mode and same resolution");
628
629                                 /* No need to restart preview */
630                                 info->restart_preview = FALSE;
631                         } else {
632                                 /* always need to restart preview  */
633                                 info->restart_preview = TRUE;
634                         }
635
636                         /* set recording hint */
637                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
638
639                         if (info->restart_preview) {
640                                 /* stop preview and set new size */
641                                 _mmcam_dbg_log("restart preview");
642
643                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
644                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
645                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
646
647                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
648
649                                 /* check decoder recreation */
650                                 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
651                                         _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
652                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
653                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
654                                 }
655
656                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
657                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
658                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
659
660                                 if (ret != MM_ERROR_NONE)
661                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
662
663                                 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
664                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
665                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
666                                 }
667
668                                 /* Start preview again with new setting */
669                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
670                                 if (ret != MM_ERROR_NONE)
671                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
672
673                                 if (motion_rate < 1.0) {
674                                         _mmcam_dbg_warn("wait for stabilization of frame");
675                                         usleep(300000);
676                                 }
677                         } else {
678                                 _mmcam_dbg_log("no need to restart preview");
679                         }
680
681                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
682                                 CONFIGURE_CATEGORY_MAIN_RECORD,
683                                 "DropVideoFrame",
684                                 &(sc->drop_vframe));
685
686                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
687                                 CONFIGURE_CATEGORY_MAIN_RECORD,
688                                 "PassFirstVideoFrame",
689                                 &(sc->pass_first_vframe));
690
691                         _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
692                                 sc->drop_vframe, sc->pass_first_vframe);
693
694                         info->record_drop_count = (guint)motion_rate;
695                         info->record_motion_rate = motion_rate;
696                         if (sc->is_modified_rate)
697                                 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
698                         else
699                                 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
700
701                         _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
702                                 fps, info->record_motion_rate, info->record_timestamp_ratio);
703
704                         /* set push buffer flag */
705                         info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
706                         info->base_video_ts = 0;
707
708                         /* connect video stream cb signal */
709                         /*130826 Connect video stream cb for handling fast record frame cb*/
710                         if (info->record_dual_stream) {
711                                 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
712                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
713                         }
714
715                         /* start video stream */
716                         if (info->record_dual_stream) {
717                                 CameraControl =  GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
718                                 if (CameraControl) {
719                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
720
721                                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
722                                         gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
723
724                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
725                                 } else {
726                                         _mmcam_dbg_err("could not get camera control");
727                                 }
728                         }
729
730                         /* check pre-created encode pipeline */
731                         g_mutex_lock(&hcamcorder->task_thread_lock);
732                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
733                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
734                                 /* create encoding pipeline */
735                                 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
736                                 if (ret != MM_ERROR_NONE) {
737                                         g_mutex_unlock(&hcamcorder->task_thread_lock);
738                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
739                                 }
740                         }
741                         g_mutex_unlock(&hcamcorder->task_thread_lock);
742
743                         /* check recording start sound */
744                         _mmcamcorder_sound_solo_play_wait(handle);
745
746                         /**< To fix video recording hanging
747                                 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
748                                 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
749                                  basetime wouldn't change if you set (GstClockTime)0.
750                                 3. Move set start time position below PAUSED of pipeline.
751                         */
752                         /*
753                         gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
754                         gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
755                         */
756
757                         info->video_frame_count = 0;
758                         info->is_firstframe = TRUE;
759                         info->audio_frame_count = 0;
760                         info->filesize = 0;
761                         sc->ferror_send = FALSE;
762                         sc->ferror_count = 0;
763                         hcamcorder->error_occurs = FALSE;
764                         sc->bget_eos = FALSE;
765
766                         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
767                         if (ret != MM_ERROR_NONE) {
768                                 /* stop video stream */
769                                 if (info->record_dual_stream) {
770                                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
771                                         if (CameraControl) {
772                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
773
774                                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
775                                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
776
777                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
778                                         } else {
779                                                 _mmcam_dbg_err("failed to get camera control");
780                                         }
781                                 }
782
783                                 /* Remove recorder pipeline and recording file which size maybe zero */
784                                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
785                                 if (info->filename) {
786                                         _mmcam_dbg_log("file delete(%s)", info->filename);
787                                         unlink(info->filename);
788                                 }
789                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
790                         }
791
792                         /*set the camera control to create the GOP so that video record will get a new key frame*/
793                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
794                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
795                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
796                                 controls = gst_camera_control_list_channels(CameraControl);
797                                 if (controls != NULL) {
798                                         for (item = controls ; item && item->data ; item = item->next) {
799                                                 CameraControlChannel = item->data;
800                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
801                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
802                                                         /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
803                                                         break;
804                                                 }
805                                         }
806
807                                         if (item == NULL)
808                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
809                                 }
810                         } else {
811                                 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
812                                         sc->info_image->preview_format);
813                         }
814                 } else {
815                         /* Resume case */
816
817                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
818                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
819                                 /* generate and I-frame on resuming */
820                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
821                                 controls = gst_camera_control_list_channels(CameraControl);
822                                 if (controls != NULL) {
823                                         for (item = controls ; item && item->data ; item = item->next) {
824                                                 CameraControlChannel = item->data;
825                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
826                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
827                                                         /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
828                                                         break;
829                                                 }
830                                         }
831
832                                         if (item == NULL)
833                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
834                                 }
835                         }
836
837                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
838
839                         _mmcam_dbg_log("Object property settings done");
840                 }
841         }
842                 break;
843         case _MMCamcorder_CMD_PAUSE:
844         {
845                 if (info->b_commiting) {
846                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
847                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
848                 }
849
850                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
851                         if (sc->audio_disable) {
852                                 /* check only video frame */
853                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
854                                         break;
855                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
856                                         _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
857                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
858                                 } else {
859                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", count, info->video_frame_count);
860                                 }
861
862                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
863                         } else {
864                                 /* check both of video and audio frame */
865                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
866                                         break;
867                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
868                                         _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
869                                                 info->video_frame_count, info->audio_frame_count);
870                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
871                                 } else {
872                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
873                                                 count, info->video_frame_count, info->audio_frame_count);
874                                 }
875
876                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
877                         }
878                 }
879
880                 /* block encodebin */
881                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
882                 break;
883         }
884         case _MMCamcorder_CMD_CANCEL:
885         {
886                 if (info->b_commiting) {
887                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
888                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
889                 }
890
891                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
892                         /* capturing */
893                         if (hcamcorder->capture_in_recording == FALSE) {
894                                 break;
895                         } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
896                                 _mmcam_dbg_err("Failed to Wait capture data");
897                                 hcamcorder->capture_in_recording = FALSE;
898                                 break;
899                         } else {
900                                 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
901                         }
902
903                         usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
904                 }
905
906                 /* block push buffer */
907                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
908
909                 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
910                 if (ret != MM_ERROR_NONE)
911                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
912
913                 /* set recording hint */
914                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
915
916                 /* stop video stream */
917                 if (info->record_dual_stream) {
918                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
919                         if (CameraControl) {
920                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
921
922                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
923                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
924
925                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
926                         } else {
927                                 _mmcam_dbg_err("failed to get camera control");
928                         }
929                 }
930
931                 if (info->restart_preview) {
932                         /* restart preview */
933                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
934                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
935                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
936
937                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
938
939                         /* check decoder recreation */
940                         if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
941                                 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
942                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
943                         }
944
945                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
946                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
947                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
948
949                         if (ret != MM_ERROR_NONE)
950                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
951
952                         /* reset restart_preview for inset window layout */
953                         info->restart_preview = FALSE;
954
955                         if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
956                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
957                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
958                         }
959
960                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
961                         if (ret != MM_ERROR_NONE)
962                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
963                 }
964
965                 /* remove target file */
966                 if (info->filename) {
967                         _mmcam_dbg_log("file delete(%s)", info->filename);
968                         unlink(info->filename);
969                 }
970
971                 sc->isMaxsizePausing = FALSE;
972                 sc->isMaxtimePausing = FALSE;
973
974                 sc->display_interval = 0;
975                 sc->previous_slot_time = 0;
976                 info->video_frame_count = 0;
977                 info->audio_frame_count = 0;
978                 info->filesize = 0;
979                 hcamcorder->capture_in_recording = FALSE;
980                 break;
981         }
982         case _MMCamcorder_CMD_COMMIT:
983         {
984                 if (info->b_commiting) {
985                         _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
986                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
987                 } else {
988                         _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
989                         info->b_commiting = TRUE;
990                         sc->bget_eos = FALSE;
991                 }
992
993                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
994                         if (sc->audio_disable) {
995                                 /* check only video frame */
996                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
997                                     hcamcorder->capture_in_recording == FALSE) {
998                                         break;
999                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1000                                         _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1001                                                 info->video_frame_count, hcamcorder->capture_in_recording);
1002
1003                                         if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1004                                                 _mmcam_dbg_warn("video frames are enough. keep going...");
1005                                         } else {
1006                                                 info->b_commiting = FALSE;
1007                                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1008                                         }
1009                                 } else {
1010                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1011                                                 count, info->video_frame_count, hcamcorder->capture_in_recording);
1012                                 }
1013                         } else {
1014                                 /* check both of video and audio frame */
1015                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1016                                     info->audio_frame_count &&
1017                                     hcamcorder->capture_in_recording == FALSE) {
1018                                         break;
1019                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1020                                         _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1021                                                 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1022
1023                                         if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1024                                                 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1025                                         } else {
1026                                                 info->b_commiting = FALSE;
1027                                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1028                                         }
1029
1030                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1031                                 } else {
1032                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1033                                                 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1034                                 }
1035                         }
1036
1037                         if (hcamcorder->capture_in_recording) {
1038                                 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1039                                 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1040                                         _mmcam_dbg_warn("signal received");
1041                                 } else {
1042                                         _mmcam_dbg_warn("timeout");
1043                                 }
1044                         } else {
1045                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1046                         }
1047                 }
1048
1049                 /* block push buffer */
1050                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1051                 _mmcam_dbg_log("block push buffer to appsrc");
1052
1053                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1054                         if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1055                                 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1056                         } else {
1057                                 _mmcam_dbg_err("VIDEO: send EOS failed");
1058                                 info->b_commiting = FALSE;
1059                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1060                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1061                         }
1062                 } else {
1063                         _mmcam_dbg_err("No video stream source");
1064                         info->b_commiting = FALSE;
1065                         ret = MM_ERROR_CAMCORDER_INTERNAL;
1066                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1067                 }
1068
1069                 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1070                         if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1071                                 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1072                         } else {
1073                                 _mmcam_dbg_err("AUDIO: send EOS failed");
1074                                 info->b_commiting = FALSE;
1075                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1076                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1077                         }
1078                 } else {
1079                         _mmcam_dbg_log("No audio stream");
1080                 }
1081
1082                 /* sc */
1083                 sc->display_interval = 0;
1084                 sc->previous_slot_time = 0;
1085
1086                 /* Wait EOS */
1087                 _mmcam_dbg_log("Start to wait EOS");
1088                 ret = _mmcamcorder_get_eos_message(handle);
1089                 if (ret != MM_ERROR_NONE) {
1090                         info->b_commiting = FALSE;
1091                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1092                 }
1093
1094                 /* reset flag */
1095                 hcamcorder->capture_in_recording = FALSE;
1096         }
1097                 break;
1098         default:
1099                 ret =  MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1100                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1101         }
1102
1103         return MM_ERROR_NONE;
1104
1105 _ERR_CAMCORDER_VIDEO_COMMAND:
1106         if (command == _MMCamcorder_CMD_RECORD)
1107                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1108
1109         return ret;
1110 }
1111
1112
1113 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1114 {
1115         int ret = MM_ERROR_NONE;
1116         int enabletag = 0;
1117         guint64 file_size = 0;
1118
1119         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1120         _MMCamcorderSubContext *sc = NULL;
1121         _MMCamcorderVideoInfo *info = NULL;
1122         _MMCamcorderMsgItem msg;
1123         MMCamRecordingReport *report = NULL;
1124
1125         mmf_return_val_if_fail(hcamcorder, FALSE);
1126
1127         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1128         mmf_return_val_if_fail(sc, FALSE);
1129         mmf_return_val_if_fail(sc->info_video, FALSE);
1130
1131         info = sc->info_video;
1132
1133         _mmcam_dbg_err("");
1134
1135         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1136                 /* Play record stop sound */
1137                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1138         } else {
1139                 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1140
1141                 _mmcamcorder_sound_init(handle);
1142
1143                 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1144
1145                 _mmcamcorder_sound_finalize(handle);
1146         }
1147
1148         /* remove blocking part */
1149         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1150
1151         mm_camcorder_get_attributes(handle, NULL,
1152                 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1153                 NULL);
1154
1155         ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1156         if (ret != MM_ERROR_NONE)
1157                 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1158
1159         /* set recording hint */
1160         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1161
1162         /* stop video stream */
1163         if (info->record_dual_stream) {
1164                 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1165                 if (control) {
1166                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1167
1168                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1169                         gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1170
1171                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1172                 } else {
1173                         _mmcam_dbg_err("failed to get camera control");
1174                 }
1175         }
1176
1177         if (enabletag && !(sc->ferror_send)) {
1178                 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1179                 if (ret) {
1180                         _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1181                 } else {
1182                         _mmcam_dbg_err("Writing location information FAILED !!");
1183                 }
1184         }
1185
1186         /* Check file size */
1187         if (info->max_size > 0) {
1188                 _mmcamcorder_get_file_size(info->filename, &file_size);
1189                 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1190                                            info->max_size, file_size);
1191
1192                 if (file_size > info->max_size) {
1193                         _MMCamcorderMsgItem message;
1194                         _mmcam_dbg_err("File size is greater than max size !!");
1195                         message.id = MM_MESSAGE_CAMCORDER_ERROR;
1196                         message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1197                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1198                 }
1199         }
1200
1201         if (info->restart_preview) {
1202                 /* block queue */
1203                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1204                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1205                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1206
1207                 _mmcam_dbg_log("Set state of pipeline as READY");
1208                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1209
1210                 /* check decoder recreation */
1211                 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1212                         _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1213                         ret = MM_ERROR_CAMCORDER_INTERNAL;
1214                 }
1215
1216                 /* unblock queue */
1217                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1218                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1219                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1220
1221                 if (ret != MM_ERROR_NONE) {
1222                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1223                         msg.param.code = ret;
1224                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1225                         _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1226                 }
1227
1228                 /* reset restart_preview for inset window layout */
1229                 info->restart_preview = FALSE;
1230
1231                 /* recover preview size */
1232                 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1233
1234                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1235                 /* Do not return when error is occurred.
1236                    Recording file was created successfully, but starting pipeline failed */
1237                 if (ret != MM_ERROR_NONE) {
1238                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1239                         msg.param.code = ret;
1240                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1241                         _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1242                 }
1243         } else {
1244                 _mmcam_dbg_log("No need to restart preview");
1245         }
1246
1247         /* Send recording report to application */
1248         msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1249         report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1250         if (!report) {
1251                 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1252         } else {
1253                 report->recording_filename = g_strdup(info->filename);
1254                 msg.param.data = report;
1255                 msg.param.code = 1;
1256                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1257         }
1258
1259         /* Finishing */
1260         sc->pipeline_time = 0;
1261         sc->pause_time = 0;
1262         sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1263         sc->isMaxtimePausing = FALSE;
1264         hcamcorder->error_occurs = FALSE;
1265
1266         info->video_frame_count = 0;
1267         info->audio_frame_count = 0;
1268         info->filesize = 0;
1269         info->b_commiting = FALSE;
1270
1271         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1272                 /* check recording stop sound */
1273                 _mmcamcorder_sound_solo_play_wait(handle);
1274         }
1275
1276         _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1277
1278         return TRUE;
1279 }
1280
1281
1282 /**
1283  * This function is record video data probing function.
1284  * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1285  * this function will be called when data stream pass through the pad.
1286  *
1287  * @param[in]   pad             probing pad which calls this function.
1288  * @param[in]   buffer          buffer which contains stream data.
1289  * @param[in]   u_data          user data.
1290  * @return      This function returns true on success, or false value with error
1291  * @remarks
1292  * @see
1293  */
1294 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1295 {
1296         GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1297         switch (GST_EVENT_TYPE(event)) {
1298         case GST_EVENT_UNKNOWN:
1299         /* upstream events */
1300         case GST_EVENT_QOS:
1301         case GST_EVENT_SEEK:
1302         case GST_EVENT_NAVIGATION:
1303         case GST_EVENT_LATENCY:
1304         /* downstream serialized events */
1305         case GST_EVENT_SEGMENT:
1306         case GST_EVENT_TAG:
1307         case GST_EVENT_BUFFERSIZE:
1308                 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1309                 break;
1310         case GST_EVENT_EOS:
1311                 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1312                 break;
1313         /* bidirectional events */
1314         case GST_EVENT_FLUSH_START:
1315         case GST_EVENT_FLUSH_STOP:
1316                 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1317                 break;
1318         default:
1319                 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1320                 break;
1321         }
1322
1323         return GST_PAD_PROBE_OK;
1324 }
1325
1326
1327 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1328 {
1329         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1330         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1331         GstMapInfo mapinfo;
1332         _MMCamcorderSubContext *sc = NULL;
1333         _MMCamcorderVideoInfo *videoinfo = NULL;
1334         _MMCamcorderMsgItem msg;
1335         guint64 buffer_size = 0;
1336         guint64 trailer_size = 0;
1337         guint64 max_size = 0;
1338
1339         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1340         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1341         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1342
1343         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1344         videoinfo = sc->info_video;
1345
1346         /* get buffer size */
1347         if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1348                 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1349                 return GST_PAD_PROBE_OK;
1350         }
1351
1352         buffer_size = mapinfo.size;
1353         gst_buffer_unmap(buffer, &mapinfo);
1354
1355         /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1356
1357         g_mutex_lock(&videoinfo->size_check_lock);
1358
1359         if (videoinfo->audio_frame_count == 0) {
1360                 videoinfo->filesize += buffer_size;
1361                 videoinfo->audio_frame_count++;
1362                 g_mutex_unlock(&videoinfo->size_check_lock);
1363                 return GST_PAD_PROBE_OK;
1364         }
1365
1366         if (sc->ferror_send || sc->isMaxsizePausing) {
1367                 _mmcam_dbg_warn("Recording is paused, drop frames");
1368                 g_mutex_unlock(&videoinfo->size_check_lock);
1369                 return GST_PAD_PROBE_DROP;
1370         }
1371
1372         /* get trailer size */
1373         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1374                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1375         } else {
1376                 trailer_size = 0;
1377         }
1378
1379         /* check max size of recorded file */
1380         max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1381         if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1382                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1383                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1384                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1385                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1386                         " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1387                         videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1388
1389                 if (!sc->isMaxsizePausing) {
1390                         sc->isMaxsizePausing = TRUE;
1391                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1392                         if (pipeline_state == GST_STATE_PLAYING)
1393                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1394
1395                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1396                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1397                 }
1398
1399                 g_mutex_unlock(&videoinfo->size_check_lock);
1400
1401                 return FALSE;
1402         }
1403
1404         videoinfo->filesize += buffer_size;
1405         videoinfo->audio_frame_count++;
1406
1407         g_mutex_unlock(&videoinfo->size_check_lock);
1408
1409         return GST_PAD_PROBE_OK;
1410 }
1411
1412
1413 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1414 {
1415         gint ret = 0;
1416         guint vq_size = 0;
1417         guint aq_size = 0;
1418         guint64 free_space = 0;
1419         guint64 buffer_size = 0;
1420         guint64 trailer_size = 0;
1421         guint64 queued_buffer = 0;
1422         guint64 max_size = 0;
1423         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1424         GstMapInfo mapinfo;
1425         storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1426
1427         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1428         _MMCamcorderMsgItem msg;
1429         _MMCamcorderSubContext *sc = NULL;
1430         _MMCamcorderVideoInfo *videoinfo = NULL;
1431
1432         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1433         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1434
1435         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1436         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1437         videoinfo = sc->info_video;
1438
1439         /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1440         if (sc->ferror_send) {
1441                 _mmcam_dbg_warn("file write error, drop frames");
1442                 return GST_PAD_PROBE_DROP;
1443         }
1444
1445         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1446         buffer_size = mapinfo.size;
1447         gst_buffer_unmap(buffer, &mapinfo);
1448
1449         videoinfo->video_frame_count++;
1450         if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1451                 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1452                         info->video_frame_count); */
1453                 g_mutex_lock(&videoinfo->size_check_lock);
1454                 videoinfo->filesize += buffer_size;
1455                 g_mutex_unlock(&videoinfo->size_check_lock);
1456                 return GST_PAD_PROBE_OK;
1457         }
1458
1459         /* get trailer size */
1460         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1461                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1462         } else {
1463                 trailer_size = 0;
1464         }
1465
1466         /* check free space */
1467         ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1468         if (ret != 0) {
1469                 _mmcam_dbg_err("Error occured. [%d]", ret);
1470                 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1471                         sc->ferror_send = TRUE;
1472
1473                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1474                         msg.param.code = MM_ERROR_FILE_READ;
1475
1476                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1477                 } else {
1478                         sc->ferror_count++;
1479                 }
1480
1481                 return GST_PAD_PROBE_DROP; /* skip this buffer */
1482         }
1483
1484         if (free_space == 0) {
1485                 /* check storage state */
1486                 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1487
1488                 _mmcam_dbg_warn("storage state %d", storage_state);
1489
1490                 if (storage_state == STORAGE_STATE_REMOVED ||
1491                         storage_state == STORAGE_STATE_UNMOUNTABLE) {
1492                         _mmcam_dbg_err("storage was removed!");
1493
1494                         _MMCAMCORDER_LOCK(hcamcorder);
1495
1496                         if (sc->ferror_send == FALSE) {
1497                                 _mmcam_dbg_err("OUT_OF_STORAGE error");
1498
1499                                 sc->ferror_send = TRUE;
1500
1501                                 _MMCAMCORDER_UNLOCK(hcamcorder);
1502
1503                                 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1504                                 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1505
1506                                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1507                         } else {
1508                                 _MMCAMCORDER_UNLOCK(hcamcorder);
1509                                 _mmcam_dbg_warn("error was already sent");
1510                         }
1511
1512                         return GST_PAD_PROBE_DROP;
1513                 }
1514         }
1515
1516         /* get queued buffer size */
1517         if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1518                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1519         }
1520
1521         if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1522                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1523         }
1524
1525         queued_buffer = aq_size + vq_size;
1526
1527         if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1528                 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1529                 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1530                         " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1531                         free_space, trailer_size, buffer_size, queued_buffer);
1532
1533                 if (!sc->isMaxsizePausing) {
1534                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1535                         sc->isMaxsizePausing = TRUE;
1536
1537                         msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1538                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1539                 }
1540
1541                 return GST_PAD_PROBE_DROP;
1542         }
1543
1544         g_mutex_lock(&videoinfo->size_check_lock);
1545
1546         /* check max size of recorded file */
1547         max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1548         if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1549                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1550                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1551                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1552                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1553                         " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1554                         videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1555
1556                 if (!sc->isMaxsizePausing) {
1557                         sc->isMaxsizePausing = TRUE;
1558                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1559                         if (pipeline_state == GST_STATE_PLAYING)
1560                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1561
1562                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1563                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1564                 }
1565
1566                 g_mutex_unlock(&videoinfo->size_check_lock);
1567
1568                 return GST_PAD_PROBE_DROP;
1569         }
1570
1571         videoinfo->filesize += (guint64)buffer_size;
1572
1573         /*
1574         _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1575         */
1576
1577         g_mutex_unlock(&videoinfo->size_check_lock);
1578
1579         return GST_PAD_PROBE_OK;
1580 }
1581
1582
1583 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1584 {
1585         guint64 trailer_size = 0;
1586         guint64 rec_pipe_time = 0;
1587         unsigned int remained_time = 0;
1588
1589         GstClockTime b_time;
1590
1591         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1592         _MMCamcorderMsgItem msg;
1593         _MMCamcorderSubContext *sc = NULL;
1594         _MMCamcorderVideoInfo *videoinfo = NULL;
1595
1596         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1597
1598         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1599         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1600
1601         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1602         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1603         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1604
1605         videoinfo = sc->info_video;
1606
1607         b_time = GST_BUFFER_PTS(buffer);
1608
1609         rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1610
1611         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1612                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1613         } else {
1614                 trailer_size = 0;
1615         }
1616
1617         /* check max time */
1618         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1619                 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1620                         rec_pipe_time, videoinfo->max_time);
1621
1622                 if (!sc->isMaxtimePausing) {
1623                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1624
1625                         sc->isMaxtimePausing = TRUE;
1626
1627                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1628                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1629                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1630                         msg.param.recording_status.remained_time = 0;
1631                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1632
1633                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1634                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1635                 }
1636
1637                 return GST_PAD_PROBE_DROP;
1638         }
1639
1640         /* calculate remained time can be recorded */
1641         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1642                 remained_time = videoinfo->max_time - rec_pipe_time;
1643         } else if (videoinfo->max_size > 0) {
1644                 long double max_size = (long double)videoinfo->max_size;
1645                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1646
1647                 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1648         }
1649
1650         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1651         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1652         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1653         msg.param.recording_status.remained_time = remained_time;
1654         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1655
1656         /*
1657         _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1658                 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1659         */
1660
1661         if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1662                 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1663
1664                 /*
1665                 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1666                         record_motion_rate, videoinfo->record_drop_count);
1667                 */
1668
1669                 /* drop some frame if fast motion */
1670                 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1671                         if (record_motion_rate != (videoinfo->record_drop_count++)) {
1672                                 /*
1673                                 _mmcam_dbg_warn("drop frame");
1674                                 */
1675                                 return GST_PAD_PROBE_DROP;
1676                         }
1677
1678                         videoinfo->record_drop_count = 1;
1679                         /*
1680                         _mmcam_dbg_warn("pass frame");
1681                         */
1682                 }
1683
1684                 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1685         }
1686
1687         return GST_PAD_PROBE_OK;
1688 }
1689
1690
1691 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1692 {
1693         _MMCamcorderMsgItem msg;
1694         guint64 trailer_size = 0;
1695         guint64 rec_pipe_time = 0;
1696         _MMCamcorderSubContext *sc = NULL;
1697         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1698         _MMCamcorderVideoInfo *videoinfo = NULL;
1699         unsigned int remained_time = 0;
1700         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1701
1702         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1703         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1704         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1705
1706         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1707         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1708         mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1709
1710         videoinfo = sc->info_video;
1711
1712         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1713                 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1714                 return GST_PAD_PROBE_OK;
1715         }
1716
1717         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1718
1719         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1720                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1721         } else {
1722                 trailer_size = 0;
1723         }
1724
1725         /* calculate remained time can be recorded */
1726         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1727                 remained_time = videoinfo->max_time - rec_pipe_time;
1728         } else if (videoinfo->max_size > 0) {
1729                 long double max_size = (long double)videoinfo->max_size;
1730                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1731
1732                 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1733         }
1734
1735         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1736                 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1737                         rec_pipe_time, videoinfo->max_time);
1738
1739                 if (!sc->isMaxtimePausing) {
1740                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1741
1742                         sc->isMaxtimePausing = TRUE;
1743
1744                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1745                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1746                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1747                         msg.param.recording_status.remained_time = 0;
1748                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1749
1750                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1751                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1752                 }
1753
1754                 return GST_PAD_PROBE_DROP;
1755         }
1756
1757         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1758         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1759         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1760         msg.param.recording_status.remained_time = remained_time;
1761         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1762
1763         /*
1764         _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1765                 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1766         */
1767
1768         return GST_PAD_PROBE_OK;
1769 }
1770
1771
1772 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1773 {
1774         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1775         double volume = 0.0;
1776         int format = 0;
1777         int channel = 0;
1778         int err = MM_ERROR_UNKNOWN;
1779         char *err_name = NULL;
1780         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1781         GstMapInfo mapinfo;
1782
1783         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1784         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1785
1786         /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1787         err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1788                 MMCAM_AUDIO_VOLUME, &volume,
1789                 MMCAM_AUDIO_FORMAT, &format,
1790                 MMCAM_AUDIO_CHANNEL, &channel,
1791                 NULL);
1792         if (err != MM_ERROR_NONE) {
1793                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1794                 SAFE_FREE(err_name);
1795                 return err;
1796         }
1797
1798         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1799
1800         gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1801
1802         /* Set audio stream NULL */
1803         if (volume == 0.0)
1804                 memset(mapinfo.data, 0, mapinfo.size);
1805
1806         /* CALL audio stream callback */
1807         if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1808                 MMCamcorderAudioStreamDataType stream;
1809
1810                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1811                         _mmcam_dbg_warn("Not ready for stream callback");
1812                         gst_buffer_unmap(buffer, &mapinfo);
1813                         return GST_PAD_PROBE_OK;
1814                 }
1815
1816                 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1817                         GST_BUFFER_DATA(buffer), width, height, format);*/
1818
1819                 stream.data = (void *)mapinfo.data;
1820                 stream.format = format;
1821                 stream.channel = channel;
1822                 stream.length = mapinfo.size;
1823                 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1824
1825                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1826
1827                 if (hcamcorder->astream_cb)
1828                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1829
1830                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1831         }
1832
1833         gst_buffer_unmap(buffer, &mapinfo);
1834         return GST_PAD_PROBE_OK;
1835 }
1836
1837
1838 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1839 {
1840         gboolean bret = FALSE;
1841
1842         switch (fileformat) {
1843         case MM_FILE_FORMAT_3GP:
1844         case MM_FILE_FORMAT_MP4:
1845                 bret = __mmcamcorder_add_metadata_mp4(handle);
1846                 break;
1847         default:
1848                 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1849                 break;
1850         }
1851
1852         return bret;
1853 }
1854
1855
1856 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1857 {
1858         FILE *f = NULL;
1859         guchar buf[4];
1860         guint64 udta_size = 0;
1861         gint64 current_pos = 0;
1862         gint64 moov_pos = 0;
1863         gint64 udta_pos = 0;
1864         gdouble longitude = 0;
1865         gdouble latitude = 0;
1866         gdouble altitude = 0;
1867         int err = 0;
1868         int orientation = 0;
1869         int gps_enable = 0;
1870         char *err_name = NULL;
1871         char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1872         _MMCamcorderLocationInfo location_info = {0, 0, 0};
1873         _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1874
1875         _MMCamcorderVideoInfo *info = NULL;
1876         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1877         _MMCamcorderSubContext *sc = NULL;
1878
1879         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1880         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1881
1882         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1883         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1884
1885         _mmcam_dbg_log("");
1886
1887         info = sc->info_video;
1888
1889         f = fopen64(info->filename, "rb+");
1890         if (f == NULL) {
1891                 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1892                 _mmcam_dbg_err("file open failed [%s]", err_msg);
1893                 return FALSE;
1894         }
1895
1896         mm_camcorder_get_attributes(handle, &err_name,
1897                 MMCAM_TAG_LATITUDE, &latitude,
1898                 MMCAM_TAG_LONGITUDE, &longitude,
1899                 MMCAM_TAG_ALTITUDE, &altitude,
1900                 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1901                 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1902                 NULL);
1903         if (err_name) {
1904                 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1905                 SAFE_FREE(err_name);
1906         }
1907
1908         location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1909         location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1910         location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1911         geo_info.longitude = longitude *10000;
1912         geo_info.latitude = latitude *10000;
1913         geo_info.altitude = altitude *10000;
1914         /* find udta container.
1915            if, there are udta container, write loci box after that
1916            else, make udta container and write loci box. */
1917         if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1918                 size_t nread = 0;
1919
1920                 _mmcam_dbg_log("find udta container");
1921
1922                 /* read size */
1923                 if (fseek(f, -8L, SEEK_CUR) != 0)
1924                         goto fail;
1925
1926                 udta_pos = ftello(f);
1927                 if (udta_pos < 0)
1928                         goto ftell_fail;
1929
1930                 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1931
1932                 _mmcam_dbg_log("recorded file fread %d", nread);
1933
1934                 udta_size = _mmcamcorder_get_container_size(buf);
1935
1936                 /* goto end of udta and write 'loci' box */
1937                 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1938                         goto fail;
1939
1940                 if (gps_enable) {
1941                         if (!_mmcamcorder_write_loci(f, location_info)) {
1942                                 _mmcam_dbg_err("failed to write loci");
1943                                 goto fail;
1944                         }
1945
1946                         if (!_mmcamcorder_write_geodata(f, geo_info)) {
1947                                 _mmcam_dbg_err("failed to write geodata");
1948                                 goto fail;
1949                         }
1950                 }
1951
1952                 current_pos = ftello(f);
1953                 if (current_pos < 0)
1954                         goto ftell_fail;
1955
1956                 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1957                         goto fail;
1958         } else {
1959                 _mmcam_dbg_log("No udta container");
1960                 if (fseek(f, 0, SEEK_END) != 0)
1961                         goto fail;
1962
1963                 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1964                         _mmcam_dbg_err("failed to write udta");
1965                         goto fail;
1966                 }
1967         }
1968
1969         /* find moov container.
1970            update moov container size. */
1971         if ((current_pos = ftello(f)) < 0)
1972                 goto ftell_fail;
1973
1974         if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1975                 gint64 internal_pos = ftello(f);
1976
1977                 _mmcam_dbg_log("found moov container");
1978                 if (fseek(f, -8L, SEEK_CUR) != 0)
1979                         goto fail;
1980
1981                 moov_pos = ftello(f);
1982                 if (moov_pos < 0)
1983                         goto ftell_fail;
1984
1985                 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
1986                         goto fail;
1987
1988                 /* add orientation info */
1989                 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1990                         _mmcam_dbg_err("fseek failed : errno %d", errno);
1991                         goto fail;
1992                 }
1993
1994                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
1995                         _mmcam_dbg_err("failed to find [trak] tag");
1996                         goto fail;
1997                 }
1998
1999                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2000                         _mmcam_dbg_err("failed to find [tkhd] tag");
2001                         goto fail;
2002                 }
2003
2004                 _mmcam_dbg_log("found [tkhd] tag");
2005
2006                 /* seek to start position of composition matrix */
2007                 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
2008
2009                 /* update composition matrix for orientation */
2010                 _mmcamcorder_update_composition_matrix(f, orientation);
2011         } else {
2012                 _mmcam_dbg_err("No 'moov' container");
2013                 goto fail;
2014         }
2015
2016         fclose(f);
2017         return TRUE;
2018
2019 fail:
2020         fclose(f);
2021         return FALSE;
2022
2023 ftell_fail:
2024         _mmcam_dbg_err("ftell() returns negative value.");
2025         fclose(f);
2026         return FALSE;
2027 }
2028
2029
2030 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2031 {
2032         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2033         _MMCamcorderSubContext *sc = NULL;
2034
2035         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2036
2037         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2038         mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2039
2040         /* check video source element */
2041         if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2042                 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2043                 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2044                         _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2045                         G_CALLBACK(__mmcamcorder_video_stream_cb),
2046                         hcamcorder);
2047                 return MM_ERROR_NONE;
2048         } else {
2049                 _mmcam_dbg_err("videosrc element is not created yet");
2050                 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2051         }
2052 }
2053
2054
2055 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2056 {
2057         int ret = MM_ERROR_NONE;
2058
2059         _MMCamcorderVideoInfo *info = NULL;
2060         _MMCamcorderSubContext *sc = NULL;
2061         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2062
2063         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2064
2065         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2066         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2067         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2068
2069         info = sc->info_video;
2070
2071         _mmcam_dbg_warn("start");
2072
2073         /* create encoding pipeline */
2074         ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2075         if (ret != MM_ERROR_NONE)
2076                 goto _ERR_PREPARE_RECORD;
2077
2078         if (info->filename == NULL) {
2079                 char *temp_filename = NULL;
2080                 int size = 0;
2081
2082                 mm_camcorder_get_attributes(handle, NULL,
2083                         MMCAM_TARGET_FILENAME, &temp_filename, &size,
2084                         NULL);
2085                 if (temp_filename)
2086                         info->filename = g_strdup(temp_filename);
2087
2088                 if (!info->filename) {
2089                         _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2090                         goto _ERR_PREPARE_RECORD;
2091                 }
2092         }
2093
2094         _mmcam_dbg_log("Record file name [%s]", info->filename);
2095
2096         MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2097         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2098
2099         /* Adjust display FPS */
2100         sc->display_interval = 0;
2101         sc->previous_slot_time = 0;
2102
2103         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2104         if (ret != MM_ERROR_NONE)
2105                 goto _ERR_PREPARE_RECORD;
2106
2107         _mmcam_dbg_warn("done");
2108
2109         return ret;
2110
2111 _ERR_PREPARE_RECORD:
2112         /* Remove recorder pipeline and recording file which size maybe zero */
2113         _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2114         if (info && info->filename) {
2115                 _mmcam_dbg_log("file delete(%s)", info->filename);
2116                 unlink(info->filename);
2117         }
2118
2119         return ret;
2120 }