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