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