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 <gst/allocators/gsttizenmemory.h>
26 #include <gst/video/cameracontrol.h>
27 #include <gst/app/gstappsrc.h>
28 #include "mm_camcorder_internal.h"
29 #include "mm_camcorder_videorec.h"
31 /*---------------------------------------------------------------------------------------
32 | LOCAL VARIABLE DEFINITIONS for internal |
33 ---------------------------------------------------------------------------------------*/
34 #define _MMCAMCORDER_MINIMUM_FRAME 5
35 #define _MMCAMCORDER_RETRIAL_COUNT 15
36 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* us */
37 #define _MMCAMCORDER_FRAME_PASS_MIN_FPS 30
38 #define _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME 30000000 /* ns */
39 #define _MMCAMCORDER_VIDEO_MINIMUM_SPACE (_MMCAMCORDER_MINIMUM_SPACE << 1) /* byte */
40 #define OFFSET_COMPOSITION_MATRIX 40L
41 #define MAX_ERROR_MESSAGE_LEN 128
43 /*---------------------------------------------------------------------------------------
44 | LOCAL FUNCTION PROTOTYPES: |
45 ---------------------------------------------------------------------------------------*/
46 /* STATIC INTERNAL FUNCTION */
47 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
48 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
49 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
54 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
56 /*=======================================================================================
57 | FUNCTION DEFINITIONS |
58 =======================================================================================*/
59 /*---------------------------------------------------------------------------------------
60 | GLOBAL FUNCTION DEFINITIONS: |
61 ---------------------------------------------------------------------------------------*/
62 gboolean _mmcamcorder_video_push_buffer(void *handle, GstBuffer *buffer)
64 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
65 _MMCamcorderSubContext *sc = NULL;
66 _MMCamcorderImageInfo *info_image = NULL;
67 _MMCamcorderVideoInfo *info_video = NULL;
68 _MMCamcorderGstElement *element = NULL;
69 GstClockTime current_ts = 0; /* nsec */
71 mmf_return_val_if_fail(hcamcorder, FALSE);
72 mmf_return_val_if_fail(MMF_CAMCORDER_SUBCONTEXT(hcamcorder), FALSE);
74 mmf_return_val_if_fail(buffer, FALSE);
75 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
77 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
79 mmf_return_val_if_fail(sc->info_image, FALSE);
80 mmf_return_val_if_fail(sc->info_video, FALSE);
81 mmf_return_val_if_fail(sc->encode_element, FALSE);
83 info_image = sc->info_image;
84 info_video = sc->info_video;
85 element = sc->encode_element;
87 if (info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
88 element[_MMCAMCORDER_ENCSINK_SRC].gst) {
90 GstClock *clock = NULL;
93 _mmcam_dbg_log("GST_BUFFER_FLAG_DELTA_UNIT is set : %d",
94 GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT));
96 current_ts = GST_BUFFER_PTS(buffer);
98 if (info_video->is_first_frame) {
99 /* check first I frame for H.264 stream */
100 if (info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
101 if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
102 _mmcam_dbg_warn("NOT I frame.. skip this buffer");
105 _mmcam_dbg_warn("[H.264] first I frame");
109 /* set base timestamp */
110 if (element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
111 clock = GST_ELEMENT_CLOCK(element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
113 gst_object_ref(clock);
114 info_video->base_video_ts = current_ts - (gst_clock_get_time(clock) - \
115 GST_ELEMENT(element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
116 gst_object_unref(clock);
119 /* for image capture with encodebin and v4l2src */
120 if (sc->bencbin_capture && info_image->capturing) {
121 g_mutex_lock(&hcamcorder->task_thread_lock);
122 _mmcam_dbg_log("send signal for sound play");
123 hcamcorder->task_thread_state = _MMCAMCORDER_TASK_THREAD_STATE_SOUND_SOLO_PLAY_START;
124 g_cond_signal(&hcamcorder->task_thread_cond);
125 g_mutex_unlock(&hcamcorder->task_thread_lock);
127 info_video->base_video_ts = current_ts;
130 if (_mmcamcorder_invoke_video_stream_cb(handle, buffer, FALSE) == FALSE) {
131 /*_mmcam_dbg_warn("do not push buffer to encode by app's return value");*/
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 goto _VIDEO_PUSH_BUFFER_DONE;
139 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer) = current_ts - info_video->base_video_ts;
141 /*_mmcam_dbg_log("buffer %p, timestamp %"GST_TIME_FORMAT, buffer, GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
143 if (info_video->record_dual_stream) {
144 /* It will NOT INCREASE reference count of buffer */
145 ret = gst_app_src_push_buffer((GstAppSrc *)element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
147 /* It will INCREASE reference count of buffer */
148 g_signal_emit_by_name(element[_MMCAMCORDER_ENCSINK_SRC].gst, "push-buffer", buffer, &ret);
151 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
153 _VIDEO_PUSH_BUFFER_DONE:
154 info_video->last_video_ts = current_ts;
156 if (info_video->is_first_frame) {
157 info_video->is_first_frame = FALSE;
159 /* drop buffer if it's from tizen allocator */
160 if (gst_is_tizen_memory(gst_buffer_peek_memory(buffer, 0))) {
161 _mmcam_dbg_warn("drop first buffer from tizen allocator to avoid copy in basesrc");
167 /* skip display if too fast FPS */
168 if (info_video->record_dual_stream == FALSE &&
169 info_video->fps > _MMCAMCORDER_FRAME_PASS_MIN_FPS) {
170 if (info_video->prev_preview_ts != 0) {
171 if (GST_BUFFER_PTS(buffer) - info_video->prev_preview_ts < _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME) {
172 _mmcam_dbg_log("it's too fast. drop frame...");
177 /*_mmcam_dbg_log("diff %llu", diff);*/
179 info_video->prev_preview_ts = GST_BUFFER_PTS(buffer);
186 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
188 return _mmcamcorder_video_push_buffer(u_data, gst_sample_get_buffer(sample));
192 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
195 int err = MM_ERROR_NONE;
196 const char* gst_element_rsink_name = NULL;
199 GstPad *srcpad = NULL;
200 GstPad *sinkpad = NULL;
202 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
203 _MMCamcorderSubContext *sc = NULL;
205 type_element *RecordsinkElement = NULL;
207 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
209 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
210 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
211 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
213 _mmcam_dbg_warn("start");
215 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
216 if (err != MM_ERROR_NONE)
220 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
221 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
222 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
223 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
226 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
228 /* get audio disable */
229 mm_camcorder_get_attributes(handle, NULL,
230 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
233 _mmcam_dbg_log("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d, ved_cb %p",
234 sc->audio_disable, sc->is_modified_rate, hcamcorder->vedecision_cb);
236 if (sc->is_modified_rate || hcamcorder->vedecision_cb)
237 sc->audio_disable = TRUE;
239 if (sc->audio_disable == FALSE) {
240 /* create audiosrc bin */
241 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
242 if (err != MM_ERROR_NONE)
246 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
247 if (err != MM_ERROR_NONE)
250 if (sc->audio_disable == FALSE) {
251 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
252 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
255 /* add element and encodesink bin to encode main pipeline */
256 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
257 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
258 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
259 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
262 /* Link each element : appsrc - capsfilter - encodesink bin */
263 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
264 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
265 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
267 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
268 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
269 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
271 if (sc->audio_disable == FALSE) {
272 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
273 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
274 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
277 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
278 CONFIGURE_CATEGORY_MAIN_RECORD,
281 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
283 if (!gst_element_rsink_name) {
284 _mmcam_dbg_err("failed to get recordsink name");
285 err = MM_ERROR_CAMCORDER_INTERNAL;
286 goto pipeline_creation_error;
289 /* set data probe function */
291 /* register message cb */
293 /* set data probe functions */
294 if (sc->audio_disable == FALSE) {
295 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
296 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
297 __mmcamcorder_audioque_dataprobe, hcamcorder);
298 gst_object_unref(sinkpad);
302 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
303 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
304 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
305 gst_object_unref(srcpad);
308 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
309 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
310 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
311 __mmcamcorder_eventprobe_monitor, hcamcorder);
312 gst_object_unref(srcpad);
317 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
318 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
319 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
320 __mmcamcorder_eventprobe_monitor, hcamcorder);
321 gst_object_unref(srcpad);
325 if (sc->audio_disable) {
326 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
327 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
328 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
329 gst_object_unref(sinkpad);
333 if (!strcmp(gst_element_rsink_name, "filesink")) {
334 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
335 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
336 __mmcamcorder_video_dataprobe_encoded, hcamcorder);
337 gst_object_unref(srcpad);
340 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
341 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
342 __mmcamcorder_audio_dataprobe_check, hcamcorder);
343 gst_object_unref(srcpad);
347 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
348 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
349 __mmcamcorder_muxed_dataprobe, hcamcorder);
350 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
351 __mmcamcorder_eventprobe_monitor, hcamcorder);
352 gst_object_unref(sinkpad);
355 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
357 /* register pipeline message callback */
358 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
360 /* set sync handler */
361 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
363 gst_object_unref(bus);
366 return MM_ERROR_NONE;
368 pipeline_creation_error:
369 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
370 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
372 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
377 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
379 GstPad *srcpad = NULL;
380 GstPad *sinkpad = NULL;
381 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
382 _MMCamcorderSubContext *sc = NULL;
384 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
386 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
387 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
388 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
392 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
393 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
394 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
395 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
397 /* release audiosrc bin */
398 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
399 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
402 To avoid conflicting between old elements and newly created elements,
403 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
404 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
405 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
406 It's because the pipeline of audio recording destroys at the same time,
407 and '_mmcamcorder_element_release_noti' will perfom removing handle.
409 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
411 _mmcam_dbg_log("Audio pipeline removed");
414 return MM_ERROR_NONE;
418 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
420 GstPad *reqpad = NULL;
421 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
422 _MMCamcorderSubContext *sc = NULL;
423 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
424 int ret = MM_ERROR_NONE;
425 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
427 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
429 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
430 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
431 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
435 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
436 /* release request pad */
437 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
439 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
440 gst_object_unref(reqpad);
444 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
446 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
447 gst_object_unref(reqpad);
451 /* release encode main pipeline */
452 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
455 To avoid conflicting between old elements and newly created elements,
456 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
457 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
458 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
459 It's because the pipeline of audio recording destroys at the same time,
460 and '_mmcamcorder_element_release_noti' will perfom removing handle.
462 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
463 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
465 _mmcam_dbg_warn("Encoder pipeline removed");
467 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
468 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
470 _mmcam_dbg_warn("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
472 if (hcamcorder->is_release_cb_calling == FALSE) {
473 /* release resource */
474 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
475 hcamcorder->video_encoder_resource);
476 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
477 hcamcorder->video_encoder_resource = NULL;
479 _mmcam_dbg_warn("mark resource for release 0x%x", ret);
481 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
483 _mmcam_dbg_warn("commit resource release 0x%x", ret);
486 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
488 _mmcam_dbg_warn("unlock resource");
489 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
492 return MM_ERROR_NONE;
496 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
498 int ret = MM_ERROR_NONE;
499 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
500 _MMCamcorderSubContext *sc = NULL;
504 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
505 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
506 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
508 _mmcam_dbg_log("start");
510 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
511 _mmcam_dbg_warn("pipeline is not existed.");
512 return MM_ERROR_NONE;
515 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
517 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
518 if (ret != MM_ERROR_NONE) {
519 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
523 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
525 /* remove audio pipeline first */
526 ret = _mmcamcorder_remove_audio_pipeline(handle);
527 if (ret != MM_ERROR_NONE) {
528 _mmcam_dbg_err("Fail to remove audio pipeline");
532 ret = _mmcamcorder_remove_encode_pipeline(handle);
533 if (ret != MM_ERROR_NONE) {
534 _mmcam_dbg_err("Fail to remove encoder pipeline");
538 /* Remove pipeline message callback */
539 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
540 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
541 hcamcorder->encode_pipeline_cb_event_id = 0;
544 /* Remove remained message */
546 GstMessage *gst_msg = NULL;
547 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
548 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
549 gst_message_unref(gst_msg);
552 gst_object_unref(bus);
556 _mmcam_dbg_log("done");
562 int _mmcamcorder_video_command(MMHandleType handle, int command)
567 int gop_interval = 0;
568 int ret = MM_ERROR_NONE;
569 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
570 char *err_name = NULL;
571 char *target_filename = NULL;
572 GstCameraControl *CameraControl = NULL;
575 GstElement *pipeline = NULL;
577 _MMCamcorderVideoInfo *info = NULL;
578 _MMCamcorderSubContext *sc = NULL;
579 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
581 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
583 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
584 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
585 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
586 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
588 info = sc->info_video;
590 _mmcam_dbg_log("Command(%d)", command);
592 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
595 case _MMCamcorder_CMD_RECORD:
597 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
601 gboolean storage_validity = FALSE;
604 int root_directory_length = 0;
607 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
609 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
610 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
612 /* prepare resource manager for H/W encoder */
613 if (hcamcorder->video_encoder_resource == NULL) {
614 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
615 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
616 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
617 &hcamcorder->video_encoder_resource);
618 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
619 _mmcam_dbg_err("could not prepare for encoder resource");
620 ret = MM_ERROR_RESOURCE_INTERNAL;
621 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
622 goto _ERR_CAMCORDER_VIDEO_COMMAND;
625 _mmcam_dbg_log("encoder already acquired");
628 /* acquire resources */
629 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
630 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
631 _mmcam_dbg_err("could not acquire resources");
632 ret = MM_ERROR_RESOURCE_INTERNAL;
633 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
634 goto _ERR_CAMCORDER_VIDEO_COMMAND;
637 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
638 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
640 /* init record_dual_stream */
641 info->record_dual_stream = FALSE;
643 ret = mm_camcorder_get_attributes(handle, &err_name,
644 MMCAM_CAMERA_FPS, &fps,
645 MMCAM_CAMERA_WIDTH, &(info->preview_width),
646 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
647 MMCAM_VIDEO_WIDTH, &(info->video_width),
648 MMCAM_VIDEO_HEIGHT, &(info->video_height),
649 MMCAM_FILE_FORMAT, &fileformat,
650 MMCAM_TARGET_FILENAME, &target_filename, &size,
651 MMCAM_TARGET_MAX_SIZE, &imax_size,
652 MMCAM_TARGET_TIME_LIMIT, &imax_time,
653 MMCAM_FILE_FORMAT, &(info->fileformat),
654 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
655 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
657 if (ret != MM_ERROR_NONE) {
658 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
660 goto _ERR_CAMCORDER_VIDEO_COMMAND;
663 if (!target_filename && !hcamcorder->mstream_cb) {
664 _mmcam_dbg_err("filename is not set and muxed stream cb is NULL");
665 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
666 goto _ERR_CAMCORDER_VIDEO_COMMAND;
671 info->max_size = 0; /* do not check */
673 info->max_size = ((guint64)imax_size) << 10; /* to byte */
677 info->max_time = 0; /* do not check */
679 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
681 ret = _mmcamcorder_get_storage_validity(hcamcorder, target_filename,
682 _MMCAMCORDER_VIDEO_MINIMUM_SPACE, &storage_validity);
683 if (ret != MM_ERROR_NONE) {
684 _mmcam_dbg_err("storage validation failed[0x%x]:%d", ret, storage_validity);
688 _mmcamcorder_adjust_recording_max_size(target_filename, &info->max_size);
690 g_mutex_lock(&hcamcorder->task_thread_lock);
691 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
692 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
693 /* Play record start sound */
694 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
696 g_mutex_unlock(&hcamcorder->task_thread_lock);
698 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
700 if (info->video_width == 0 || info->video_height == 0) {
701 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
702 info->video_width, info->video_height, info->preview_width, info->preview_height);
703 info->video_width = info->preview_width;
704 info->video_height = info->preview_height;
707 if (info->support_dual_stream) {
708 _mmcam_dbg_warn("DUAL STREAM MODE");
710 info->record_dual_stream = TRUE;
712 /* No need to restart preview */
713 info->restart_preview = FALSE;
715 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
716 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
717 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
718 info->preview_width == info->video_width &&
719 info->preview_height == info->video_height) {
720 _mmcam_dbg_log("H264 preview mode and same resolution");
722 /* No need to restart preview */
723 info->restart_preview = FALSE;
725 /* always need to restart preview */
726 info->restart_preview = TRUE;
729 /* set recording hint */
730 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
732 if (info->restart_preview) {
733 /* stop preview and set new size */
734 _mmcam_dbg_log("restart preview");
736 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
737 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
738 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
740 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
742 /* check decoder recreation */
743 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
744 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
745 ret = MM_ERROR_CAMCORDER_INTERNAL;
746 goto _ERR_CAMCORDER_VIDEO_COMMAND;
749 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
750 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
751 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
753 if (ret != MM_ERROR_NONE)
754 goto _ERR_CAMCORDER_VIDEO_COMMAND;
756 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
757 ret = MM_ERROR_CAMCORDER_INTERNAL;
758 goto _ERR_CAMCORDER_VIDEO_COMMAND;
761 /* Start preview again with new setting */
762 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
763 if (ret != MM_ERROR_NONE)
764 goto _ERR_CAMCORDER_VIDEO_COMMAND;
766 if (motion_rate < 1.0) {
767 _mmcam_dbg_warn("wait for stabilization of frame");
771 _mmcam_dbg_log("no need to restart preview");
774 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
775 CONFIGURE_CATEGORY_MAIN_RECORD,
779 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
780 CONFIGURE_CATEGORY_MAIN_RECORD,
781 "PassFirstVideoFrame",
782 &(sc->pass_first_vframe));
784 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
785 sc->drop_vframe, sc->pass_first_vframe);
787 info->record_drop_count = (guint)motion_rate;
788 info->record_motion_rate = motion_rate;
789 if (sc->is_modified_rate)
790 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
792 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
794 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
795 fps, info->record_motion_rate, info->record_timestamp_ratio);
797 /* set push buffer flag */
798 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
799 info->base_video_ts = 0;
801 /* connect video stream cb signal if it supports dual stream. */
802 if (info->record_dual_stream) {
803 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
804 goto _ERR_CAMCORDER_VIDEO_COMMAND;
807 /* start video stream */
808 if (info->record_dual_stream) {
809 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
811 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
813 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
814 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
816 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
818 _mmcam_dbg_err("could not get camera control");
822 /* check pre-created encode pipeline */
823 g_mutex_lock(&hcamcorder->task_thread_lock);
824 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
825 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
826 /* create encoding pipeline */
827 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
828 if (ret != MM_ERROR_NONE) {
829 g_mutex_unlock(&hcamcorder->task_thread_lock);
830 goto _ERR_CAMCORDER_VIDEO_COMMAND;
833 g_mutex_unlock(&hcamcorder->task_thread_lock);
835 /* check recording start sound */
836 _mmcamcorder_sound_solo_play_wait(handle);
838 /**< To fix video recording hanging
839 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
840 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
841 basetime wouldn't change if you set (GstClockTime)0.
842 3. Move set start time position below PAUSED of pipeline.
845 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
846 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
849 info->video_frame_count = 0;
850 info->is_first_frame = TRUE;
851 info->audio_frame_count = 0;
853 sc->ferror_send = FALSE;
854 sc->ferror_count = 0;
855 hcamcorder->error_occurs = FALSE;
856 sc->bget_eos = FALSE;
857 sc->muxed_stream_offset = 0;
859 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
860 if (ret != MM_ERROR_NONE) {
861 /* stop video stream */
862 if (info->record_dual_stream) {
863 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
865 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
867 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
868 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
870 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
872 _mmcam_dbg_err("failed to get camera control");
876 /* Remove recorder pipeline and recording file which size maybe zero */
877 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
878 if (info->filename) {
879 _mmcam_dbg_log("file delete(%s)", info->filename);
880 unlink(info->filename);
882 goto _ERR_CAMCORDER_VIDEO_COMMAND;
885 /*set the GOP so that video record will get a new key frame*/
886 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
887 if (mm_camcorder_get_attributes(handle, NULL,
888 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
889 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
891 _mmcam_dbg_err("get gop interval failed");
895 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
896 if (mm_camcorder_get_attributes(handle, NULL,
897 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
898 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
900 _mmcam_dbg_err("get gop interval failed");
903 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
905 _mmcam_dbg_log("Object property settings done");
909 case _MMCamcorder_CMD_PAUSE:
911 if (info->b_commiting) {
912 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
913 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
916 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
917 if (sc->audio_disable) {
918 /* check only video frame */
919 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
921 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
922 _mmcam_dbg_err("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
923 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
925 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
928 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
930 /* check both of video and audio frame */
931 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
933 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
934 _mmcam_dbg_err("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
935 info->video_frame_count, info->audio_frame_count);
936 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
938 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
939 count, info->video_frame_count, info->audio_frame_count);
942 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
946 /* block encodebin */
947 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
950 case _MMCamcorder_CMD_CANCEL:
952 if (info->b_commiting) {
953 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
954 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
957 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
959 if (hcamcorder->capture_in_recording == FALSE) {
961 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
962 _mmcam_dbg_err("Failed to Wait capture data");
963 hcamcorder->capture_in_recording = FALSE;
966 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
969 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
972 /* block push buffer */
973 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
975 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
976 if (ret != MM_ERROR_NONE)
977 goto _ERR_CAMCORDER_VIDEO_COMMAND;
979 /* set recording hint */
980 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
982 /* stop video stream */
983 if (info->record_dual_stream) {
984 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
986 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
988 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
989 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
991 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
993 _mmcam_dbg_err("failed to get camera control");
997 if (info->restart_preview) {
998 /* restart preview */
999 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1000 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1001 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1003 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1005 /* check decoder recreation */
1006 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1007 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1008 ret = MM_ERROR_CAMCORDER_INTERNAL;
1011 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1012 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1013 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1015 if (ret != MM_ERROR_NONE)
1016 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1018 /* reset restart_preview for inset window layout */
1019 info->restart_preview = FALSE;
1021 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1022 ret = MM_ERROR_CAMCORDER_INTERNAL;
1023 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1026 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1027 if (ret != MM_ERROR_NONE)
1028 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1031 /* remove target file */
1032 if (info->filename) {
1033 _mmcam_dbg_log("file delete(%s)", info->filename);
1034 unlink(info->filename);
1037 sc->isMaxsizePausing = FALSE;
1038 sc->isMaxtimePausing = FALSE;
1040 sc->display_interval = 0;
1041 sc->previous_slot_time = 0;
1042 info->video_frame_count = 0;
1043 info->audio_frame_count = 0;
1045 hcamcorder->capture_in_recording = FALSE;
1048 case _MMCamcorder_CMD_COMMIT:
1052 if (info->b_commiting) {
1053 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
1054 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1056 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
1057 info->b_commiting = TRUE;
1058 sc->bget_eos = FALSE;
1061 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1062 if (sc->audio_disable) {
1063 /* check only video frame */
1064 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1065 hcamcorder->capture_in_recording == FALSE) {
1067 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1068 _mmcam_dbg_err("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1069 info->video_frame_count, hcamcorder->capture_in_recording);
1071 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1072 _mmcam_dbg_warn("video frames are enough. keep going...");
1074 info->b_commiting = FALSE;
1075 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1078 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1079 count, info->video_frame_count, hcamcorder->capture_in_recording);
1082 /* check both of video and audio frame */
1083 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1084 info->audio_frame_count &&
1085 hcamcorder->capture_in_recording == FALSE) {
1087 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1088 _mmcam_dbg_err("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1089 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1091 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1092 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1094 info->b_commiting = FALSE;
1095 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1098 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1100 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1101 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1105 if (hcamcorder->capture_in_recording) {
1106 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1107 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1108 _mmcam_dbg_warn("timeout");
1110 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1114 /* block push buffer */
1115 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1116 _mmcam_dbg_log("block push buffer to appsrc");
1118 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1119 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1120 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1121 ret = MM_ERROR_OUT_OF_STORAGE;
1122 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1125 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1126 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1127 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1129 _mmcam_dbg_err("VIDEO: send EOS failed");
1130 info->b_commiting = FALSE;
1131 ret = MM_ERROR_CAMCORDER_INTERNAL;
1132 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1135 _mmcam_dbg_err("No video stream source");
1136 info->b_commiting = FALSE;
1137 ret = MM_ERROR_CAMCORDER_INTERNAL;
1138 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1141 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1142 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1143 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1145 _mmcam_dbg_err("AUDIO: send EOS failed");
1146 info->b_commiting = FALSE;
1147 ret = MM_ERROR_CAMCORDER_INTERNAL;
1148 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1151 _mmcam_dbg_log("No audio stream");
1155 sc->display_interval = 0;
1156 sc->previous_slot_time = 0;
1159 _mmcam_dbg_log("Start to wait EOS");
1160 ret = _mmcamcorder_get_eos_message(handle);
1161 if (ret != MM_ERROR_NONE) {
1162 info->b_commiting = FALSE;
1163 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1167 hcamcorder->capture_in_recording = FALSE;
1171 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1172 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1175 return MM_ERROR_NONE;
1177 _ERR_CAMCORDER_VIDEO_COMMAND:
1178 if (command == _MMCamcorder_CMD_RECORD)
1179 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1185 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1187 int ret = MM_ERROR_NONE;
1189 guint64 file_size = 0;
1191 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1192 _MMCamcorderSubContext *sc = NULL;
1193 _MMCamcorderVideoInfo *info = NULL;
1194 _MMCamcorderMsgItem msg;
1195 MMCamRecordingReport *report = NULL;
1197 mmf_return_val_if_fail(hcamcorder, FALSE);
1199 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1200 mmf_return_val_if_fail(sc, FALSE);
1201 mmf_return_val_if_fail(sc->info_video, FALSE);
1203 info = sc->info_video;
1207 /* Play record stop sound */
1208 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1210 /* remove blocking part */
1211 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1213 mm_camcorder_get_attributes(handle, NULL,
1214 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1217 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1218 if (ret != MM_ERROR_NONE)
1219 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1221 /* set recording hint */
1222 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1224 /* stop video stream */
1225 if (info->record_dual_stream) {
1226 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1228 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1230 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1231 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1233 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1235 _mmcam_dbg_err("failed to get camera control");
1239 if (enabletag && !(sc->ferror_send)) {
1240 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1241 _mmcam_dbg_log("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1244 /* Check file size */
1245 if (info->max_size > 0) {
1246 _mmcamcorder_get_file_size(info->filename, &file_size);
1247 _mmcam_dbg_log("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1248 info->max_size, file_size);
1250 if (file_size > info->max_size) {
1251 _MMCamcorderMsgItem message;
1252 _mmcam_dbg_err("File size is greater than max size !!");
1253 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1254 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1255 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1259 if (info->restart_preview) {
1261 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1262 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1263 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1265 _mmcam_dbg_log("Set state of pipeline as READY");
1266 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1268 /* check decoder recreation */
1269 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1270 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1271 ret = MM_ERROR_CAMCORDER_INTERNAL;
1275 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1276 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1277 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1279 if (ret != MM_ERROR_NONE) {
1280 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1281 msg.param.code = ret;
1282 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1283 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1286 /* reset restart_preview for inset window layout */
1287 info->restart_preview = FALSE;
1289 /* recover preview size */
1290 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1291 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1292 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1293 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1294 _mmcam_dbg_err("Failed to set camera resolution %dx%d",
1295 info->preview_width, info->preview_height);
1298 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1299 /* Do not return when error is occurred.
1300 Recording file was created successfully, but starting pipeline failed */
1301 if (ret != MM_ERROR_NONE) {
1302 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1303 msg.param.code = ret;
1304 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1305 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1308 _mmcam_dbg_log("No need to restart preview");
1311 /* Send recording report to application */
1312 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1313 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1315 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1317 report->recording_filename = g_strdup(info->filename);
1318 msg.param.data = report;
1320 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1324 sc->pipeline_time = 0;
1326 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1327 sc->isMaxtimePausing = FALSE;
1328 hcamcorder->error_occurs = FALSE;
1330 info->video_frame_count = 0;
1331 info->audio_frame_count = 0;
1333 info->b_commiting = FALSE;
1335 /* check recording stop sound */
1336 _mmcamcorder_sound_solo_play_wait(handle);
1338 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1344 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1346 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1347 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1349 _MMCamcorderSubContext *sc = NULL;
1350 _MMCamcorderVideoInfo *videoinfo = NULL;
1351 _MMCamcorderMsgItem msg;
1352 guint64 buffer_size = 0;
1353 guint64 trailer_size = 0;
1354 guint64 max_size = 0;
1356 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1357 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1358 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1360 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1361 videoinfo = sc->info_video;
1363 /* get buffer size */
1364 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1365 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1366 return GST_PAD_PROBE_OK;
1369 buffer_size = mapinfo.size;
1370 gst_buffer_unmap(buffer, &mapinfo);
1372 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1374 g_mutex_lock(&videoinfo->size_check_lock);
1376 if (videoinfo->audio_frame_count == 0) {
1377 videoinfo->filesize += buffer_size;
1378 videoinfo->audio_frame_count++;
1379 g_mutex_unlock(&videoinfo->size_check_lock);
1380 return GST_PAD_PROBE_OK;
1383 if (sc->ferror_send || sc->isMaxsizePausing) {
1384 _mmcam_dbg_warn("Recording is paused, drop frames");
1385 g_mutex_unlock(&videoinfo->size_check_lock);
1386 return GST_PAD_PROBE_DROP;
1389 /* get trailer size */
1390 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1391 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1395 /* check max size of recorded file */
1396 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1397 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1398 GstState pipeline_state = GST_STATE_VOID_PENDING;
1399 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1400 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1401 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1402 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1403 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1405 if (!sc->isMaxsizePausing) {
1406 sc->isMaxsizePausing = TRUE;
1407 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1408 if (pipeline_state == GST_STATE_PLAYING)
1409 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1411 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1412 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1415 g_mutex_unlock(&videoinfo->size_check_lock);
1420 videoinfo->filesize += buffer_size;
1421 videoinfo->audio_frame_count++;
1423 g_mutex_unlock(&videoinfo->size_check_lock);
1425 return GST_PAD_PROBE_OK;
1429 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1434 guint64 free_space = 0;
1435 guint64 buffer_size = 0;
1436 guint64 trailer_size = 0;
1437 guint64 queued_buffer = 0;
1438 guint64 max_size = 0;
1439 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1441 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1443 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1444 _MMCamcorderMsgItem msg;
1445 _MMCamcorderSubContext *sc = NULL;
1446 _MMCamcorderVideoInfo *videoinfo = NULL;
1448 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1449 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1451 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1452 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1453 videoinfo = sc->info_video;
1455 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1456 if (sc->ferror_send) {
1457 _mmcam_dbg_warn("file write error, drop frames");
1458 return GST_PAD_PROBE_DROP;
1461 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1462 buffer_size = mapinfo.size;
1463 gst_buffer_unmap(buffer, &mapinfo);
1465 videoinfo->video_frame_count++;
1466 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1467 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1468 info->video_frame_count); */
1469 g_mutex_lock(&videoinfo->size_check_lock);
1470 videoinfo->filesize += buffer_size;
1471 g_mutex_unlock(&videoinfo->size_check_lock);
1472 return GST_PAD_PROBE_OK;
1475 /* get trailer size */
1476 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1477 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1481 /* check free space */
1482 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1484 _mmcam_dbg_err("Error occured. [%d]", ret);
1485 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1486 sc->ferror_send = TRUE;
1488 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1489 msg.param.code = MM_ERROR_FILE_READ;
1491 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1496 return GST_PAD_PROBE_DROP; /* skip this buffer */
1499 if (free_space == 0) {
1500 /* check storage state */
1501 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1503 _mmcam_dbg_warn("storage state %d", storage_state);
1505 if (storage_state == STORAGE_STATE_REMOVED ||
1506 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1507 _mmcam_dbg_err("storage was removed!");
1509 _MMCAMCORDER_LOCK(hcamcorder);
1511 if (sc->ferror_send == FALSE) {
1512 _mmcam_dbg_err("OUT_OF_STORAGE error");
1514 sc->ferror_send = TRUE;
1516 _MMCAMCORDER_UNLOCK(hcamcorder);
1518 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1519 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1521 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1523 _MMCAMCORDER_UNLOCK(hcamcorder);
1524 _mmcam_dbg_warn("error was already sent");
1527 return GST_PAD_PROBE_DROP;
1531 /* get queued buffer size */
1532 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1533 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1535 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1536 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1538 queued_buffer = aq_size + vq_size;
1540 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1541 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1542 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1543 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1544 free_space, trailer_size, buffer_size, queued_buffer);
1546 if (!sc->isMaxsizePausing) {
1547 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1548 sc->isMaxsizePausing = TRUE;
1550 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1551 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1554 return GST_PAD_PROBE_DROP;
1557 g_mutex_lock(&videoinfo->size_check_lock);
1559 /* check max size of recorded file */
1560 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1561 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1562 GstState pipeline_state = GST_STATE_VOID_PENDING;
1563 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1564 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1565 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1566 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1567 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1569 if (!sc->isMaxsizePausing) {
1570 sc->isMaxsizePausing = TRUE;
1571 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1572 if (pipeline_state == GST_STATE_PLAYING)
1573 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1575 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1576 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1579 g_mutex_unlock(&videoinfo->size_check_lock);
1581 return GST_PAD_PROBE_DROP;
1584 videoinfo->filesize += (guint64)buffer_size;
1587 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1590 g_mutex_unlock(&videoinfo->size_check_lock);
1592 return GST_PAD_PROBE_OK;
1596 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1598 guint64 trailer_size = 0;
1599 guint64 rec_pipe_time = 0;
1600 unsigned int remained_time = 0;
1602 GstClockTime b_time;
1604 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1605 _MMCamcorderMsgItem msg;
1606 _MMCamcorderSubContext *sc = NULL;
1607 _MMCamcorderVideoInfo *videoinfo = NULL;
1609 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1611 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1612 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1614 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1615 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1616 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1618 videoinfo = sc->info_video;
1620 b_time = GST_BUFFER_PTS(buffer);
1622 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1624 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1625 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1629 /* check max time */
1630 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1631 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1632 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1634 if (!sc->isMaxtimePausing) {
1635 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1637 sc->isMaxtimePausing = TRUE;
1639 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1640 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1641 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1642 msg.param.recording_status.remained_time = 0;
1643 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1645 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1646 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1649 return GST_PAD_PROBE_DROP;
1652 /* calculate remained time can be recorded */
1653 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1654 remained_time = videoinfo->max_time - rec_pipe_time;
1655 } else if (videoinfo->max_size > 0) {
1656 long double max_size = (long double)videoinfo->max_size;
1657 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1659 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1662 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1663 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1664 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1665 msg.param.recording_status.remained_time = remained_time;
1666 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1669 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1670 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1673 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1674 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1677 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1678 record_motion_rate, videoinfo->record_drop_count);
1681 /* drop some frame if fast motion */
1682 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1683 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1685 _mmcam_dbg_warn("drop frame");
1687 return GST_PAD_PROBE_DROP;
1690 videoinfo->record_drop_count = 1;
1692 _mmcam_dbg_warn("pass frame");
1696 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1697 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1700 return GST_PAD_PROBE_OK;
1704 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1706 _MMCamcorderMsgItem msg;
1707 guint64 trailer_size = 0;
1708 guint64 rec_pipe_time = 0;
1709 _MMCamcorderSubContext *sc = NULL;
1710 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1711 _MMCamcorderVideoInfo *videoinfo = NULL;
1712 unsigned int remained_time = 0;
1713 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1715 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1716 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1717 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1719 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1720 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1721 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1723 videoinfo = sc->info_video;
1725 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1726 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1727 return GST_PAD_PROBE_OK;
1730 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1732 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1733 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1737 /* calculate remained time can be recorded */
1738 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1739 remained_time = videoinfo->max_time - rec_pipe_time;
1740 } else if (videoinfo->max_size > 0) {
1741 long double max_size = (long double)videoinfo->max_size;
1742 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1744 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1747 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1748 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1749 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1751 if (!sc->isMaxtimePausing) {
1752 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1754 sc->isMaxtimePausing = TRUE;
1756 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1757 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1758 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1759 msg.param.recording_status.remained_time = 0;
1760 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1762 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1763 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1766 return GST_PAD_PROBE_DROP;
1769 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1770 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1771 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1772 msg.param.recording_status.remained_time = remained_time;
1773 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1776 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1777 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1780 return GST_PAD_PROBE_OK;
1784 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1786 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1787 double volume = 0.0;
1790 int err = MM_ERROR_UNKNOWN;
1791 char *err_name = NULL;
1792 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1795 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1796 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1798 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1799 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1800 MMCAM_AUDIO_VOLUME, &volume,
1801 MMCAM_AUDIO_FORMAT, &format,
1802 MMCAM_AUDIO_CHANNEL, &channel,
1804 if (err != MM_ERROR_NONE) {
1805 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1806 SAFE_FREE(err_name);
1810 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1812 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1814 /* Set audio stream NULL */
1816 memset(mapinfo.data, 0, mapinfo.size);
1818 /* CALL audio stream callback */
1819 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1820 MMCamcorderAudioStreamDataType stream;
1822 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1823 _mmcam_dbg_warn("Not ready for stream callback");
1824 gst_buffer_unmap(buffer, &mapinfo);
1825 return GST_PAD_PROBE_OK;
1828 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1829 GST_BUFFER_DATA(buffer), width, height, format);*/
1831 stream.data = (void *)mapinfo.data;
1832 stream.format = format;
1833 stream.channel = channel;
1834 stream.length = mapinfo.size;
1835 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1837 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1839 if (hcamcorder->astream_cb)
1840 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1842 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1845 gst_buffer_unmap(buffer, &mapinfo);
1846 return GST_PAD_PROBE_OK;
1850 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1852 gboolean bret = FALSE;
1854 switch (fileformat) {
1855 case MM_FILE_FORMAT_3GP:
1856 case MM_FILE_FORMAT_MP4:
1857 bret = __mmcamcorder_add_metadata_mp4(handle);
1860 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1868 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1872 guint64 udta_size = 0;
1873 gint64 current_pos = 0;
1874 gint64 moov_pos = 0;
1875 gint64 udta_pos = 0;
1876 gdouble longitude = 0;
1877 gdouble latitude = 0;
1878 gdouble altitude = 0;
1880 int orientation = 0;
1882 char *err_name = NULL;
1883 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1884 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1885 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1887 _MMCamcorderVideoInfo *info = NULL;
1888 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1889 _MMCamcorderSubContext *sc = NULL;
1891 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1892 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1894 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1895 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1899 info = sc->info_video;
1901 f = fopen64(info->filename, "rb+");
1903 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1904 _mmcam_dbg_err("file open failed [%s]", err_msg);
1908 mm_camcorder_get_attributes(handle, &err_name,
1909 MMCAM_TAG_LATITUDE, &latitude,
1910 MMCAM_TAG_LONGITUDE, &longitude,
1911 MMCAM_TAG_ALTITUDE, &altitude,
1912 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1913 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1916 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1917 SAFE_FREE(err_name);
1920 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1921 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1922 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1923 geo_info.longitude = longitude *10000;
1924 geo_info.latitude = latitude *10000;
1925 geo_info.altitude = altitude *10000;
1926 /* find udta container.
1927 if, there are udta container, write loci box after that
1928 else, make udta container and write loci box. */
1929 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1932 _mmcam_dbg_log("find udta container");
1935 if (fseek(f, -8L, SEEK_CUR) != 0)
1938 udta_pos = ftello(f);
1942 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1944 _mmcam_dbg_log("recorded file fread %zu", nread);
1946 udta_size = _mmcamcorder_get_container_size(buf);
1948 /* goto end of udta and write 'loci' box */
1949 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1953 if (!_mmcamcorder_write_loci(f, location_info)) {
1954 _mmcam_dbg_err("failed to write loci");
1958 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1959 _mmcam_dbg_err("failed to write geodata");
1964 current_pos = ftello(f);
1965 if (current_pos < 0)
1968 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1971 _mmcam_dbg_log("No udta container");
1972 if (fseek(f, 0, SEEK_END) != 0)
1975 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1976 _mmcam_dbg_err("failed to write udta");
1981 /* find moov container.
1982 update moov container size. */
1983 if ((current_pos = ftello(f)) < 0)
1986 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1987 gint64 internal_pos = ftello(f);
1989 _mmcam_dbg_log("found moov container");
1990 if (fseek(f, -8L, SEEK_CUR) != 0)
1993 moov_pos = ftello(f);
1997 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2000 /* add orientation info */
2001 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2002 _mmcam_dbg_err("fseeko failed : errno %d", errno);
2006 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2007 _mmcam_dbg_err("failed to find [trak] tag");
2011 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2012 _mmcam_dbg_err("failed to find [tkhd] tag");
2016 _mmcam_dbg_log("found [tkhd] tag");
2018 /* seek to start position of composition matrix */
2019 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2020 /* update composition matrix for orientation */
2021 _mmcamcorder_update_composition_matrix(f, orientation);
2023 _mmcam_dbg_err("fseek failed : errno %d", errno);
2027 _mmcam_dbg_err("No 'moov' container");
2039 _mmcam_dbg_err("ftell() returns negative value.");
2045 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2047 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2048 _MMCamcorderSubContext *sc = NULL;
2050 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2052 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2053 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2055 /* check video source element */
2056 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2057 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2058 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2059 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2060 G_CALLBACK(__mmcamcorder_video_stream_cb),
2062 return MM_ERROR_NONE;
2064 _mmcam_dbg_err("videosrc element is not created yet");
2065 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2070 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2072 int ret = MM_ERROR_NONE;
2074 char *temp_filename = NULL;
2076 _MMCamcorderVideoInfo *info = NULL;
2077 _MMCamcorderSubContext *sc = NULL;
2078 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2080 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2082 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2083 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2084 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2086 info = sc->info_video;
2088 _mmcam_dbg_warn("start");
2090 /* create encoding pipeline */
2091 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2092 if (ret != MM_ERROR_NONE)
2093 goto _ERR_PREPARE_RECORD;
2095 SAFE_G_FREE(info->filename);
2097 mm_camcorder_get_attributes(handle, NULL,
2098 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2100 if (temp_filename) {
2101 info->filename = g_strdup(temp_filename);
2102 if (!info->filename) {
2103 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2104 goto _ERR_PREPARE_RECORD;
2107 _mmcam_dbg_log("Record file name [%s]", info->filename);
2108 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2110 _mmcam_dbg_log("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2111 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2114 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2116 /* Adjust display FPS */
2117 sc->display_interval = 0;
2118 sc->previous_slot_time = 0;
2120 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2121 if (ret != MM_ERROR_NONE)
2122 goto _ERR_PREPARE_RECORD;
2124 _mmcam_dbg_warn("done");
2128 _ERR_PREPARE_RECORD:
2129 /* Remove recorder pipeline and recording file which size maybe zero */
2130 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2131 if (info && info->filename) {
2132 _mmcam_dbg_log("file delete(%s)", info->filename);
2133 unlink(info->filename);