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