Fix coverity issue
[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         gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1466         buffer_size = mapinfo.size;
1467         gst_buffer_unmap(buffer, &mapinfo);
1468
1469         videoinfo->video_frame_count++;
1470         if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1471                 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1472                 g_mutex_lock(&videoinfo->size_check_lock);
1473                 videoinfo->filesize += buffer_size;
1474                 g_mutex_unlock(&videoinfo->size_check_lock);
1475                 return GST_PAD_PROBE_OK;
1476         }
1477
1478         /* get trailer size */
1479         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1480                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1481         else
1482                 trailer_size = 0;
1483
1484         /* check free space */
1485         ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1486         if (ret != 0) {
1487                 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1488                 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1489                         sc->ferror_send = TRUE;
1490
1491                         msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1492                         msg.param.code = MM_ERROR_FILE_READ;
1493
1494                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1495                 } else {
1496                         sc->ferror_count++;
1497                 }
1498
1499                 return GST_PAD_PROBE_DROP; /* skip this buffer */
1500         }
1501
1502         if (free_space == 0) {
1503                 /* check storage state */
1504                 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1505
1506                 MMCAM_LOG_WARNING("storage state %d", storage_state);
1507
1508                 if (storage_state == STORAGE_STATE_REMOVED ||
1509                         storage_state == STORAGE_STATE_UNMOUNTABLE) {
1510                         MMCAM_LOG_ERROR("storage was removed!");
1511
1512                         _MMCAMCORDER_LOCK(hcamcorder);
1513
1514                         if (sc->ferror_send == FALSE) {
1515                                 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1516
1517                                 sc->ferror_send = TRUE;
1518
1519                                 _MMCAMCORDER_UNLOCK(hcamcorder);
1520
1521                                 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1522                                 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1523
1524                                 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1525                         } else {
1526                                 _MMCAMCORDER_UNLOCK(hcamcorder);
1527                                 MMCAM_LOG_WARNING("error was already sent");
1528                         }
1529
1530                         return GST_PAD_PROBE_DROP;
1531                 }
1532         }
1533
1534         /* get queued buffer size */
1535         if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1536                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1537
1538         if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1539                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1540
1541         queued_buffer = aq_size + vq_size;
1542
1543         if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1544                 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1545                         " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1546                         free_space, trailer_size, buffer_size, queued_buffer);
1547
1548                 if (!sc->isMaxsizePausing) {
1549                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1550                         sc->isMaxsizePausing = TRUE;
1551
1552                         msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1553                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1554                 }
1555
1556                 return GST_PAD_PROBE_DROP;
1557         }
1558
1559         g_mutex_lock(&videoinfo->size_check_lock);
1560
1561         /* check max size of recorded file */
1562         max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1563         if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1564                 GstState pipeline_state = GST_STATE_VOID_PENDING;
1565                 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1566
1567                 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1568                         " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1569                         videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1570
1571                 if (!sc->isMaxsizePausing) {
1572                         sc->isMaxsizePausing = TRUE;
1573                         gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1574                         if (pipeline_state == GST_STATE_PLAYING)
1575                                 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1576
1577                         msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1578                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1579                 }
1580
1581                 g_mutex_unlock(&videoinfo->size_check_lock);
1582
1583                 return GST_PAD_PROBE_DROP;
1584         }
1585
1586         videoinfo->filesize += (guint64)buffer_size;
1587
1588         MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1589                 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1590
1591         g_mutex_unlock(&videoinfo->size_check_lock);
1592
1593         return GST_PAD_PROBE_OK;
1594 }
1595
1596
1597 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1598 {
1599         guint64 trailer_size = 0;
1600         guint64 rec_pipe_time = 0;
1601         unsigned int remained_time = 0;
1602
1603         GstClockTime b_time;
1604
1605         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1606         _MMCamcorderMsgItem msg;
1607         _MMCamcorderSubContext *sc = NULL;
1608         _MMCamcorderVideoInfo *videoinfo = NULL;
1609
1610         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1611
1612         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1613         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1614
1615         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1616         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1617         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1618
1619         videoinfo = sc->info_video;
1620
1621         b_time = GST_BUFFER_PTS(buffer);
1622
1623         rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1624
1625         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1626                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1627         else
1628                 trailer_size = 0;
1629
1630         /* check max time */
1631         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1632                 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1633                         rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1634
1635                 if (!sc->isMaxtimePausing) {
1636                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1637
1638                         sc->isMaxtimePausing = TRUE;
1639
1640                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1641                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1642                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1643                         msg.param.recording_status.remained_time = 0;
1644                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1645
1646                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1647                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1648                 }
1649
1650                 return GST_PAD_PROBE_DROP;
1651         }
1652
1653         /* calculate remained time can be recorded */
1654         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1655                 remained_time = videoinfo->max_time - rec_pipe_time;
1656         } else if (videoinfo->max_size > 0) {
1657                 long double max_size = (long double)videoinfo->max_size;
1658                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1659
1660                 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1661         }
1662
1663         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1664         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1665         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1666         msg.param.recording_status.remained_time = remained_time;
1667         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1668
1669         if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1670                 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1671
1672                 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1673                         record_motion_rate, videoinfo->record_drop_count);
1674
1675                 /* drop some frame if fast motion */
1676                 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1677                         if (record_motion_rate != (videoinfo->record_drop_count++)) {
1678                                 MMCAM_LOG_VERBOSE("drop frame");
1679                                 return GST_PAD_PROBE_DROP;
1680                         }
1681
1682                         videoinfo->record_drop_count = 1;
1683                         MMCAM_LOG_VERBOSE("pass frame");
1684                 }
1685
1686                 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1687                 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1688         }
1689
1690         return GST_PAD_PROBE_OK;
1691 }
1692
1693
1694 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1695 {
1696         _MMCamcorderMsgItem msg;
1697         guint64 trailer_size = 0;
1698         guint64 rec_pipe_time = 0;
1699         _MMCamcorderSubContext *sc = NULL;
1700         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1701         _MMCamcorderVideoInfo *videoinfo = NULL;
1702         unsigned int remained_time = 0;
1703         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1704
1705         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1706         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1707         sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1708
1709         mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1710         mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1711         mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1712
1713         videoinfo = sc->info_video;
1714
1715         if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1716                 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1717                 return GST_PAD_PROBE_OK;
1718         }
1719
1720         rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1721
1722         if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1723                 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1724         else
1725                 trailer_size = 0;
1726
1727         /* calculate remained time can be recorded */
1728         if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1729                 remained_time = videoinfo->max_time - rec_pipe_time;
1730         } else if (videoinfo->max_size > 0) {
1731                 long double max_size = (long double)videoinfo->max_size;
1732                 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1733
1734                 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1735         }
1736
1737         if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1738                 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1739                         rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1740
1741                 if (!sc->isMaxtimePausing) {
1742                         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1743
1744                         sc->isMaxtimePausing = TRUE;
1745
1746                         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1747                         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1748                         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1749                         msg.param.recording_status.remained_time = 0;
1750                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1751
1752                         msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1753                         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1754                 }
1755
1756                 return GST_PAD_PROBE_DROP;
1757         }
1758
1759         msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1760         msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1761         msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1762         msg.param.recording_status.remained_time = remained_time;
1763         _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1764
1765         MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1766                 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1767
1768         return GST_PAD_PROBE_OK;
1769 }
1770
1771
1772 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1773 {
1774         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1775         double volume = 0.0;
1776         int format = 0;
1777         int channel = 0;
1778         int err = MM_ERROR_UNKNOWN;
1779         char *err_name = NULL;
1780         GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1781         GstMapInfo mapinfo;
1782
1783         mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1784         mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1785
1786         err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1787                 MMCAM_AUDIO_VOLUME, &volume,
1788                 MMCAM_AUDIO_FORMAT, &format,
1789                 MMCAM_AUDIO_CHANNEL, &channel,
1790                 NULL);
1791         if (err != MM_ERROR_NONE) {
1792                 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1793                 SAFE_FREE(err_name);
1794                 return err;
1795         }
1796
1797         memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1798
1799         gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1800
1801         /* Set audio stream NULL */
1802         if (volume == 0.0)
1803                 memset(mapinfo.data, 0, mapinfo.size);
1804
1805         MMCAM_LOG_DEBUG("audio stream[%"GST_TIME_FORMAT"] - cb[%p], fmt[%d], ch[%d], size[%"G_GSIZE_FORMAT"]",
1806                 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), hcamcorder->astream_cb, format, channel, mapinfo.size);
1807
1808         /* CALL audio stream callback */
1809         if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1810                 MMCamcorderAudioStreamDataType stream;
1811
1812                 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1813                         MMCAM_LOG_WARNING("Not ready for stream callback");
1814                         gst_buffer_unmap(buffer, &mapinfo);
1815                         return GST_PAD_PROBE_OK;
1816                 }
1817
1818                 stream.data = (void *)mapinfo.data;
1819                 stream.format = format;
1820                 stream.channel = channel;
1821                 stream.length = mapinfo.size;
1822                 stream.timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)));
1823
1824                 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1825
1826                 if (hcamcorder->astream_cb)
1827                         hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1828
1829                 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1830         }
1831
1832         gst_buffer_unmap(buffer, &mapinfo);
1833
1834         return GST_PAD_PROBE_OK;
1835 }
1836
1837
1838 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1839 {
1840         gboolean bret = FALSE;
1841
1842         switch (fileformat) {
1843         case MM_FILE_FORMAT_3GP:
1844         case MM_FILE_FORMAT_MP4:
1845                 bret = __mmcamcorder_add_metadata_mp4(handle);
1846                 break;
1847         default:
1848                 MMCAM_LOG_WARNING("Unsupported fileformat to insert location info (%d)", fileformat);
1849                 break;
1850         }
1851
1852         return bret;
1853 }
1854
1855
1856 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1857 {
1858         FILE *f = NULL;
1859         guchar buf[4];
1860         guint64 udta_size = 0;
1861         gint64 current_pos = 0;
1862         gint64 moov_pos = 0;
1863         gint64 udta_pos = 0;
1864         gdouble longitude = 0;
1865         gdouble latitude = 0;
1866         gdouble altitude = 0;
1867         int err = 0;
1868         int orientation = 0;
1869         int gps_enable = 0;
1870         char *err_name = NULL;
1871         char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1872         _MMCamcorderLocationInfo location_info = {0, 0, 0};
1873         _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1874
1875         _MMCamcorderVideoInfo *info = NULL;
1876         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1877         _MMCamcorderSubContext *sc = NULL;
1878
1879         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1880         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1881
1882         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1883         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1884
1885         MMCAM_LOG_INFO("");
1886
1887         info = sc->info_video;
1888
1889         f = fopen64(info->filename, "rb+");
1890         if (f == NULL) {
1891                 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1892                 MMCAM_LOG_ERROR("file open failed [%s]", err_msg);
1893                 return FALSE;
1894         }
1895
1896         mm_camcorder_get_attributes(handle, &err_name,
1897                 MMCAM_TAG_LATITUDE, &latitude,
1898                 MMCAM_TAG_LONGITUDE, &longitude,
1899                 MMCAM_TAG_ALTITUDE, &altitude,
1900                 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1901                 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1902                 NULL);
1903         if (err_name) {
1904                 MMCAM_LOG_WARNING("Get tag attrs fail. (%s:%x)", err_name, err);
1905                 SAFE_FREE(err_name);
1906         }
1907
1908         location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1909         location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1910         location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1911         geo_info.longitude = longitude *10000;
1912         geo_info.latitude = latitude *10000;
1913         geo_info.altitude = altitude *10000;
1914         /* find udta container.
1915            if, there are udta container, write loci box after that
1916            else, make udta container and write loci box. */
1917         if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1918                 size_t nread = 0;
1919
1920                 MMCAM_LOG_INFO("find udta container");
1921
1922                 /* read size */
1923                 if (fseek(f, -8L, SEEK_CUR) != 0)
1924                         goto fail;
1925
1926                 udta_pos = ftello(f);
1927                 if (udta_pos < 0)
1928                         goto ftell_fail;
1929
1930                 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1931
1932                 MMCAM_LOG_INFO("recorded file fread %zu", nread);
1933
1934                 udta_size = _mmcamcorder_get_container_size(buf);
1935
1936                 /* goto end of udta and write 'loci' box */
1937                 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1938                         goto fail;
1939
1940                 if (gps_enable) {
1941                         if (!_mmcamcorder_write_loci(f, location_info)) {
1942                                 MMCAM_LOG_ERROR("failed to write loci");
1943                                 goto fail;
1944                         }
1945
1946                         if (!_mmcamcorder_write_geodata(f, geo_info)) {
1947                                 MMCAM_LOG_ERROR("failed to write geodata");
1948                                 goto fail;
1949                         }
1950                 }
1951
1952                 current_pos = ftello(f);
1953                 if (current_pos < 0)
1954                         goto ftell_fail;
1955
1956                 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1957                         goto fail;
1958         } else {
1959                 MMCAM_LOG_INFO("No udta container");
1960                 if (fseek(f, 0, SEEK_END) != 0)
1961                         goto fail;
1962
1963                 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1964                         MMCAM_LOG_ERROR("failed to write udta");
1965                         goto fail;
1966                 }
1967         }
1968
1969         /* find moov container.
1970            update moov container size. */
1971         if ((current_pos = ftello(f)) < 0)
1972                 goto ftell_fail;
1973
1974         if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1975                 gint64 internal_pos = ftello(f);
1976
1977                 MMCAM_LOG_INFO("found moov container");
1978                 if (fseek(f, -8L, SEEK_CUR) != 0)
1979                         goto fail;
1980
1981                 moov_pos = ftello(f);
1982                 if (moov_pos < 0)
1983                         goto ftell_fail;
1984
1985                 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
1986                         goto fail;
1987
1988                 /* add orientation info */
1989                 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1990                         MMCAM_LOG_ERROR("fseeko failed : errno %d", errno);
1991                         goto fail;
1992                 }
1993
1994                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
1995                         MMCAM_LOG_ERROR("failed to find [trak] tag");
1996                         goto fail;
1997                 }
1998
1999                 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2000                         MMCAM_LOG_ERROR("failed to find [tkhd] tag");
2001                         goto fail;
2002                 }
2003
2004                 MMCAM_LOG_INFO("found [tkhd] tag");
2005
2006                 /* seek to start position of composition matrix */
2007                 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2008                         /* update composition matrix for orientation */
2009                         _mmcamcorder_update_composition_matrix(f, orientation);
2010                 } else {
2011                         MMCAM_LOG_ERROR("fseek failed : errno %d", errno);
2012                         goto fail;
2013                 }
2014         } else {
2015                 MMCAM_LOG_ERROR("No 'moov' container");
2016                 goto fail;
2017         }
2018
2019         fclose(f);
2020         return TRUE;
2021
2022 fail:
2023         fclose(f);
2024         return FALSE;
2025
2026 ftell_fail:
2027         MMCAM_LOG_ERROR("ftell() returns negative value.");
2028         fclose(f);
2029         return FALSE;
2030 }
2031
2032
2033 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2034 {
2035         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2036         _MMCamcorderSubContext *sc = NULL;
2037
2038         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2039
2040         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2041         mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2042
2043         /* check video source element */
2044         if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2045                 MMCAM_LOG_WARNING("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2046                 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2047                         _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2048                         G_CALLBACK(__mmcamcorder_video_stream_cb),
2049                         hcamcorder);
2050                 return MM_ERROR_NONE;
2051         } else {
2052                 MMCAM_LOG_ERROR("videosrc element is not created yet");
2053                 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2054         }
2055 }
2056
2057
2058 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2059 {
2060         int ret = MM_ERROR_NONE;
2061         int size = 0;
2062         char *temp_filename = NULL;
2063
2064         _MMCamcorderVideoInfo *info = NULL;
2065         _MMCamcorderSubContext *sc = NULL;
2066         mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2067
2068         mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2069
2070         sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2071         mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2072         mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2073
2074         info = sc->info_video;
2075
2076         MMCAM_LOG_WARNING("start");
2077
2078         /* create encoding pipeline */
2079         ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2080         if (ret != MM_ERROR_NONE)
2081                 goto _ERR_PREPARE_RECORD;
2082
2083         SAFE_G_FREE(info->filename);
2084
2085         mm_camcorder_get_attributes(handle, NULL,
2086                 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2087                 NULL);
2088         if (temp_filename) {
2089                 info->filename = g_strdup(temp_filename);
2090                 if (!info->filename) {
2091                         MMCAM_LOG_ERROR("strdup[src:%p] was failed", temp_filename);
2092                         goto _ERR_PREPARE_RECORD;
2093                 }
2094
2095                 MMCAM_LOG_INFO("Record file name [%s]", info->filename);
2096                 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2097         } else {
2098                 MMCAM_LOG_INFO("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2099                 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2100         }
2101
2102         MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2103
2104         /* Adjust display FPS */
2105         sc->display_interval = 0;
2106         sc->previous_slot_time = 0;
2107
2108         ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2109         if (ret != MM_ERROR_NONE)
2110                 goto _ERR_PREPARE_RECORD;
2111
2112         MMCAM_LOG_WARNING("done");
2113
2114         return ret;
2115
2116 _ERR_PREPARE_RECORD:
2117         /* Remove recorder pipeline and recording file which size maybe zero */
2118         _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2119         if (info && info->filename) {
2120                 MMCAM_LOG_INFO("file delete(%s)", info->filename);
2121                 unlink(info->filename);
2122         }
2123
2124         return ret;
2125 }