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