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