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