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