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