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