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