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