4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jeongmo Yang <jm80.yang@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 /*=======================================================================================
24 =======================================================================================*/
25 #include "mm_camcorder_internal.h"
26 #include "mm_camcorder_videorec.h"
28 /*---------------------------------------------------------------------------------------
29 | GLOBAL VARIABLE DEFINITIONS for internal |
30 ---------------------------------------------------------------------------------------*/
31 #define _MMCAMCORDER_LOCATION_INFO // for add gps information
33 /*---------------------------------------------------------------------------------------
34 | LOCAL VARIABLE DEFINITIONS for internal |
35 ---------------------------------------------------------------------------------------*/
36 #define _MMCAMCORDER_MINIMUM_FRAME 10
37 #define _MMCAMCORDER_RETRIAL_COUNT 10
38 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* ms */
39 #define _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL 5
41 /*---------------------------------------------------------------------------------------
42 | LOCAL FUNCTION PROTOTYPES: |
43 ---------------------------------------------------------------------------------------*/
44 /* STATIC INTERNAL FUNCTION */
45 static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buffer, gpointer u_data);
46 static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data);
47 static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, gpointer u_data);
48 static gboolean __mmcamcorder_video_dataprobe_slow(GstPad *pad, GstBuffer *buffer, gpointer u_data);
49 static gboolean __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstBuffer *buffer, gpointer u_data);
50 static gboolean __mmcamcorder_add_locationinfo(MMHandleType handle, int fileformat);
51 static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle);
52 static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, gpointer u_data);
54 /*=======================================================================================
55 | FUNCTION DEFINITIONS |
56 =======================================================================================*/
57 /*---------------------------------------------------------------------------------------
58 | GLOBAL FUNCTION DEFINITIONS: |
59 ---------------------------------------------------------------------------------------*/
60 int _mmcamcorder_add_recorder_pipeline(MMHandleType handle)
62 int err = MM_ERROR_NONE;
63 char* gst_element_rsink_name = NULL;
65 GstPad *srcpad = NULL;
66 GstPad *sinkpad = NULL;
68 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
69 _MMCamcorderSubContext *sc = NULL;
71 type_element *RecordsinkElement = NULL;
73 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
75 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
76 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
77 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
81 err = _mmcamcorder_check_videocodec_fileformat_compatibility( handle );
82 if( err != MM_ERROR_NONE )
87 /* Create gstreamer element */
88 /* Check main pipeline */
89 if (!sc->element[_MMCAMCORDER_MAIN_PIPE].gst) {
90 err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
91 goto pipeline_creation_error;
94 if (sc->is_slow == FALSE) {
96 __ta__(" __mmcamcorder_create_audiosrc_bin",
97 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
99 if (err != MM_ERROR_NONE) {
103 gst_bin_add(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
104 sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
107 __ta__(" _mmcamcorder_create_encodesink_bin",
108 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder);
110 if (err != MM_ERROR_NONE) {
114 gst_bin_add(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
115 sc->element[_MMCAMCORDER_ENCSINK_BIN].gst);
117 /* Link each element */
118 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, "src1");
119 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
120 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
122 if (sc->is_slow == FALSE) {
123 srcpad = gst_element_get_static_pad (sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
124 sinkpad = gst_element_get_static_pad (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
125 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
128 _mmcamcorder_conf_get_element(hcamcorder->conf_main,
129 CONFIGURE_CATEGORY_MAIN_RECORD,
132 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
134 /* set data probe function */
136 /* register message cb */
138 /* set data probe function for audio */
140 if (sc->is_slow == FALSE) {
141 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
142 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
143 __mmcamcorder_audioque_dataprobe, hcamcorder);
144 gst_object_unref(sinkpad);
148 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
149 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
150 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
151 gst_object_unref(srcpad);
154 if (sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
155 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
156 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
157 __mmcamcorder_eventprobe_monitor, hcamcorder);
158 gst_object_unref(srcpad);
163 if (sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
164 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
165 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
166 __mmcamcorder_eventprobe_monitor, hcamcorder);
167 gst_object_unref(srcpad);
172 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
173 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
174 __mmcamcorder_video_dataprobe_slow, hcamcorder);
175 gst_object_unref(sinkpad);
179 if (!strcmp(gst_element_rsink_name, "filesink")) {
180 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
181 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
182 __mmcamcorder_video_dataprobe_record, hcamcorder);
183 gst_object_unref(srcpad);
186 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
187 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
188 __mmcamcorder_audio_dataprobe_check, hcamcorder);
189 gst_object_unref(srcpad);
193 return MM_ERROR_NONE;
195 pipeline_creation_error:
200 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
202 int ret = MM_ERROR_NONE;
203 GstPad *srcpad = NULL;
204 GstPad *sinkpad = NULL;
205 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
206 _MMCamcorderSubContext *sc = NULL;
208 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
210 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
211 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
212 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
216 if (sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
217 __ta__( " AudiosrcBin Set NULL",
218 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, GST_STATE_NULL);
220 if (ret != MM_ERROR_NONE) {
221 _mmcam_dbg_err("Faile to change audio source state[%d]", ret);
225 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
226 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
227 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
229 gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
230 sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
233 To avoid conflicting between old elements and newly created elements,
234 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
235 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
236 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
237 It's because the pipeline of audio recording destroys at the same time,
238 and '_mmcamcorder_element_release_noti' will perfom removing handle.
240 _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_NS);
242 _mmcam_dbg_log("Audio pipeline removed");
245 return MM_ERROR_NONE;
249 int _mmcamcorder_remove_encoder_pipeline(MMHandleType handle)
251 int ret = MM_ERROR_NONE;
252 GstPad *srcpad = NULL;
253 GstPad *sinkpad = NULL;
254 GstPad *reqpad = NULL;
255 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
256 _MMCamcorderSubContext *sc = NULL;
258 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
260 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
261 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
262 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
266 if (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst != NULL) {
267 __ta__( " EncodeBin Set NULL",
268 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, GST_STATE_NULL);
270 if (ret != MM_ERROR_NONE) {
271 _mmcam_dbg_err("Faile to change encode bin state[%d]", ret);
275 srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, "src1");
276 sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
277 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
279 /* release request pad */
280 reqpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
282 gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
283 gst_object_unref(reqpad);
287 reqpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
289 gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
290 gst_object_unref(reqpad);
294 gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst),
295 sc->element[_MMCAMCORDER_ENCSINK_BIN].gst);
298 To avoid conflicting between old elements and newly created elements,
299 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
300 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
301 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
302 It's because the pipeline of audio recording destroys at the same time,
303 and '_mmcamcorder_element_release_noti' will perfom removing handle.
305 _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_AUDIOSRC_QUE, _MMCAMCORDER_AUDIOSRC_ENC); /* Encode bin has audio encoder too. */
306 _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_ENCSINK_BIN, _MMCAMCORDER_ENCSINK_SINK);
308 _mmcam_dbg_log("Encoder pipeline removed");
311 return MM_ERROR_NONE;
315 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
317 int ret = MM_ERROR_NONE;
318 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
319 _MMCamcorderSubContext *sc = NULL;
321 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
322 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
323 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
327 if (!sc->element[_MMCAMCORDER_MAIN_PIPE].gst) {
328 _mmcam_dbg_warn("pipeline is not existed.");
329 return MM_ERROR_NONE;
332 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
334 ret = _mmcamcorder_remove_encoder_pipeline(handle);
335 if (ret != MM_ERROR_NONE) {
336 _mmcam_dbg_err("Fail to remove encoder pipeline");
340 ret = _mmcamcorder_remove_audio_pipeline(handle);
341 if (ret != MM_ERROR_NONE) {
342 _mmcam_dbg_err("Fail to remove audio pipeline");
350 void _mmcamcorder_destroy_video_pipeline(MMHandleType handle)
352 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
353 _MMCamcorderSubContext *sc = NULL;
354 GstPad *reqpad1 = NULL;
355 GstPad *reqpad2 = NULL;
357 mmf_return_if_fail(hcamcorder);
358 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
360 mmf_return_if_fail(sc);
361 mmf_return_if_fail(sc->element);
365 if (sc->element[_MMCAMCORDER_MAIN_PIPE].gst) {
366 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
367 _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_NULL);
369 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_CATEGORY_ALL);
371 reqpad1 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src0");
372 reqpad2 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src1");
373 gst_element_release_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, reqpad1);
374 gst_element_release_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, reqpad2);
375 gst_object_unref(reqpad1);
376 gst_object_unref(reqpad2);
378 /* object disposing problem happen. */
379 _mmcam_dbg_log("Reference count of pipeline(%d)", GST_OBJECT_REFCOUNT_VALUE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst));
380 gst_object_unref(sc->element[_MMCAMCORDER_MAIN_PIPE].gst);
385 int _mmcamcorder_video_command(MMHandleType handle, int command)
389 int ret = MM_ERROR_NONE;
390 char *temp_filename = NULL;
391 char *err_name = NULL;
395 GstElement *pipeline = NULL;
398 _MMCamcorderVideoInfo *info = NULL;
399 _MMCamcorderSubContext *sc = NULL;
400 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
402 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
404 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
405 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
406 mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
407 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
411 _mmcam_dbg_log("Command(%d)", command);
413 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
416 case _MMCamcorder_CMD_RECORD:
418 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
421 /* Play record start sound */
422 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_START_SND, TRUE);
425 _mmcam_dbg_log("Record Start");
427 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
428 if (ret != MM_ERROR_NONE) {
429 goto _ERR_CAMCORDER_VIDEO_COMMAND;
432 _mmcamcorder_conf_get_value_int(hcamcorder->conf_main,
433 CONFIGURE_CATEGORY_MAIN_RECORD,
437 _mmcamcorder_conf_get_value_int(hcamcorder->conf_main,
438 CONFIGURE_CATEGORY_MAIN_RECORD,
439 "PassFirstVideoFrame",
440 &(sc->pass_first_vframe));
442 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
443 sc->drop_vframe, sc->pass_first_vframe);
445 ret = mm_camcorder_get_attributes(handle, &err_name,
446 MMCAM_CAMERA_FPS, &fps,
447 "camera-slow-motion-fps", &slow_fps,
448 MMCAM_FILE_FORMAT, &fileformat,
449 MMCAM_TARGET_FILENAME, &temp_filename, &size,
450 MMCAM_TARGET_TIME_LIMIT, &imax_time,
451 MMCAM_FILE_FORMAT, &(info->fileformat),
453 if (ret != MM_ERROR_NONE) {
454 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
455 SAFE_FREE (err_name);
456 goto _ERR_CAMCORDER_VIDEO_COMMAND;
460 if (imax_time <= 0) {
461 info->max_time = 0; /* do not check */
463 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
467 info->multiple_fps = fps/slow_fps;
468 _mmcam_dbg_log("high speed recording fps:%d,slow_fps:%d,multiple_fps:%d",
469 fps, slow_fps, info->multiple_fps);
472 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", TRUE);
473 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "req-negotiation", TRUE);
475 ret =_mmcamcorder_add_recorder_pipeline((MMHandleType)hcamcorder);
476 if (ret != MM_ERROR_NONE) {
477 goto _ERR_CAMCORDER_VIDEO_COMMAND;
480 info->filename = strdup(temp_filename);
481 if (!info->filename) {
482 _mmcam_dbg_err("strdup was failed");
483 goto _ERR_CAMCORDER_VIDEO_COMMAND;
486 _mmcam_dbg_log("Record start : set file name using attribute - %s ",info->filename);
488 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
489 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
491 /* Adjust display FPS */
492 sc->display_interval = 0;
493 sc->previous_slot_time = 0;
495 /* gst_element_set_base_time(GST_ELEMENT(pipeline), (GstClockTime)0);
496 if you want to use audio clock, enable this block
497 for change recorder_pipeline state to paused. */
498 __ta__(" _MMCamcorder_CMD_RECORD:GST_STATE_PAUSED2",
499 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
501 if (ret != MM_ERROR_NONE) {
502 /* Remove recorder pipeline and recording file which size maybe zero */
503 __ta__(" record fail:remove_recorder_pipeline",
504 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
506 if (info->filename) {
507 _mmcam_dbg_log("file delete(%s)", info->filename);
508 unlink(info->filename);
509 g_free(info->filename);
510 info->filename = NULL;
512 goto _ERR_CAMCORDER_VIDEO_COMMAND;
515 /**< To fix video recording hanging
516 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
517 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
518 basetime wouldn't change if you set (GstClockTime)0.
519 3. Move set start time position below PAUSED of pipeline.
521 gst_element_set_start_time(GST_ELEMENT(pipeline), (GstClockTime)1);
522 info->video_frame_count = 0;
523 info->audio_frame_count = 0;
525 sc->ferror_send = FALSE;
526 sc->ferror_count = 0;
527 sc->error_occurs = FALSE;
528 sc->bget_eos = FALSE;
530 __ta__(" _MMCamcorder_CMD_RECORD:GST_STATE_PLAYING2",
531 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
533 if (ret != MM_ERROR_NONE) {
534 /* Remove recorder pipeline and recording file which size maybe zero */
535 __ta__(" record fail:remove_recorder_pipeline",
536 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
538 if (info->filename) {
539 _mmcam_dbg_log("file delete(%s)", info->filename);
540 unlink(info->filename);
541 g_free(info->filename);
542 info->filename = NULL;
544 goto _ERR_CAMCORDER_VIDEO_COMMAND;
550 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
552 mm_camcorder_get_attributes(handle, NULL, MMCAM_VIDEO_ENCODER, &video_enc, NULL);
553 if (video_enc == MM_VIDEO_CODEC_MPEG4) {
554 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "force-intra", TRUE);
557 _mmcam_dbg_log("Object property settings done");
561 case _MMCamcorder_CMD_PAUSE:
565 if (info->b_commiting) {
566 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
567 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
570 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
572 /* check only video frame */
573 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
575 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
576 _mmcam_dbg_err("Pause fail, frame count %" G_GUINT64_FORMAT "",
577 info->video_frame_count);
578 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
580 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %" G_GUINT64_FORMAT "",
581 count, info->video_frame_count);
584 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
586 /* check both of video and audio frame */
587 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
589 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
590 _mmcam_dbg_err("Pause fail, frame count VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
591 info->video_frame_count, info->audio_frame_count);
592 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
594 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
595 count, info->video_frame_count, info->audio_frame_count);
598 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
602 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
606 case _MMCamcorder_CMD_CANCEL:
608 if (info->b_commiting) {
609 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
610 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
613 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
614 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", FALSE);
616 if (sc->now_continuous_af) {
617 sc->now_continuous_af = FALSE;
618 _mmcam_dbg_log("Set now_continuous_af as FALSE when CANCEL recording");
621 __ta__(" _MMCamcorder_CMD_CANCEL:GST_STATE_READY",
622 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
624 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
625 if (ret != MM_ERROR_NONE) {
626 goto _ERR_CAMCORDER_VIDEO_COMMAND;
629 __ta__(" __mmcamcorder_remove_recorder_pipeline",
630 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
633 /* remove target file */
634 if (info->filename) {
635 _mmcam_dbg_log("file delete(%s)", info->filename);
636 unlink(info->filename);
637 g_free(info->filename);
638 info->filename = NULL;
641 sc->isMaxsizePausing = FALSE;
642 sc->isMaxtimePausing = FALSE;
644 sc->display_interval = 0;
645 sc->previous_slot_time = 0;
646 info->video_frame_count = 0;
647 info->audio_frame_count = 0;
650 __ta__(" _MMCamcorder_CMD_CANCEL:GST_STATE_PLAYING",
651 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
653 if (ret != MM_ERROR_NONE) {
654 goto _ERR_CAMCORDER_VIDEO_COMMAND;
659 case _MMCamcorder_CMD_COMMIT:
663 if (info->b_commiting) {
664 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
665 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
667 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
668 info->b_commiting = TRUE;
671 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
673 /* check only video frame */
674 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
676 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
677 _mmcam_dbg_err("Commit fail, frame count is %" G_GUINT64_FORMAT "",
678 info->video_frame_count);
679 info->b_commiting = FALSE;
680 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
682 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %" G_GUINT64_FORMAT "",
683 count, info->video_frame_count);
686 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
688 /* check both of video and audio frame */
689 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
691 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
692 _mmcam_dbg_err("Commit fail, VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
693 info->video_frame_count, info->audio_frame_count);
695 info->b_commiting = FALSE;
696 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
698 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
699 count, info->video_frame_count, info->audio_frame_count);
702 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
706 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", FALSE);
708 if (sc->now_continuous_af) {
709 sc->now_continuous_af = FALSE;
710 _mmcam_dbg_log("Set now_continuous_af as FALSE when COMMIT recording");
713 if (sc->error_occurs) {
715 GstPad *audio = NULL;
718 _mmcam_dbg_err("Committing Error case");
720 video = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "sink");
721 ret = gst_pad_send_event (video, gst_event_new_eos());
722 _mmcam_dbg_err("Sending EOS video sink : %d", ret);
723 gst_object_unref(video);
725 video = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
726 gst_pad_push_event (video, gst_event_new_flush_start());
727 gst_pad_push_event (video, gst_event_new_flush_stop());
728 ret = gst_pad_push_event (video, gst_event_new_eos());
729 _mmcam_dbg_err("Sending EOS video encoder src pad : %d", ret);
730 gst_object_unref(video);
733 audio = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
734 gst_pad_push_event (audio, gst_event_new_flush_start());
735 gst_pad_push_event (audio, gst_event_new_flush_stop());
736 ret = gst_element_send_event(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
737 _mmcam_dbg_err("Sending EOS audio encoder src pad : %d", ret);
738 gst_object_unref(audio);
741 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst != NULL) {
742 ret = gst_element_send_event(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, gst_event_new_eos());
743 _mmcam_dbg_warn("send eos to videosrc result : %d", ret);
746 if (sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
747 pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
748 ret = gst_element_send_event(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
749 gst_object_unref(pad);
752 _mmcam_dbg_warn("send eos to audiosrc result : %d", ret);
756 if (hcamcorder->quick_device_close) {
757 _mmcam_dbg_warn("quick_device_close");
758 /* close device quickly */
759 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "quick-device-close",TRUE);
763 sc->display_interval = 0;
764 sc->previous_slot_time = 0;
767 _mmcam_dbg_log("Start to wait EOS");
768 ret =_mmcamcorder_get_eos_message(handle);
769 if (ret != MM_ERROR_NONE) {
770 goto _ERR_CAMCORDER_VIDEO_COMMAND;
774 case _MMCamcorder_CMD_PREVIEW_START:
778 _mmcamcorder_vframe_stablize((MMHandleType)hcamcorder);
781 sc->display_interval = 0;
782 sc->previous_slot_time = 0;
784 mm_camcorder_get_attributes(handle, NULL, MMCAM_CAMERA_FPS_AUTO, &fps_auto, NULL);
786 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "fps-auto", fps_auto);
788 __ta__(" _MMCamcorder_CMD_PREVIEW_START:GST_STATE_PLAYING",
789 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
791 if (ret != MM_ERROR_NONE) {
792 goto _ERR_CAMCORDER_VIDEO_COMMAND;
795 /* I place this function last because it miscalculates a buffer that sents in GST_STATE_PAUSED */
796 _mmcamcorder_video_current_framerate_init(handle);
799 case _MMCamcorder_CMD_PREVIEW_STOP:
800 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
801 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
802 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
803 if (ret != MM_ERROR_NONE) {
804 goto _ERR_CAMCORDER_VIDEO_COMMAND;
807 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
809 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "operation-status", &op_status);
810 _mmcam_dbg_err("Current Videosrc status[0x%x]", op_status);
815 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
816 goto _ERR_CAMCORDER_VIDEO_COMMAND;
819 return MM_ERROR_NONE;
821 _ERR_CAMCORDER_VIDEO_COMMAND:
822 if (ret != MM_ERROR_NONE && sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst != NULL) {
824 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "operation-status", &op_status);
825 _mmcam_dbg_err("Current Videosrc status[0x%x]", op_status);
832 int _mmcamcorder_video_handle_eos(MMHandleType handle)
834 int ret = MM_ERROR_NONE;
836 int camcorder_rotate = MM_VIDEO_INPUT_ROTATION_NONE;
837 int camera_rotate = MM_VIDEO_INPUT_ROTATION_NONE;
838 int display_rotate = MM_DISPLAY_ROTATION_NONE;
839 guint64 file_size = 0;
842 GstElement *pipeline = NULL;
844 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
845 _MMCamcorderSubContext *sc = NULL;
846 _MMCamcorderVideoInfo *info = NULL;
847 _MMCamcorderMsgItem msg;
848 MMCamRecordingReport *report = NULL;
850 mmf_return_val_if_fail(hcamcorder, FALSE);
852 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
853 mmf_return_val_if_fail(sc, FALSE);
854 mmf_return_val_if_fail(sc->info, FALSE);
860 MMTA_ACUM_ITEM_BEGIN(" _mmcamcorder_video_handle_eos", 0);
862 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
864 /* remove blocking part */
865 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
866 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
868 _mmcam_dbg_log("Set state of pipeline as PAUSED");
869 __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_PAUSED",
870 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
872 if (ret != MM_ERROR_NONE) {
873 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:GST_STATE_PAUSED failed. error[%x]", ret);
876 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
878 __ta__(" _MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline",
879 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
881 if (ret != MM_ERROR_NONE) {
882 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
885 if (enabletag && !(sc->ferror_send)) {
886 __ta__( " _MMCamcorder_CMD_COMMIT:__mmcamcorder_add_locationinfo",
887 ret = __mmcamcorder_add_locationinfo((MMHandleType)hcamcorder, info->fileformat);
890 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
892 _mmcam_dbg_err("Writing location information FAILED !!");
896 /* Recovering camera-rotation and display-rotation when start recording */
897 if (camcorder_rotate != camera_rotate &&
898 camera_rotate < MM_VIDEO_INPUT_ROTATION_FLIP_HORZ) {
899 _mmcamcorder_set_videosrc_rotation(handle, camera_rotate);
900 _mmcamcorder_set_display_rotation(handle, display_rotate);
901 _mmcam_dbg_log("## Recovering camcorder rotation is done. camcorder_rotate=%d, camera_rotate=%d, display_rotate=%d",
902 camcorder_rotate,camera_rotate,display_rotate);
904 _mmcam_dbg_log("## No need to recover camcorder rotation. camcorder_rotate=%d, camera_rotate=%d, display_rotate=%d",
905 camcorder_rotate,camera_rotate,display_rotate);
907 /* Flush EOS event to avoid pending pipeline */
908 pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "sink");
909 gst_pad_push_event(pad, gst_event_new_flush_start());
910 gst_pad_push_event(pad, gst_event_new_flush_stop());
911 gst_object_unref(pad);
914 pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "src");
915 gst_pad_push_event(pad, gst_event_new_flush_start());
916 gst_pad_push_event(pad, gst_event_new_flush_stop());
917 gst_object_unref(pad);
921 _mmcam_dbg_log("Set state as PLAYING");
922 __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_PLAYING",
923 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
925 /* Do not return when error is occurred.
926 Recording file was created successfully, but starting pipeline failed */
927 if (ret != MM_ERROR_NONE) {
928 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
929 msg.param.code = ret;
930 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
931 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
934 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
935 /* Play record stop sound */
936 __ta__(" _MMCamcorder_CMD_COMMIT:_mmcamcorder_sound_solo_play",
937 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND, TRUE);
940 _mmcam_dbg_log("Do NOT play recording stop sound because of ASM stop");
943 /* Send recording report to application */
944 msg.id = MM_MESSAGE_CAMCORDER_CAPTURED;
945 report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport));
947 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
949 report->recording_filename = strdup(info->filename);
950 msg.param.data= report;
952 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
956 sc->pipeline_time = 0;
958 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
959 sc->isMaxtimePausing = FALSE;
960 sc->error_occurs = FALSE;
962 info->video_frame_count = 0;
963 info->audio_frame_count = 0;
965 g_free(info->filename);
966 info->filename = NULL;
967 info->b_commiting = FALSE;
969 MMTA_ACUM_ITEM_END(" _mmcamcorder_video_handle_eos", 0);
970 MMTA_ACUM_ITEM_END("Real Commit Time", 0);
972 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
978 * This function is record video data probing function.
979 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
980 * this function will be called when data stream pass through the pad.
982 * @param[in] pad probing pad which calls this function.
983 * @param[in] buffer buffer which contains stream data.
984 * @param[in] u_data user data.
985 * @return This function returns true on success, or false value with error
989 static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, gpointer u_data)
991 switch (GST_EVENT_TYPE(event)) {
992 case GST_EVENT_UNKNOWN:
993 /* upstream events */
996 case GST_EVENT_NAVIGATION:
997 case GST_EVENT_LATENCY:
998 /* downstream serialized events */
999 case GST_EVENT_NEWSEGMENT :
1001 case GST_EVENT_BUFFERSIZE:
1002 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1005 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1007 /* bidirectional events */
1008 case GST_EVENT_FLUSH_START:
1009 case GST_EVENT_FLUSH_STOP:
1010 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1013 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1021 static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1023 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1024 _MMCamcorderSubContext *sc = NULL;
1025 _MMCamcorderVideoInfo * info = NULL;
1027 mmf_return_val_if_fail(hcamcorder, TRUE);
1028 mmf_return_val_if_fail(buffer, FALSE);
1029 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1031 mmf_return_val_if_fail(sc && sc->info, TRUE);
1034 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1036 if (info->audio_frame_count == 0) {
1037 info->filesize += (guint64)GST_BUFFER_SIZE(buffer);
1038 info->audio_frame_count++;
1042 if (sc->ferror_send || sc->isMaxsizePausing) {
1043 _mmcam_dbg_warn("Recording is paused, drop frames");
1047 info->filesize += (guint64)GST_BUFFER_SIZE(buffer);
1048 info->audio_frame_count++;
1054 static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1056 static int count = 0;
1060 guint64 free_space = 0;
1061 guint64 buffer_size = 0;
1062 guint64 trailer_size = 0;
1063 guint64 queued_buffer = 0;
1064 char *filename = NULL;
1066 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1067 _MMCamcorderMsgItem msg;
1068 _MMCamcorderSubContext *sc = NULL;
1069 _MMCamcorderVideoInfo *info = NULL;
1071 mmf_return_val_if_fail(hcamcorder, TRUE);
1072 mmf_return_val_if_fail(buffer, FALSE);
1074 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1075 mmf_return_val_if_fail(sc && sc->info, TRUE);
1078 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1079 if (sc->ferror_send) {
1080 _mmcam_dbg_warn("file write error, drop frames");
1084 info->video_frame_count++;
1085 if (info->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1086 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1087 info->video_frame_count); */
1088 info->filesize += (guint64)GST_BUFFER_SIZE(buffer);
1092 buffer_size = GST_BUFFER_SIZE(buffer);
1094 if (sc->now_continuous_af) {
1095 _mmcam_dbg_log("Start continuous AF when START recording");
1096 __ta__(" _MMCamcorder_CMD_RECORD:START CAF",
1097 ret = _mmcamcorder_adjust_auto_focus((MMHandleType)hcamcorder);
1099 sc->now_continuous_af = FALSE;
1100 if (ret != MM_ERROR_NONE) {
1101 _mmcam_dbg_warn("Failed continuous AF when START recording");
1105 /* get trailer size */
1106 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1107 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1112 /* to minimizing free space check overhead */
1113 count = count % _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL;
1115 filename = info->filename;
1116 ret = _mmcamcorder_get_freespace(filename, &free_space);
1118 /*_mmcam_dbg_log("check free space for recording");*/
1121 case -2: /* file not exist */
1122 case -1: /* failed to get free space */
1123 _mmcam_dbg_err("Error occured. [%d]", ret);
1124 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1125 sc->ferror_send = TRUE;
1126 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1128 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1130 msg.param.code = MM_ERROR_FILE_READ;
1132 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1137 return FALSE; /* skip this buffer */
1139 default: /* succeeded to get free space */
1140 /* check free space for recording */
1141 /* get queued buffer size */
1142 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1143 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1144 queued_buffer = aq_size + vq_size;
1146 /* check free space */
1147 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1148 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1149 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1150 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1151 free_space, trailer_size, buffer_size, queued_buffer);
1153 if (!sc->isMaxsizePausing) {
1154 MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1155 sc->isMaxsizePausing = TRUE;
1157 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1158 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1167 info->filesize += (guint64)buffer_size;
1173 static gboolean __mmcamcorder_video_dataprobe_slow(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1176 guint64 trailer_size = 0;
1177 static guint count = 0;
1179 GstClockTime b_time;
1181 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1182 _MMCamcorderMsgItem msg;
1183 _MMCamcorderSubContext *sc = NULL;
1184 _MMCamcorderVideoInfo *info = NULL;
1186 mmf_return_val_if_fail(buffer, FALSE);
1187 mmf_return_val_if_fail(hcamcorder, TRUE);
1189 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1190 mmf_return_val_if_fail(sc, TRUE);
1191 mmf_return_val_if_fail(sc->info, TRUE);
1195 b_time = GST_BUFFER_TIMESTAMP(buffer);
1198 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1199 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1204 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1205 msg.param.recording_status.elapsed = (unsigned int)GST_TIME_AS_MSECONDS(b_time);
1206 msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10);
1207 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1212 GST_BUFFER_TIMESTAMP(buffer) = b_time * (info->multiple_fps);
1218 static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1220 _MMCamcorderMsgItem msg;
1221 guint64 trailer_size = 0;
1222 guint64 rec_pipe_time = 0;
1223 _MMCamcorderSubContext *sc = NULL;
1224 GstElement *pipeline = NULL;
1225 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1226 _MMCamcorderVideoInfo *info = NULL;
1228 mmf_return_val_if_fail(buffer, FALSE);
1229 mmf_return_val_if_fail(hcamcorder, TRUE);
1230 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1232 mmf_return_val_if_fail(sc, TRUE);
1233 mmf_return_val_if_fail(sc->info, TRUE);
1234 mmf_return_val_if_fail(sc->element, TRUE);
1237 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1239 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buffer))) {
1240 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1244 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1246 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1247 MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1252 if (info->max_time > 0 && rec_pipe_time > info->max_time) {
1253 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1254 rec_pipe_time, info->max_time);
1256 if (!sc->isMaxtimePausing) {
1257 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1259 sc->isMaxtimePausing = TRUE;
1261 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1262 msg.param.recording_status.elapsed = (unsigned int)rec_pipe_time;
1263 msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10);
1264 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1266 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1267 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1273 /*_mmcam_dbg_log("_mmcamcorder_audioque_dataprobe :: time [%" GST_TIME_FORMAT "], size [%d]",
1274 GST_TIME_ARGS(rec_pipe_time), (info->filesize + trailer_size) >> 10);*/
1276 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1277 msg.param.recording_status.elapsed = (unsigned int)rec_pipe_time;
1278 msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10);
1279 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1285 static gboolean __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1287 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1288 double volume = 0.0;
1291 int err = MM_ERROR_UNKNOWN;
1292 char *err_name = NULL;
1294 mmf_return_val_if_fail(buffer, FALSE);
1295 mmf_return_val_if_fail(hcamcorder, FALSE);
1297 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1298 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1299 MMCAM_AUDIO_VOLUME, &volume,
1300 MMCAM_AUDIO_FORMAT, &format,
1301 MMCAM_AUDIO_CHANNEL, &channel,
1303 if (err != MM_ERROR_NONE) {
1304 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1305 SAFE_FREE(err_name);
1309 /* Set audio stream NULL */
1310 if (volume == 0.0) {
1311 memset(GST_BUFFER_DATA(buffer), 0, GST_BUFFER_SIZE(buffer));
1314 /* CALL audio stream callback */
1315 if (hcamcorder->astream_cb && buffer && GST_BUFFER_DATA(buffer)) {
1316 MMCamcorderAudioStreamDataType stream;
1318 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1319 _mmcam_dbg_warn("Not ready for stream callback");
1323 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1324 GST_BUFFER_DATA(buffer), width, height, format);*/
1326 stream.data = (void *)GST_BUFFER_DATA(buffer);
1327 stream.format = format;
1328 stream.channel = channel;
1329 stream.length = GST_BUFFER_SIZE(buffer);
1330 stream.timestamp = (unsigned int)(GST_BUFFER_TIMESTAMP(buffer)/1000000); /* nano -> milli second */
1332 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1334 if (hcamcorder->astream_cb) {
1335 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1338 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1345 static gboolean __mmcamcorder_add_locationinfo(MMHandleType handle, int fileformat)
1347 gboolean bret = FALSE;
1349 switch (fileformat) {
1350 case MM_FILE_FORMAT_3GP:
1351 case MM_FILE_FORMAT_MP4:
1352 bret = __mmcamcorder_add_locationinfo_mp4(handle);
1355 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1363 static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle)
1367 guint64 udta_size = 0;
1368 gint64 current_pos = 0;
1369 gint64 moov_pos = 0;
1370 gint64 udta_pos = 0;
1371 gdouble longitude = 0;
1372 gdouble latitude = 0;
1373 gdouble altitude = 0;
1375 char *err_name = NULL;
1376 _MMCamcorderLocationInfo location_info = {0,};
1378 _MMCamcorderVideoInfo *info = NULL;
1379 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1380 _MMCamcorderSubContext *sc = NULL;
1382 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1383 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1385 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1386 mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1392 f = fopen(info->filename, "rb+");
1397 err = mm_camcorder_get_attributes(handle, &err_name,
1398 MMCAM_TAG_LATITUDE, &latitude,
1399 MMCAM_TAG_LONGITUDE, &longitude,
1400 MMCAM_TAG_ALTITUDE, &altitude,
1402 if (err != MM_ERROR_NONE) {
1403 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1404 SAFE_FREE (err_name);
1410 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1411 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1412 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1414 /* find udta container.
1415 if, there are udta container, write loci box after that
1416 else, make udta container and write loci box. */
1417 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('u','d','t','a'))) {
1418 _mmcam_dbg_log("find udta container");
1421 if (fseek(f, -8L, SEEK_CUR) != 0) {
1425 udta_pos = ftell(f);
1430 fread(&buf, sizeof(char), sizeof(buf), f);
1431 udta_size = _mmcamcorder_get_container_size(buf);
1433 /* goto end of udta and write 'loci' box */
1434 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1438 if (!_mmcamcorder_write_loci(f, location_info)) {
1442 current_pos = ftell(f);
1443 if (current_pos < 0) {
1447 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1451 _mmcam_dbg_log("No udta container");
1452 if (fseek(f, 0, SEEK_END) != 0) {
1456 if (!_mmcamcorder_write_udta(f, location_info)) {
1461 /* find moov container.
1462 update moov container size. */
1463 if((current_pos = ftell(f))<0)
1466 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'))) {
1467 _mmcam_dbg_log("find moov container");
1468 if (fseek(f, -8L, SEEK_CUR) !=0) {
1472 moov_pos = ftell(f);
1477 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1481 _mmcam_dbg_err("No 'moov' container");
1493 _mmcam_dbg_err("ftell() returns negative value.");