fea07bfc79d802d41a2ccea66cb21fb723a04100
[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 *temp_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                         guint imax_size = 0;
541                         guint imax_time = 0;
542                         int ret_free_space = 0;
543                         char *dir_name = NULL;
544                         guint64 free_space = 0;
545                         int file_system_type = 0;
546                         int root_directory_length = 0;
547
548                         /* Recording */
549                         _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
550
551 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
552                         _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
553
554                         /* prepare resource manager for H/W encoder */
555                         if (hcamcorder->video_encoder_resource == NULL) {
556                                 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
557                                                 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
558                                                 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
559                                                 &hcamcorder->video_encoder_resource);
560                                 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
561                                         _mmcam_dbg_err("could not prepare for encoder resource");
562                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
563                                         _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
564                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
565                                 }
566                         } else {
567                                 _mmcam_dbg_log("encoder already acquired");
568                         }
569
570                         /* acquire resources */
571                         ret = mm_resource_manager_commit(hcamcorder->resource_manager);
572                         if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
573                                 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
574
575                                 _mmcam_dbg_err("could not acquire resources");
576
577                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
578                         }
579
580                         _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
581 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
582
583                         /* init record_dual_stream */
584                         info->record_dual_stream = FALSE;
585
586                         ret = mm_camcorder_get_attributes(handle, &err_name,
587                                 MMCAM_CAMERA_FPS, &fps,
588                                 MMCAM_CAMERA_WIDTH, &(info->preview_width),
589                                 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
590                                 MMCAM_VIDEO_WIDTH, &(info->video_width),
591                                 MMCAM_VIDEO_HEIGHT, &(info->video_height),
592                                 MMCAM_FILE_FORMAT, &fileformat,
593                                 MMCAM_TARGET_FILENAME, &temp_filename, &size,
594                                 MMCAM_TARGET_MAX_SIZE, &imax_size,
595                                 MMCAM_TARGET_TIME_LIMIT, &imax_time,
596                                 MMCAM_FILE_FORMAT, &(info->fileformat),
597                                 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
598                                 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
599                                 NULL);
600                         if (ret != MM_ERROR_NONE) {
601                                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
602                                 SAFE_FREE(err_name);
603                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
604                         }
605
606                         if (!temp_filename && !hcamcorder->mstream_cb) {
607                                 _mmcam_dbg_err("filename is not set and muxed stream cb is NULL");
608                                 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
609                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
610                         }
611
612                         /* set max size */
613                         if (imax_size <= 0)
614                                 info->max_size = 0; /* do not check */
615                         else
616                                 info->max_size = ((guint64)imax_size) << 10; /* to byte */
617
618                         /* set max time */
619                         if (imax_time <= 0)
620                                 info->max_time = 0; /* do not check */
621                         else
622                                 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
623
624                         dir_name = g_path_get_dirname(temp_filename);
625                         if (dir_name) {
626                                 ret = _mmcamcorder_get_storage_info(dir_name, hcamcorder->root_directory, &hcamcorder->storage_info);
627                                 if (ret != 0) {
628                                         _mmcam_dbg_err("get storage info failed");
629                                         g_free(dir_name);
630                                         dir_name = NULL;
631                                         return MM_ERROR_OUT_OF_STORAGE;
632                                 }
633
634                                 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
635
636                                 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
637
638                                 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
639                                         /* MSDOS_SUPER_MAGIC : 0x4d44 */
640                                         if (file_system_type == MSDOS_SUPER_MAGIC &&
641                                             (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
642                                                 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %lu",
643                                                         info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
644                                                 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
645                                         } else {
646                                                 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
647                                                         file_system_type, info->max_size);
648                                         }
649                                 } else {
650                                         _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
651                                 }
652
653                                 g_free(dir_name);
654                                 dir_name = NULL;
655                         } else {
656                                 _mmcam_dbg_err("failed to get directory name");
657                                 ret_free_space = -1;
658                         }
659
660                         if (temp_filename &&
661                                 (ret_free_space == -1 || free_space <= _MMCAMCORDER_VIDEO_MINIMUM_SPACE)) {
662                                 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
663                                         ret_free_space, free_space, _MMCAMCORDER_VIDEO_MINIMUM_SPACE);
664                                 return MM_ERROR_OUT_OF_STORAGE;
665                         }
666
667                         g_mutex_lock(&hcamcorder->task_thread_lock);
668                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
669                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
670                                 /* Play record start sound */
671                                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
672                         }
673                         g_mutex_unlock(&hcamcorder->task_thread_lock);
674
675                         _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
676
677                         if (info->video_width == 0 || info->video_height == 0) {
678                                 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
679                                         info->video_width, info->video_height, info->preview_width, info->preview_height);
680                                 info->video_width = info->preview_width;
681                                 info->video_height = info->preview_height;
682                         }
683
684                         if (info->support_dual_stream) {
685                                 _mmcam_dbg_warn("DUAL STREAM MODE");
686
687                                 info->record_dual_stream = TRUE;
688
689                                 /* No need to restart preview */
690                                 info->restart_preview = FALSE;
691
692                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
693                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
694                         } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
695                                 info->preview_width == info->video_width &&
696                                 info->preview_height == info->video_height) {
697                                 _mmcam_dbg_log("H264 preview mode and same resolution");
698
699                                 /* No need to restart preview */
700                                 info->restart_preview = FALSE;
701                         } else {
702                                 /* always need to restart preview  */
703                                 info->restart_preview = TRUE;
704                         }
705
706                         /* set recording hint */
707                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
708
709                         if (info->restart_preview) {
710                                 /* stop preview and set new size */
711                                 _mmcam_dbg_log("restart preview");
712
713                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
714                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
715                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
716
717                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
718
719                                 /* check decoder recreation */
720                                 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
721                                         _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
722                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
723                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
724                                 }
725
726                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
727                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
728                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
729
730                                 if (ret != MM_ERROR_NONE)
731                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
732
733                                 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
734                                         ret = MM_ERROR_CAMCORDER_INTERNAL;
735                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
736                                 }
737
738                                 /* Start preview again with new setting */
739                                 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
740                                 if (ret != MM_ERROR_NONE)
741                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
742
743                                 if (motion_rate < 1.0) {
744                                         _mmcam_dbg_warn("wait for stabilization of frame");
745                                         usleep(300000);
746                                 }
747                         } else {
748                                 _mmcam_dbg_log("no need to restart preview");
749                         }
750
751                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
752                                 CONFIGURE_CATEGORY_MAIN_RECORD,
753                                 "DropVideoFrame",
754                                 &(sc->drop_vframe));
755
756                         _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
757                                 CONFIGURE_CATEGORY_MAIN_RECORD,
758                                 "PassFirstVideoFrame",
759                                 &(sc->pass_first_vframe));
760
761                         _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
762                                 sc->drop_vframe, sc->pass_first_vframe);
763
764                         info->record_drop_count = (guint)motion_rate;
765                         info->record_motion_rate = motion_rate;
766                         if (sc->is_modified_rate)
767                                 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
768                         else
769                                 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
770
771                         _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
772                                 fps, info->record_motion_rate, info->record_timestamp_ratio);
773
774                         /* set push buffer flag */
775                         info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
776                         info->base_video_ts = 0;
777
778                         /* connect video stream cb signal */
779                         /*130826 Connect video stream cb for handling fast record frame cb*/
780                         if (info->record_dual_stream) {
781                                 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
782                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
783                         }
784
785                         /* start video stream */
786                         if (info->record_dual_stream) {
787                                 CameraControl =  GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
788                                 if (CameraControl) {
789                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
790
791                                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
792                                         gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
793
794                                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
795                                 } else {
796                                         _mmcam_dbg_err("could not get camera control");
797                                 }
798                         }
799
800                         /* check pre-created encode pipeline */
801                         g_mutex_lock(&hcamcorder->task_thread_lock);
802                         if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
803                             hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
804                                 /* create encoding pipeline */
805                                 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
806                                 if (ret != MM_ERROR_NONE) {
807                                         g_mutex_unlock(&hcamcorder->task_thread_lock);
808                                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
809                                 }
810                         }
811                         g_mutex_unlock(&hcamcorder->task_thread_lock);
812
813                         /* check recording start sound */
814                         _mmcamcorder_sound_solo_play_wait(handle);
815
816                         /**< To fix video recording hanging
817                                 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
818                                 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
819                                  basetime wouldn't change if you set (GstClockTime)0.
820                                 3. Move set start time position below PAUSED of pipeline.
821                         */
822                         /*
823                         gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
824                         gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
825                         */
826
827                         info->video_frame_count = 0;
828                         info->is_firstframe = TRUE;
829                         info->audio_frame_count = 0;
830                         info->filesize = 0;
831                         sc->ferror_send = FALSE;
832                         sc->ferror_count = 0;
833                         hcamcorder->error_occurs = FALSE;
834                         sc->bget_eos = FALSE;
835                         sc->muxed_stream_offset = 0;
836
837                         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
838                         if (ret != MM_ERROR_NONE) {
839                                 /* stop video stream */
840                                 if (info->record_dual_stream) {
841                                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
842                                         if (CameraControl) {
843                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
844
845                                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
846                                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
847
848                                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
849                                         } else {
850                                                 _mmcam_dbg_err("failed to get camera control");
851                                         }
852                                 }
853
854                                 /* Remove recorder pipeline and recording file which size maybe zero */
855                                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
856                                 if (info->filename) {
857                                         _mmcam_dbg_log("file delete(%s)", info->filename);
858                                         unlink(info->filename);
859                                 }
860                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
861                         }
862
863                         /*set the camera control to create the GOP so that video record will get a new key frame*/
864                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
865                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
866                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
867                                 controls = gst_camera_control_list_channels(CameraControl);
868                                 if (controls != NULL) {
869                                         for (item = controls ; item && item->data ; item = item->next) {
870                                                 CameraControlChannel = item->data;
871                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
872                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
873                                                         /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
874                                                         break;
875                                                 }
876                                         }
877
878                                         if (item == NULL)
879                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
880                                 }
881                         } else {
882                                 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
883                                         sc->info_image->preview_format);
884                         }
885                 } else {
886                         /* Resume case */
887
888                         if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
889                             GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
890                                 /* generate and I-frame on resuming */
891                                 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
892                                 controls = gst_camera_control_list_channels(CameraControl);
893                                 if (controls != NULL) {
894                                         for (item = controls ; item && item->data ; item = item->next) {
895                                                 CameraControlChannel = item->data;
896                                                 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
897                                                 if (!strcmp(CameraControlChannel->label, "new-gop")) {
898                                                         /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
899                                                         break;
900                                                 }
901                                         }
902
903                                         if (item == NULL)
904                                                 _mmcam_dbg_warn("failed to find new-gop control channel");
905                                 }
906                         }
907
908                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
909
910                         _mmcam_dbg_log("Object property settings done");
911                 }
912         }
913                 break;
914         case _MMCamcorder_CMD_PAUSE:
915         {
916                 if (info->b_commiting) {
917                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
918                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
919                 }
920
921                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
922                         if (sc->audio_disable) {
923                                 /* check only video frame */
924                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
925                                         break;
926                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
927                                         _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
928                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
929                                 } else {
930                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", count, info->video_frame_count);
931                                 }
932
933                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
934                         } else {
935                                 /* check both of video and audio frame */
936                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
937                                         break;
938                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
939                                         _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
940                                                 info->video_frame_count, info->audio_frame_count);
941                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
942                                 } else {
943                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
944                                                 count, info->video_frame_count, info->audio_frame_count);
945                                 }
946
947                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
948                         }
949                 }
950
951                 /* block encodebin */
952                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
953                 break;
954         }
955         case _MMCamcorder_CMD_CANCEL:
956         {
957                 if (info->b_commiting) {
958                         _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
959                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
960                 }
961
962                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
963                         /* capturing */
964                         if (hcamcorder->capture_in_recording == FALSE) {
965                                 break;
966                         } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
967                                 _mmcam_dbg_err("Failed to Wait capture data");
968                                 hcamcorder->capture_in_recording = FALSE;
969                                 break;
970                         } else {
971                                 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
972                         }
973
974                         usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
975                 }
976
977                 /* block push buffer */
978                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
979
980                 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
981                 if (ret != MM_ERROR_NONE)
982                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
983
984                 /* set recording hint */
985                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
986
987                 /* stop video stream */
988                 if (info->record_dual_stream) {
989                         CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
990                         if (CameraControl) {
991                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
992
993                                 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
994                                 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
995
996                                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
997                         } else {
998                                 _mmcam_dbg_err("failed to get camera control");
999                         }
1000                 }
1001
1002                 if (info->restart_preview) {
1003                         /* restart preview */
1004                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1005                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1006                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1007
1008                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1009
1010                         /* check decoder recreation */
1011                         if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1012                                 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1013                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1014                         }
1015
1016                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1017                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1018                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1019
1020                         if (ret != MM_ERROR_NONE)
1021                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1022
1023                         /* reset restart_preview for inset window layout */
1024                         info->restart_preview = FALSE;
1025
1026                         if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1027                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1028                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1029                         }
1030
1031                         ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1032                         if (ret != MM_ERROR_NONE)
1033                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1034                 }
1035
1036                 /* remove target file */
1037                 if (info->filename) {
1038                         _mmcam_dbg_log("file delete(%s)", info->filename);
1039                         unlink(info->filename);
1040                 }
1041
1042                 sc->isMaxsizePausing = FALSE;
1043                 sc->isMaxtimePausing = FALSE;
1044
1045                 sc->display_interval = 0;
1046                 sc->previous_slot_time = 0;
1047                 info->video_frame_count = 0;
1048                 info->audio_frame_count = 0;
1049                 info->filesize = 0;
1050                 hcamcorder->capture_in_recording = FALSE;
1051                 break;
1052         }
1053         case _MMCamcorder_CMD_COMMIT:
1054         {
1055                 guint64 free_space;
1056
1057                 if (info->b_commiting) {
1058                         _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
1059                         return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1060                 } else {
1061                         _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
1062                         info->b_commiting = TRUE;
1063                         sc->bget_eos = FALSE;
1064                 }
1065
1066                 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1067                         if (sc->audio_disable) {
1068                                 /* check only video frame */
1069                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1070                                     hcamcorder->capture_in_recording == FALSE) {
1071                                         break;
1072                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1073                                         _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1074                                                 info->video_frame_count, hcamcorder->capture_in_recording);
1075
1076                                         if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1077                                                 _mmcam_dbg_warn("video frames are enough. keep going...");
1078                                         } else {
1079                                                 info->b_commiting = FALSE;
1080                                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1081                                         }
1082                                 } else {
1083                                         _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1084                                                 count, info->video_frame_count, hcamcorder->capture_in_recording);
1085                                 }
1086                         } else {
1087                                 /* check both of video and audio frame */
1088                                 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1089                                     info->audio_frame_count &&
1090                                     hcamcorder->capture_in_recording == FALSE) {
1091                                         break;
1092                                 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1093                                         _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1094                                                 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1095
1096                                         if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1097                                                 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1098                                         } else {
1099                                                 info->b_commiting = FALSE;
1100                                                 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1101                                         }
1102
1103                                         return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1104                                 } else {
1105                                         _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1106                                                 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1107                                 }
1108                         }
1109
1110                         if (hcamcorder->capture_in_recording) {
1111                                 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1112                                 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1113                                         _mmcam_dbg_warn("timeout");
1114                         } else {
1115                                 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1116                         }
1117                 }
1118
1119                 /* block push buffer */
1120                 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1121                 _mmcam_dbg_log("block push buffer to appsrc");
1122
1123                 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1124                 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1125                         _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1126                         ret = MM_ERROR_OUT_OF_STORAGE;
1127                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1128                 }
1129
1130                 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1131                         if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1132                                 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1133                         } else {
1134                                 _mmcam_dbg_err("VIDEO: send EOS failed");
1135                                 info->b_commiting = FALSE;
1136                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1137                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1138                         }
1139                 } else {
1140                         _mmcam_dbg_err("No video stream source");
1141                         info->b_commiting = FALSE;
1142                         ret = MM_ERROR_CAMCORDER_INTERNAL;
1143                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1144                 }
1145
1146                 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1147                         if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1148                                 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1149                         } else {
1150                                 _mmcam_dbg_err("AUDIO: send EOS failed");
1151                                 info->b_commiting = FALSE;
1152                                 ret = MM_ERROR_CAMCORDER_INTERNAL;
1153                                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1154                         }
1155                 } else {
1156                         _mmcam_dbg_log("No audio stream");
1157                 }
1158
1159                 /* sc */
1160                 sc->display_interval = 0;
1161                 sc->previous_slot_time = 0;
1162
1163                 /* Wait EOS */
1164                 _mmcam_dbg_log("Start to wait EOS");
1165                 ret = _mmcamcorder_get_eos_message(handle);
1166                 if (ret != MM_ERROR_NONE) {
1167                         info->b_commiting = FALSE;
1168                         goto _ERR_CAMCORDER_VIDEO_COMMAND;
1169                 }
1170
1171                 /* reset flag */
1172                 hcamcorder->capture_in_recording = FALSE;
1173         }
1174                 break;
1175         default:
1176                 ret =  MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1177                 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1178         }
1179
1180         return MM_ERROR_NONE;
1181
1182 _ERR_CAMCORDER_VIDEO_COMMAND:
1183         if (command == _MMCamcorder_CMD_RECORD)
1184                 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1185
1186         return ret;
1187 }
1188
1189
1190 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1191 {
1192         int ret = MM_ERROR_NONE;
1193         int enabletag = 0;
1194         guint64 file_size = 0;
1195
1196         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1197         _MMCamcorderSubContext *sc = NULL;
1198         _MMCamcorderVideoInfo *info = NULL;
1199         _MMCamcorderMsgItem msg;
1200         MMCamRecordingReport *report = NULL;
1201
1202         mmf_return_val_if_fail(hcamcorder, FALSE);
1203
1204         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1205         mmf_return_val_if_fail(sc, FALSE);
1206         mmf_return_val_if_fail(sc->info_video, FALSE);
1207
1208         info = sc->info_video;
1209
1210         _mmcam_dbg_err("");
1211
1212         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1213                 /* Play record stop sound */
1214                 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1215         } else {
1216                 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1217
1218                 _mmcamcorder_sound_init(handle);
1219
1220                 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1221
1222                 _mmcamcorder_sound_finalize(handle);
1223         }
1224
1225         /* remove blocking part */
1226         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1227
1228         mm_camcorder_get_attributes(handle, NULL,
1229                 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1230                 NULL);
1231
1232         ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1233         if (ret != MM_ERROR_NONE)
1234                 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1235
1236         /* set recording hint */
1237         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1238
1239         /* stop video stream */
1240         if (info->record_dual_stream) {
1241                 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1242                 if (control) {
1243                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1244
1245                         _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1246                         gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1247
1248                         MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1249                 } else {
1250                         _mmcam_dbg_err("failed to get camera control");
1251                 }
1252         }
1253
1254         if (enabletag && !(sc->ferror_send)) {
1255                 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1256                 _mmcam_dbg_log("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1257         }
1258
1259         /* Check file size */
1260         if (info->max_size > 0) {
1261                 _mmcamcorder_get_file_size(info->filename, &file_size);
1262                 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1263                                            info->max_size, file_size);
1264
1265                 if (file_size > info->max_size) {
1266                         _MMCamcorderMsgItem message;
1267                         _mmcam_dbg_err("File size is greater than max size !!");
1268                         message.id = MM_MESSAGE_CAMCORDER_ERROR;
1269                         message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1270                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1271                 }
1272         }
1273
1274         if (info->restart_preview) {
1275                 /* block queue */
1276                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1277                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1278                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1279
1280                 _mmcam_dbg_log("Set state of pipeline as READY");
1281                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1282
1283                 /* check decoder recreation */
1284                 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1285                         _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1286                         ret = MM_ERROR_CAMCORDER_INTERNAL;
1287                 }
1288
1289                 /* unblock queue */
1290                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1291                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1292                 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1293
1294                 if (ret != MM_ERROR_NONE) {
1295                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1296                         msg.param.code = ret;
1297                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1298                         _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1299                 }
1300
1301                 /* reset restart_preview for inset window layout */
1302                 info->restart_preview = FALSE;
1303
1304                 /* recover preview size */
1305                 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1306                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1307                         msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1308                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1309                         _mmcam_dbg_err("Failed to set camera resolution %dx%d",
1310                                 info->preview_width, info->preview_height);
1311                 }
1312
1313                 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1314                 /* Do not return when error is occurred.
1315                    Recording file was created successfully, but starting pipeline failed */
1316                 if (ret != MM_ERROR_NONE) {
1317                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1318                         msg.param.code = ret;
1319                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1320                         _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1321                 }
1322         } else {
1323                 _mmcam_dbg_log("No need to restart preview");
1324         }
1325
1326         /* Send recording report to application */
1327         msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1328         report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1329         if (!report) {
1330                 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1331         } else {
1332                 report->recording_filename = g_strdup(info->filename);
1333                 msg.param.data = report;
1334                 msg.param.code = 1;
1335                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1336         }
1337
1338         /* Finishing */
1339         sc->pipeline_time = 0;
1340         sc->pause_time = 0;
1341         sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1342         sc->isMaxtimePausing = FALSE;
1343         hcamcorder->error_occurs = FALSE;
1344
1345         info->video_frame_count = 0;
1346         info->audio_frame_count = 0;
1347         info->filesize = 0;
1348         info->b_commiting = FALSE;
1349
1350         if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1351                 /* check recording stop sound */
1352                 _mmcamcorder_sound_solo_play_wait(handle);
1353         }
1354
1355         _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1356
1357         return TRUE;
1358 }
1359
1360
1361 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1362 {
1363         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1364         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1365         GstMapInfo mapinfo;
1366         _MMCamcorderSubContext *sc = NULL;
1367         _MMCamcorderVideoInfo *videoinfo = NULL;
1368         _MMCamcorderMsgItem msg;
1369         guint64 buffer_size = 0;
1370         guint64 trailer_size = 0;
1371         guint64 max_size = 0;
1372
1373         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1374         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1375         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1376
1377         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1378         videoinfo = sc->info_video;
1379
1380         /* get buffer size */
1381         if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1382                 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1383                 return GST_PAD_PROBE_OK;
1384         }
1385
1386         buffer_size = mapinfo.size;
1387         gst_buffer_unmap(buffer, &mapinfo);
1388
1389         /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1390
1391         g_mutex_lock(&videoinfo->size_check_lock);
1392
1393         if (videoinfo->audio_frame_count == 0) {
1394                 videoinfo->filesize += buffer_size;
1395                 videoinfo->audio_frame_count++;
1396                 g_mutex_unlock(&videoinfo->size_check_lock);
1397                 return GST_PAD_PROBE_OK;
1398         }
1399
1400         if (sc->ferror_send || sc->isMaxsizePausing) {
1401                 _mmcam_dbg_warn("Recording is paused, drop frames");
1402                 g_mutex_unlock(&videoinfo->size_check_lock);
1403                 return GST_PAD_PROBE_DROP;
1404         }
1405
1406         /* get trailer size */
1407         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1408                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1409         else
1410                 trailer_size = 0;
1411
1412         /* check max size of recorded file */
1413         max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1414         if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1415                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1416                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1417                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1418                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1419                         " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1420                         videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1421
1422                 if (!sc->isMaxsizePausing) {
1423                         sc->isMaxsizePausing = TRUE;
1424                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1425                         if (pipeline_state == GST_STATE_PLAYING)
1426                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1427
1428                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1429                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1430                 }
1431
1432                 g_mutex_unlock(&videoinfo->size_check_lock);
1433
1434                 return FALSE;
1435         }
1436
1437         videoinfo->filesize += buffer_size;
1438         videoinfo->audio_frame_count++;
1439
1440         g_mutex_unlock(&videoinfo->size_check_lock);
1441
1442         return GST_PAD_PROBE_OK;
1443 }
1444
1445
1446 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1447 {
1448         gint ret = 0;
1449         guint vq_size = 0;
1450         guint aq_size = 0;
1451         guint64 free_space = 0;
1452         guint64 buffer_size = 0;
1453         guint64 trailer_size = 0;
1454         guint64 queued_buffer = 0;
1455         guint64 max_size = 0;
1456         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1457         GstMapInfo mapinfo;
1458         storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1459
1460         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1461         _MMCamcorderMsgItem msg;
1462         _MMCamcorderSubContext *sc = NULL;
1463         _MMCamcorderVideoInfo *videoinfo = NULL;
1464
1465         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1466         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1467
1468         sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1469         mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1470         videoinfo = sc->info_video;
1471
1472         /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1473         if (sc->ferror_send) {
1474                 _mmcam_dbg_warn("file write error, drop frames");
1475                 return GST_PAD_PROBE_DROP;
1476         }
1477
1478         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1479         buffer_size = mapinfo.size;
1480         gst_buffer_unmap(buffer, &mapinfo);
1481
1482         videoinfo->video_frame_count++;
1483         if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1484                 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1485                         info->video_frame_count); */
1486                 g_mutex_lock(&videoinfo->size_check_lock);
1487                 videoinfo->filesize += buffer_size;
1488                 g_mutex_unlock(&videoinfo->size_check_lock);
1489                 return GST_PAD_PROBE_OK;
1490         }
1491
1492         /* get trailer size */
1493         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1494                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1495         else
1496                 trailer_size = 0;
1497
1498         /* check free space */
1499         ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1500         if (ret != 0) {
1501                 _mmcam_dbg_err("Error occured. [%d]", ret);
1502                 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1503                         sc->ferror_send = TRUE;
1504
1505                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1506                         msg.param.code = MM_ERROR_FILE_READ;
1507
1508                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1509                 } else {
1510                         sc->ferror_count++;
1511                 }
1512
1513                 return GST_PAD_PROBE_DROP; /* skip this buffer */
1514         }
1515
1516         if (free_space == 0) {
1517                 /* check storage state */
1518                 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1519
1520                 _mmcam_dbg_warn("storage state %d", storage_state);
1521
1522                 if (storage_state == STORAGE_STATE_REMOVED ||
1523                         storage_state == STORAGE_STATE_UNMOUNTABLE) {
1524                         _mmcam_dbg_err("storage was removed!");
1525
1526                         _MMCAMCORDER_LOCK(hcamcorder);
1527
1528                         if (sc->ferror_send == FALSE) {
1529                                 _mmcam_dbg_err("OUT_OF_STORAGE error");
1530
1531                                 sc->ferror_send = TRUE;
1532
1533                                 _MMCAMCORDER_UNLOCK(hcamcorder);
1534
1535                                 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1536                                 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1537
1538                                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1539                         } else {
1540                                 _MMCAMCORDER_UNLOCK(hcamcorder);
1541                                 _mmcam_dbg_warn("error was already sent");
1542                         }
1543
1544                         return GST_PAD_PROBE_DROP;
1545                 }
1546         }
1547
1548         /* get queued buffer size */
1549         if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1550                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1551
1552         if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1553                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1554
1555         queued_buffer = aq_size + vq_size;
1556
1557         if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1558                 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1559                 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1560                         " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1561                         free_space, trailer_size, buffer_size, queued_buffer);
1562
1563                 if (!sc->isMaxsizePausing) {
1564                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1565                         sc->isMaxsizePausing = TRUE;
1566
1567                         msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1568                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1569                 }
1570
1571                 return GST_PAD_PROBE_DROP;
1572         }
1573
1574         g_mutex_lock(&videoinfo->size_check_lock);
1575
1576         /* check max size of recorded file */
1577         max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1578         if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1579                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1580                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1581                 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1582                 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1583                         " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1584                         videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1585
1586                 if (!sc->isMaxsizePausing) {
1587                         sc->isMaxsizePausing = TRUE;
1588                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1589                         if (pipeline_state == GST_STATE_PLAYING)
1590                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1591
1592                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1593                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1594                 }
1595
1596                 g_mutex_unlock(&videoinfo->size_check_lock);
1597
1598                 return GST_PAD_PROBE_DROP;
1599         }
1600
1601         videoinfo->filesize += (guint64)buffer_size;
1602
1603         /*
1604         _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1605         */
1606
1607         g_mutex_unlock(&videoinfo->size_check_lock);
1608
1609         return GST_PAD_PROBE_OK;
1610 }
1611
1612
1613 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1614 {
1615         guint64 trailer_size = 0;
1616         guint64 rec_pipe_time = 0;
1617         unsigned int remained_time = 0;
1618
1619         GstClockTime b_time;
1620
1621         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1622         _MMCamcorderMsgItem msg;
1623         _MMCamcorderSubContext *sc = NULL;
1624         _MMCamcorderVideoInfo *videoinfo = NULL;
1625
1626         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1627
1628         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1629         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1630
1631         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1632         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1633         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1634
1635         videoinfo = sc->info_video;
1636
1637         b_time = GST_BUFFER_PTS(buffer);
1638
1639         rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1640
1641         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1642                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1643         else
1644                 trailer_size = 0;
1645
1646         /* check max time */
1647         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1648                 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1649                         rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1650
1651                 if (!sc->isMaxtimePausing) {
1652                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1653
1654                         sc->isMaxtimePausing = TRUE;
1655
1656                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1657                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1658                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1659                         msg.param.recording_status.remained_time = 0;
1660                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1661
1662                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1663                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1664                 }
1665
1666                 return GST_PAD_PROBE_DROP;
1667         }
1668
1669         /* calculate remained time can be recorded */
1670         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1671                 remained_time = videoinfo->max_time - rec_pipe_time;
1672         } else if (videoinfo->max_size > 0) {
1673                 long double max_size = (long double)videoinfo->max_size;
1674                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1675
1676                 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1677         }
1678
1679         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1680         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1681         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1682         msg.param.recording_status.remained_time = remained_time;
1683         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1684
1685         /*
1686         _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1687                 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1688         */
1689
1690         if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1691                 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1692
1693                 /*
1694                 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1695                         record_motion_rate, videoinfo->record_drop_count);
1696                 */
1697
1698                 /* drop some frame if fast motion */
1699                 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1700                         if (record_motion_rate != (videoinfo->record_drop_count++)) {
1701                                 /*
1702                                 _mmcam_dbg_warn("drop frame");
1703                                 */
1704                                 return GST_PAD_PROBE_DROP;
1705                         }
1706
1707                         videoinfo->record_drop_count = 1;
1708                         /*
1709                         _mmcam_dbg_warn("pass frame");
1710                         */
1711                 }
1712
1713                 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1714                 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1715         }
1716
1717         return GST_PAD_PROBE_OK;
1718 }
1719
1720
1721 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1722 {
1723         _MMCamcorderMsgItem msg;
1724         guint64 trailer_size = 0;
1725         guint64 rec_pipe_time = 0;
1726         _MMCamcorderSubContext *sc = NULL;
1727         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1728         _MMCamcorderVideoInfo *videoinfo = NULL;
1729         unsigned int remained_time = 0;
1730         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1731
1732         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1733         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1734         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1735
1736         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1737         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1738         mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1739
1740         videoinfo = sc->info_video;
1741
1742         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1743                 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1744                 return GST_PAD_PROBE_OK;
1745         }
1746
1747         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1748
1749         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1750                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1751         else
1752                 trailer_size = 0;
1753
1754         /* calculate remained time can be recorded */
1755         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1756                 remained_time = videoinfo->max_time - rec_pipe_time;
1757         } else if (videoinfo->max_size > 0) {
1758                 long double max_size = (long double)videoinfo->max_size;
1759                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1760
1761                 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1762         }
1763
1764         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1765                 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1766                         rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1767
1768                 if (!sc->isMaxtimePausing) {
1769                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1770
1771                         sc->isMaxtimePausing = TRUE;
1772
1773                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1774                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1775                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1776                         msg.param.recording_status.remained_time = 0;
1777                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1778
1779                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1780                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1781                 }
1782
1783                 return GST_PAD_PROBE_DROP;
1784         }
1785
1786         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1787         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1788         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1789         msg.param.recording_status.remained_time = remained_time;
1790         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1791
1792         /*
1793         _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1794                 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1795         */
1796
1797         return GST_PAD_PROBE_OK;
1798 }
1799
1800
1801 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1802 {
1803         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1804         double volume = 0.0;
1805         int format = 0;
1806         int channel = 0;
1807         int err = MM_ERROR_UNKNOWN;
1808         char *err_name = NULL;
1809         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1810         GstMapInfo mapinfo;
1811
1812         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1813         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1814
1815         /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1816         err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1817                 MMCAM_AUDIO_VOLUME, &volume,
1818                 MMCAM_AUDIO_FORMAT, &format,
1819                 MMCAM_AUDIO_CHANNEL, &channel,
1820                 NULL);
1821         if (err != MM_ERROR_NONE) {
1822                 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1823                 SAFE_FREE(err_name);
1824                 return err;
1825         }
1826
1827         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1828
1829         gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1830
1831         /* Set audio stream NULL */
1832         if (volume == 0.0)
1833                 memset(mapinfo.data, 0, mapinfo.size);
1834
1835         /* CALL audio stream callback */
1836         if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1837                 MMCamcorderAudioStreamDataType stream;
1838
1839                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1840                         _mmcam_dbg_warn("Not ready for stream callback");
1841                         gst_buffer_unmap(buffer, &mapinfo);
1842                         return GST_PAD_PROBE_OK;
1843                 }
1844
1845                 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1846                         GST_BUFFER_DATA(buffer), width, height, format);*/
1847
1848                 stream.data = (void *)mapinfo.data;
1849                 stream.format = format;
1850                 stream.channel = channel;
1851                 stream.length = mapinfo.size;
1852                 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1853
1854                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1855
1856                 if (hcamcorder->astream_cb)
1857                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1858
1859                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1860         }
1861
1862         gst_buffer_unmap(buffer, &mapinfo);
1863         return GST_PAD_PROBE_OK;
1864 }
1865
1866
1867 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1868 {
1869         gboolean bret = FALSE;
1870
1871         switch (fileformat) {
1872         case MM_FILE_FORMAT_3GP:
1873         case MM_FILE_FORMAT_MP4:
1874                 bret = __mmcamcorder_add_metadata_mp4(handle);
1875                 break;
1876         default:
1877                 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1878                 break;
1879         }
1880
1881         return bret;
1882 }
1883
1884
1885 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1886 {
1887         FILE *f = NULL;
1888         guchar buf[4];
1889         guint64 udta_size = 0;
1890         gint64 current_pos = 0;
1891         gint64 moov_pos = 0;
1892         gint64 udta_pos = 0;
1893         gdouble longitude = 0;
1894         gdouble latitude = 0;
1895         gdouble altitude = 0;
1896         int err = 0;
1897         int orientation = 0;
1898         int gps_enable = 0;
1899         char *err_name = NULL;
1900         char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1901         _MMCamcorderLocationInfo location_info = {0, 0, 0};
1902         _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1903
1904         _MMCamcorderVideoInfo *info = NULL;
1905         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1906         _MMCamcorderSubContext *sc = NULL;
1907
1908         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1909         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1910
1911         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1912         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1913
1914         _mmcam_dbg_log("");
1915
1916         info = sc->info_video;
1917
1918         f = fopen64(info->filename, "rb+");
1919         if (f == NULL) {
1920                 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1921                 _mmcam_dbg_err("file open failed [%s]", err_msg);
1922                 return FALSE;
1923         }
1924
1925         mm_camcorder_get_attributes(handle, &err_name,
1926                 MMCAM_TAG_LATITUDE, &latitude,
1927                 MMCAM_TAG_LONGITUDE, &longitude,
1928                 MMCAM_TAG_ALTITUDE, &altitude,
1929                 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1930                 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1931                 NULL);
1932         if (err_name) {
1933                 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1934                 SAFE_FREE(err_name);
1935         }
1936
1937         location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1938         location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1939         location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1940         geo_info.longitude = longitude *10000;
1941         geo_info.latitude = latitude *10000;
1942         geo_info.altitude = altitude *10000;
1943         /* find udta container.
1944            if, there are udta container, write loci box after that
1945            else, make udta container and write loci box. */
1946         if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1947                 size_t nread = 0;
1948
1949                 _mmcam_dbg_log("find udta container");
1950
1951                 /* read size */
1952                 if (fseek(f, -8L, SEEK_CUR) != 0)
1953                         goto fail;
1954
1955                 udta_pos = ftello(f);
1956                 if (udta_pos < 0)
1957                         goto ftell_fail;
1958
1959                 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1960
1961                 _mmcam_dbg_log("recorded file fread %d", nread);
1962
1963                 udta_size = _mmcamcorder_get_container_size(buf);
1964
1965                 /* goto end of udta and write 'loci' box */
1966                 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1967                         goto fail;
1968
1969                 if (gps_enable) {
1970                         if (!_mmcamcorder_write_loci(f, location_info)) {
1971                                 _mmcam_dbg_err("failed to write loci");
1972                                 goto fail;
1973                         }
1974
1975                         if (!_mmcamcorder_write_geodata(f, geo_info)) {
1976                                 _mmcam_dbg_err("failed to write geodata");
1977                                 goto fail;
1978                         }
1979                 }
1980
1981                 current_pos = ftello(f);
1982                 if (current_pos < 0)
1983                         goto ftell_fail;
1984
1985                 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1986                         goto fail;
1987         } else {
1988                 _mmcam_dbg_log("No udta container");
1989                 if (fseek(f, 0, SEEK_END) != 0)
1990                         goto fail;
1991
1992                 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1993                         _mmcam_dbg_err("failed to write udta");
1994                         goto fail;
1995                 }
1996         }
1997
1998         /* find moov container.
1999            update moov container size. */
2000         if ((current_pos = ftello(f)) < 0)
2001                 goto ftell_fail;
2002
2003         if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
2004                 gint64 internal_pos = ftello(f);
2005
2006                 _mmcam_dbg_log("found moov container");
2007                 if (fseek(f, -8L, SEEK_CUR) != 0)
2008                         goto fail;
2009
2010                 moov_pos = ftello(f);
2011                 if (moov_pos < 0)
2012                         goto ftell_fail;
2013
2014                 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2015                         goto fail;
2016
2017                 /* add orientation info */
2018                 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2019                         _mmcam_dbg_err("fseeko failed : errno %d", errno);
2020                         goto fail;
2021                 }
2022
2023                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2024                         _mmcam_dbg_err("failed to find [trak] tag");
2025                         goto fail;
2026                 }
2027
2028                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2029                         _mmcam_dbg_err("failed to find [tkhd] tag");
2030                         goto fail;
2031                 }
2032
2033                 _mmcam_dbg_log("found [tkhd] tag");
2034
2035                 /* seek to start position of composition matrix */
2036                 if (fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2037                         /* update composition matrix for orientation */
2038                         _mmcamcorder_update_composition_matrix(f, orientation);
2039                 } else {
2040                         _mmcam_dbg_err("fseek failed : errno %d", errno);
2041                         goto fail;
2042                 }
2043         } else {
2044                 _mmcam_dbg_err("No 'moov' container");
2045                 goto fail;
2046         }
2047
2048         fclose(f);
2049         return TRUE;
2050
2051 fail:
2052         fclose(f);
2053         return FALSE;
2054
2055 ftell_fail:
2056         _mmcam_dbg_err("ftell() returns negative value.");
2057         fclose(f);
2058         return FALSE;
2059 }
2060
2061
2062 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2063 {
2064         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2065         _MMCamcorderSubContext *sc = NULL;
2066
2067         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2068
2069         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2070         mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2071
2072         /* check video source element */
2073         if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2074                 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2075                 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2076                         _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2077                         G_CALLBACK(__mmcamcorder_video_stream_cb),
2078                         hcamcorder);
2079                 return MM_ERROR_NONE;
2080         } else {
2081                 _mmcam_dbg_err("videosrc element is not created yet");
2082                 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2083         }
2084 }
2085
2086
2087 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2088 {
2089         int ret = MM_ERROR_NONE;
2090         int size = 0;
2091         char *temp_filename = NULL;
2092
2093         _MMCamcorderVideoInfo *info = NULL;
2094         _MMCamcorderSubContext *sc = NULL;
2095         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2096
2097         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2098
2099         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2100         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2101         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2102
2103         info = sc->info_video;
2104
2105         _mmcam_dbg_warn("start");
2106
2107         /* create encoding pipeline */
2108         ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2109         if (ret != MM_ERROR_NONE)
2110                 goto _ERR_PREPARE_RECORD;
2111
2112         SAFE_G_FREE(info->filename);
2113
2114         mm_camcorder_get_attributes(handle, NULL,
2115                 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2116                 NULL);
2117         if (temp_filename) {
2118                 info->filename = g_strdup(temp_filename);
2119                 if (!info->filename) {
2120                         _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2121                         goto _ERR_PREPARE_RECORD;
2122                 }
2123
2124                 _mmcam_dbg_log("Record file name [%s]", info->filename);
2125                 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2126         } else {
2127                 _mmcam_dbg_log("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2128                 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2129         }
2130
2131         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2132
2133         /* Adjust display FPS */
2134         sc->display_interval = 0;
2135         sc->previous_slot_time = 0;
2136
2137         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2138         if (ret != MM_ERROR_NONE)
2139                 goto _ERR_PREPARE_RECORD;
2140
2141         _mmcam_dbg_warn("done");
2142
2143         return ret;
2144
2145 _ERR_PREPARE_RECORD:
2146         /* Remove recorder pipeline and recording file which size maybe zero */
2147         _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2148         if (info && info->filename) {
2149                 _mmcam_dbg_log("file delete(%s)", info->filename);
2150                 unlink(info->filename);
2151         }
2152
2153         return ret;
2154 }