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