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