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