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