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/video/cameracontrol.h>
26 #include <gst/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
30 /*---------------------------------------------------------------------------------------
31 | GLOBAL VARIABLE DEFINITIONS for internal |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_LOCATION_INFO /* for add gps information */
34 #define MAX_ERROR_MESSAGE_LEN 128
36 /*---------------------------------------------------------------------------------------
37 | LOCAL VARIABLE DEFINITIONS for internal |
38 ---------------------------------------------------------------------------------------*/
39 #define _MMCAMCORDER_MINIMUM_FRAME 5
40 #define _MMCAMCORDER_RETRIAL_COUNT 10
41 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* ms */
42 #define _OFFSET_COMPOSITION_MATRIX 40L
43 #define _GOP_GEN_INTERVAL 1000000000 /*nano seconds*/
44 #define _MMCAMCORDER_VIDEO_MINIMUM_SPACE (_MMCAMCORDER_MINIMUM_SPACE << 1) /* byte */
46 /*---------------------------------------------------------------------------------------
47 | LOCAL FUNCTION PROTOTYPES: |
48 ---------------------------------------------------------------------------------------*/
49 /* STATIC INTERNAL FUNCTION */
50 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
54 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
55 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
56 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
57 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
59 /*=======================================================================================
60 | FUNCTION DEFINITIONS |
61 =======================================================================================*/
62 /*---------------------------------------------------------------------------------------
63 | GLOBAL FUNCTION DEFINITIONS: |
64 ---------------------------------------------------------------------------------------*/
65 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
67 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
68 _MMCamcorderSubContext *sc = NULL;
70 GstBuffer *buffer = gst_sample_get_buffer(sample);
71 mmf_return_val_if_fail(buffer, FALSE);
72 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
73 mmf_return_val_if_fail(hcamcorder, FALSE);
75 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
76 mmf_return_val_if_fail(sc, FALSE);
79 _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
80 sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
83 /* push buffer in appsrc to encode */
84 if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
85 sc->info_video->record_dual_stream &&
86 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
87 GstFlowReturn ret = 0;
88 GstClock *pipe_clock = NULL;
90 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
91 if (sc->info_video->is_firstframe) {
92 sc->info_video->is_firstframe = FALSE;
93 pipe_clock = GST_ELEMENT_CLOCK(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
95 gst_object_ref(pipe_clock);
96 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer) - (gst_clock_get_time(pipe_clock) - GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
97 gst_object_unref(pipe_clock);
101 if (sc->info_video->is_firstframe) {
102 sc->info_video->is_firstframe = FALSE;
103 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer);
107 GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS(buffer) - sc->info_video->base_video_ts;
108 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
110 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
111 if (ret != GST_FLOW_OK && ret != GST_FLOW_FLUSHING) {
112 _mmcam_dbg_err("gst_app_src_push_buffer failed [0x%x]", ret);
113 gst_buffer_unref(buffer);
117 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
119 _mmcam_dbg_warn("unref video buffer immediately - push encoding buffer %d",
120 sc->info_video->push_encoding_buffer);
122 gst_buffer_unref(buffer);
130 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
133 int err = MM_ERROR_NONE;
134 const char* gst_element_rsink_name = NULL;
137 GstPad *srcpad = NULL;
138 GstPad *sinkpad = NULL;
140 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
141 _MMCamcorderSubContext *sc = NULL;
143 type_element *RecordsinkElement = NULL;
145 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
147 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
148 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
149 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
151 _mmcam_dbg_warn("start");
153 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
154 if (err != MM_ERROR_NONE)
158 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
159 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
160 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
161 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
164 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
166 /* get audio disable */
167 mm_camcorder_get_attributes(handle, NULL,
168 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
171 _mmcam_dbg_log("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d",
172 sc->audio_disable, sc->is_modified_rate);
174 sc->audio_disable |= sc->is_modified_rate;
176 if (sc->audio_disable == FALSE) {
177 /* create audiosrc bin */
178 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
179 if (err != MM_ERROR_NONE)
183 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
184 if (err != MM_ERROR_NONE)
187 if (sc->audio_disable == FALSE) {
188 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
189 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
192 /* add element and encodesink bin to encode main pipeline */
193 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
194 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
195 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
196 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
199 /* Link each element : appsrc - capsfilter - encodesink bin */
200 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
201 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
202 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
204 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
205 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
206 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
208 if (sc->audio_disable == FALSE) {
209 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
210 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
211 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
214 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
215 CONFIGURE_CATEGORY_MAIN_RECORD,
218 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
220 if (!gst_element_rsink_name) {
221 _mmcam_dbg_err("failed to get recordsink name");
222 err = MM_ERROR_CAMCORDER_INTERNAL;
223 goto pipeline_creation_error;
226 /* set data probe function */
228 /* register message cb */
230 /* set data probe functions */
231 if (sc->audio_disable == FALSE) {
232 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
233 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
234 __mmcamcorder_audioque_dataprobe, hcamcorder);
235 gst_object_unref(sinkpad);
239 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
240 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
241 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
242 gst_object_unref(srcpad);
245 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
246 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
247 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
248 __mmcamcorder_eventprobe_monitor, hcamcorder);
249 gst_object_unref(srcpad);
254 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
255 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
256 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
257 __mmcamcorder_eventprobe_monitor, hcamcorder);
258 gst_object_unref(srcpad);
262 if (sc->audio_disable) {
263 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
264 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
265 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
266 gst_object_unref(sinkpad);
270 if (!strcmp(gst_element_rsink_name, "filesink")) {
271 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
272 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
273 __mmcamcorder_video_dataprobe_record, hcamcorder);
274 gst_object_unref(srcpad);
277 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
278 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
279 __mmcamcorder_audio_dataprobe_check, hcamcorder);
280 gst_object_unref(srcpad);
284 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
285 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
286 __mmcamcorder_muxed_dataprobe, hcamcorder);
287 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
288 __mmcamcorder_eventprobe_monitor, hcamcorder);
289 gst_object_unref(sinkpad);
292 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
294 /* register pipeline message callback */
295 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
297 /* set sync handler */
298 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
300 gst_object_unref(bus);
303 return MM_ERROR_NONE;
305 pipeline_creation_error:
306 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
307 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
309 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
314 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
316 GstPad *srcpad = NULL;
317 GstPad *sinkpad = NULL;
318 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
319 _MMCamcorderSubContext *sc = NULL;
321 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
323 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
324 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
325 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
329 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
330 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
331 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
332 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
334 /* release audiosrc bin */
335 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
336 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
339 To avoid conflicting between old elements and newly created elements,
340 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
341 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
342 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
343 It's because the pipeline of audio recording destroys at the same time,
344 and '_mmcamcorder_element_release_noti' will perfom removing handle.
346 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
348 _mmcam_dbg_log("Audio pipeline removed");
351 return MM_ERROR_NONE;
355 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
357 GstPad *reqpad = NULL;
358 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
359 _MMCamcorderSubContext *sc = NULL;
360 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
361 int ret = MM_ERROR_NONE;
362 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
364 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
366 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
367 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
368 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
372 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
373 /* release request pad */
374 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
376 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
377 gst_object_unref(reqpad);
381 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
383 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
384 gst_object_unref(reqpad);
388 /* release encode main pipeline */
389 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
392 To avoid conflicting between old elements and newly created elements,
393 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
394 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
395 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
396 It's because the pipeline of audio recording destroys at the same time,
397 and '_mmcamcorder_element_release_noti' will perfom removing handle.
399 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
400 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
402 _mmcam_dbg_warn("Encoder pipeline removed");
404 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
405 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
407 _mmcam_dbg_warn("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
409 if (hcamcorder->is_release_cb_calling == FALSE) {
410 /* release resource */
411 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
412 hcamcorder->video_encoder_resource);
413 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
414 hcamcorder->video_encoder_resource = NULL;
416 _mmcam_dbg_warn("mark resource for release 0x%x", ret);
418 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
420 _mmcam_dbg_warn("commit resource release 0x%x", ret);
423 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
425 _mmcam_dbg_warn("unlock resource");
426 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
429 return MM_ERROR_NONE;
433 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
435 int ret = MM_ERROR_NONE;
436 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
437 _MMCamcorderSubContext *sc = NULL;
441 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
442 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
443 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
445 _mmcam_dbg_log("start");
447 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
448 _mmcam_dbg_warn("pipeline is not existed.");
449 return MM_ERROR_NONE;
452 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
454 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
455 if (ret != MM_ERROR_NONE) {
456 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
460 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
462 /* remove audio pipeline first */
463 ret = _mmcamcorder_remove_audio_pipeline(handle);
464 if (ret != MM_ERROR_NONE) {
465 _mmcam_dbg_err("Fail to remove audio pipeline");
469 ret = _mmcamcorder_remove_encode_pipeline(handle);
470 if (ret != MM_ERROR_NONE) {
471 _mmcam_dbg_err("Fail to remove encoder pipeline");
475 /* Remove pipeline message callback */
476 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
477 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
478 hcamcorder->encode_pipeline_cb_event_id = 0;
481 /* Remove remained message */
483 GstMessage *gst_msg = NULL;
484 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
485 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
486 gst_message_unref(gst_msg);
489 gst_object_unref(bus);
493 _mmcam_dbg_log("done");
499 int _mmcamcorder_video_command(MMHandleType handle, int command)
504 int ret = MM_ERROR_NONE;
505 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
506 char *err_name = NULL;
507 char *temp_filename = NULL;
508 GstCameraControl *CameraControl = NULL;
509 GstCameraControlChannel *CameraControlChannel = NULL;
510 const GList *controls = NULL;
511 const GList *item = NULL;
514 GstElement *pipeline = NULL;
516 _MMCamcorderVideoInfo *info = NULL;
517 _MMCamcorderSubContext *sc = NULL;
518 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
520 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
522 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
523 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
524 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
525 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
527 info = sc->info_video;
529 _mmcam_dbg_log("Command(%d)", command);
531 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
534 case _MMCamcorder_CMD_RECORD:
536 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
542 int ret_free_space = 0;
543 char *dir_name = NULL;
544 guint64 free_space = 0;
545 int file_system_type = 0;
546 int root_directory_length = 0;
549 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
551 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
552 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
554 /* prepare resource manager for H/W encoder */
555 if (hcamcorder->video_encoder_resource == NULL) {
556 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
557 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
558 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
559 &hcamcorder->video_encoder_resource);
560 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
561 _mmcam_dbg_err("could not prepare for encoder resource");
562 ret = MM_ERROR_RESOURCE_INTERNAL;
563 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
564 goto _ERR_CAMCORDER_VIDEO_COMMAND;
567 _mmcam_dbg_log("encoder already acquired");
570 /* acquire resources */
571 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
572 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
573 _mmcam_dbg_err("could not acquire resources");
574 ret = MM_ERROR_RESOURCE_INTERNAL;
575 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
576 goto _ERR_CAMCORDER_VIDEO_COMMAND;
579 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
580 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
582 /* init record_dual_stream */
583 info->record_dual_stream = FALSE;
585 ret = mm_camcorder_get_attributes(handle, &err_name,
586 MMCAM_CAMERA_FPS, &fps,
587 MMCAM_CAMERA_WIDTH, &(info->preview_width),
588 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
589 MMCAM_VIDEO_WIDTH, &(info->video_width),
590 MMCAM_VIDEO_HEIGHT, &(info->video_height),
591 MMCAM_FILE_FORMAT, &fileformat,
592 MMCAM_TARGET_FILENAME, &temp_filename, &size,
593 MMCAM_TARGET_MAX_SIZE, &imax_size,
594 MMCAM_TARGET_TIME_LIMIT, &imax_time,
595 MMCAM_FILE_FORMAT, &(info->fileformat),
596 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
597 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
599 if (ret != MM_ERROR_NONE) {
600 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
602 goto _ERR_CAMCORDER_VIDEO_COMMAND;
605 if (!temp_filename && !hcamcorder->mstream_cb) {
606 _mmcam_dbg_err("filename is not set and muxed stream cb is NULL");
607 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
608 goto _ERR_CAMCORDER_VIDEO_COMMAND;
613 info->max_size = 0; /* do not check */
615 info->max_size = ((guint64)imax_size) << 10; /* to byte */
619 info->max_time = 0; /* do not check */
621 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
623 dir_name = g_path_get_dirname(temp_filename);
625 ret = _mmcamcorder_get_storage_info(dir_name, hcamcorder->root_directory, &hcamcorder->storage_info);
627 _mmcam_dbg_err("get storage info failed");
630 return MM_ERROR_OUT_OF_STORAGE;
633 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
635 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
637 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
638 /* MSDOS_SUPER_MAGIC : 0x4d44 */
639 if (file_system_type == MSDOS_SUPER_MAGIC &&
640 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
641 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %lu",
642 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
643 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
645 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
646 file_system_type, info->max_size);
649 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
655 _mmcam_dbg_err("failed to get directory name");
660 (ret_free_space == -1 || free_space <= _MMCAMCORDER_VIDEO_MINIMUM_SPACE)) {
661 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
662 ret_free_space, free_space, _MMCAMCORDER_VIDEO_MINIMUM_SPACE);
663 return MM_ERROR_OUT_OF_STORAGE;
666 g_mutex_lock(&hcamcorder->task_thread_lock);
667 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
668 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
669 /* Play record start sound */
670 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
672 g_mutex_unlock(&hcamcorder->task_thread_lock);
674 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
676 if (info->video_width == 0 || info->video_height == 0) {
677 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
678 info->video_width, info->video_height, info->preview_width, info->preview_height);
679 info->video_width = info->preview_width;
680 info->video_height = info->preview_height;
683 if (info->support_dual_stream) {
684 _mmcam_dbg_warn("DUAL STREAM MODE");
686 info->record_dual_stream = TRUE;
688 /* No need to restart preview */
689 info->restart_preview = FALSE;
691 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
692 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
693 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
694 info->preview_width == info->video_width &&
695 info->preview_height == info->video_height) {
696 _mmcam_dbg_log("H264 preview mode and same resolution");
698 /* No need to restart preview */
699 info->restart_preview = FALSE;
701 /* always need to restart preview */
702 info->restart_preview = TRUE;
705 /* set recording hint */
706 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
708 if (info->restart_preview) {
709 /* stop preview and set new size */
710 _mmcam_dbg_log("restart preview");
712 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
713 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
714 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
716 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
718 /* check decoder recreation */
719 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
720 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
721 ret = MM_ERROR_CAMCORDER_INTERNAL;
722 goto _ERR_CAMCORDER_VIDEO_COMMAND;
725 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
726 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
727 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
729 if (ret != MM_ERROR_NONE)
730 goto _ERR_CAMCORDER_VIDEO_COMMAND;
732 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
733 ret = MM_ERROR_CAMCORDER_INTERNAL;
734 goto _ERR_CAMCORDER_VIDEO_COMMAND;
737 /* Start preview again with new setting */
738 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
739 if (ret != MM_ERROR_NONE)
740 goto _ERR_CAMCORDER_VIDEO_COMMAND;
742 if (motion_rate < 1.0) {
743 _mmcam_dbg_warn("wait for stabilization of frame");
747 _mmcam_dbg_log("no need to restart preview");
750 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
751 CONFIGURE_CATEGORY_MAIN_RECORD,
755 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
756 CONFIGURE_CATEGORY_MAIN_RECORD,
757 "PassFirstVideoFrame",
758 &(sc->pass_first_vframe));
760 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
761 sc->drop_vframe, sc->pass_first_vframe);
763 info->record_drop_count = (guint)motion_rate;
764 info->record_motion_rate = motion_rate;
765 if (sc->is_modified_rate)
766 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
768 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
770 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
771 fps, info->record_motion_rate, info->record_timestamp_ratio);
773 /* set push buffer flag */
774 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
775 info->base_video_ts = 0;
777 /* connect video stream cb signal */
778 /*130826 Connect video stream cb for handling fast record frame cb*/
779 if (info->record_dual_stream) {
780 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
781 goto _ERR_CAMCORDER_VIDEO_COMMAND;
784 /* start video stream */
785 if (info->record_dual_stream) {
786 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
788 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
790 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
791 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
793 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
795 _mmcam_dbg_err("could not get camera control");
799 /* check pre-created encode pipeline */
800 g_mutex_lock(&hcamcorder->task_thread_lock);
801 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
802 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
803 /* create encoding pipeline */
804 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
805 if (ret != MM_ERROR_NONE) {
806 g_mutex_unlock(&hcamcorder->task_thread_lock);
807 goto _ERR_CAMCORDER_VIDEO_COMMAND;
810 g_mutex_unlock(&hcamcorder->task_thread_lock);
812 /* check recording start sound */
813 _mmcamcorder_sound_solo_play_wait(handle);
815 /**< To fix video recording hanging
816 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
817 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
818 basetime wouldn't change if you set (GstClockTime)0.
819 3. Move set start time position below PAUSED of pipeline.
822 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
823 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
826 info->video_frame_count = 0;
827 info->is_firstframe = TRUE;
828 info->audio_frame_count = 0;
830 sc->ferror_send = FALSE;
831 sc->ferror_count = 0;
832 hcamcorder->error_occurs = FALSE;
833 sc->bget_eos = FALSE;
834 sc->muxed_stream_offset = 0;
836 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
837 if (ret != MM_ERROR_NONE) {
838 /* stop video stream */
839 if (info->record_dual_stream) {
840 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
842 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
844 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
845 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
847 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
849 _mmcam_dbg_err("failed to get camera control");
853 /* Remove recorder pipeline and recording file which size maybe zero */
854 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
855 if (info->filename) {
856 _mmcam_dbg_log("file delete(%s)", info->filename);
857 unlink(info->filename);
859 goto _ERR_CAMCORDER_VIDEO_COMMAND;
862 /*set the camera control to create the GOP so that video record will get a new key frame*/
863 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
864 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
865 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
866 controls = gst_camera_control_list_channels(CameraControl);
867 if (controls != NULL) {
868 for (item = controls ; item && item->data ; item = item->next) {
869 CameraControlChannel = item->data;
870 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
871 if (!strcmp(CameraControlChannel->label, "new-gop")) {
872 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
878 _mmcam_dbg_warn("failed to find new-gop control channel");
881 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
882 sc->info_image->preview_format);
887 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
888 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
889 /* generate and I-frame on resuming */
890 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
891 controls = gst_camera_control_list_channels(CameraControl);
892 if (controls != NULL) {
893 for (item = controls ; item && item->data ; item = item->next) {
894 CameraControlChannel = item->data;
895 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
896 if (!strcmp(CameraControlChannel->label, "new-gop")) {
897 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
903 _mmcam_dbg_warn("failed to find new-gop control channel");
907 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
909 _mmcam_dbg_log("Object property settings done");
913 case _MMCamcorder_CMD_PAUSE:
915 if (info->b_commiting) {
916 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
917 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
920 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
921 if (sc->audio_disable) {
922 /* check only video frame */
923 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
925 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
926 _mmcam_dbg_err("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
927 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
929 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
932 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
934 /* check both of video and audio frame */
935 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
937 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
938 _mmcam_dbg_err("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
939 info->video_frame_count, info->audio_frame_count);
940 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
942 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
943 count, info->video_frame_count, info->audio_frame_count);
946 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
950 /* block encodebin */
951 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
954 case _MMCamcorder_CMD_CANCEL:
956 if (info->b_commiting) {
957 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
958 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
961 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
963 if (hcamcorder->capture_in_recording == FALSE) {
965 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
966 _mmcam_dbg_err("Failed to Wait capture data");
967 hcamcorder->capture_in_recording = FALSE;
970 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
973 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
976 /* block push buffer */
977 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
979 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
980 if (ret != MM_ERROR_NONE)
981 goto _ERR_CAMCORDER_VIDEO_COMMAND;
983 /* set recording hint */
984 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
986 /* stop video stream */
987 if (info->record_dual_stream) {
988 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
990 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
992 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
993 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
995 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
997 _mmcam_dbg_err("failed to get camera control");
1001 if (info->restart_preview) {
1002 /* restart preview */
1003 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1004 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1005 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1007 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1009 /* check decoder recreation */
1010 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1011 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1012 ret = MM_ERROR_CAMCORDER_INTERNAL;
1015 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1016 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1017 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1019 if (ret != MM_ERROR_NONE)
1020 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1022 /* reset restart_preview for inset window layout */
1023 info->restart_preview = FALSE;
1025 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1026 ret = MM_ERROR_CAMCORDER_INTERNAL;
1027 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1030 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1031 if (ret != MM_ERROR_NONE)
1032 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1035 /* remove target file */
1036 if (info->filename) {
1037 _mmcam_dbg_log("file delete(%s)", info->filename);
1038 unlink(info->filename);
1041 sc->isMaxsizePausing = FALSE;
1042 sc->isMaxtimePausing = FALSE;
1044 sc->display_interval = 0;
1045 sc->previous_slot_time = 0;
1046 info->video_frame_count = 0;
1047 info->audio_frame_count = 0;
1049 hcamcorder->capture_in_recording = FALSE;
1052 case _MMCamcorder_CMD_COMMIT:
1056 if (info->b_commiting) {
1057 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
1058 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1060 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
1061 info->b_commiting = TRUE;
1062 sc->bget_eos = FALSE;
1065 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1066 if (sc->audio_disable) {
1067 /* check only video frame */
1068 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1069 hcamcorder->capture_in_recording == FALSE) {
1071 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1072 _mmcam_dbg_err("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1073 info->video_frame_count, hcamcorder->capture_in_recording);
1075 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1076 _mmcam_dbg_warn("video frames are enough. keep going...");
1078 info->b_commiting = FALSE;
1079 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1082 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1083 count, info->video_frame_count, hcamcorder->capture_in_recording);
1086 /* check both of video and audio frame */
1087 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1088 info->audio_frame_count &&
1089 hcamcorder->capture_in_recording == FALSE) {
1091 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1092 _mmcam_dbg_err("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1093 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1095 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1096 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1098 info->b_commiting = FALSE;
1099 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1102 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1104 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1105 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1109 if (hcamcorder->capture_in_recording) {
1110 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1111 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1112 _mmcam_dbg_warn("timeout");
1114 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1118 /* block push buffer */
1119 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1120 _mmcam_dbg_log("block push buffer to appsrc");
1122 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1123 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1124 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1125 ret = MM_ERROR_OUT_OF_STORAGE;
1126 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1129 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1130 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1131 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1133 _mmcam_dbg_err("VIDEO: send EOS failed");
1134 info->b_commiting = FALSE;
1135 ret = MM_ERROR_CAMCORDER_INTERNAL;
1136 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1139 _mmcam_dbg_err("No video stream source");
1140 info->b_commiting = FALSE;
1141 ret = MM_ERROR_CAMCORDER_INTERNAL;
1142 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1145 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1146 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1147 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1149 _mmcam_dbg_err("AUDIO: send EOS failed");
1150 info->b_commiting = FALSE;
1151 ret = MM_ERROR_CAMCORDER_INTERNAL;
1152 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1155 _mmcam_dbg_log("No audio stream");
1159 sc->display_interval = 0;
1160 sc->previous_slot_time = 0;
1163 _mmcam_dbg_log("Start to wait EOS");
1164 ret = _mmcamcorder_get_eos_message(handle);
1165 if (ret != MM_ERROR_NONE) {
1166 info->b_commiting = FALSE;
1167 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1171 hcamcorder->capture_in_recording = FALSE;
1175 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1176 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1179 return MM_ERROR_NONE;
1181 _ERR_CAMCORDER_VIDEO_COMMAND:
1182 if (command == _MMCamcorder_CMD_RECORD)
1183 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1189 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1191 int ret = MM_ERROR_NONE;
1193 guint64 file_size = 0;
1195 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1196 _MMCamcorderSubContext *sc = NULL;
1197 _MMCamcorderVideoInfo *info = NULL;
1198 _MMCamcorderMsgItem msg;
1199 MMCamRecordingReport *report = NULL;
1201 mmf_return_val_if_fail(hcamcorder, FALSE);
1203 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1204 mmf_return_val_if_fail(sc, FALSE);
1205 mmf_return_val_if_fail(sc->info_video, FALSE);
1207 info = sc->info_video;
1211 /* Play record stop sound */
1212 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1214 /* remove blocking part */
1215 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1217 mm_camcorder_get_attributes(handle, NULL,
1218 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1221 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1222 if (ret != MM_ERROR_NONE)
1223 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1225 /* set recording hint */
1226 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1228 /* stop video stream */
1229 if (info->record_dual_stream) {
1230 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1232 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1234 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1235 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1237 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1239 _mmcam_dbg_err("failed to get camera control");
1243 if (enabletag && !(sc->ferror_send)) {
1244 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1245 _mmcam_dbg_log("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1248 /* Check file size */
1249 if (info->max_size > 0) {
1250 _mmcamcorder_get_file_size(info->filename, &file_size);
1251 _mmcam_dbg_log("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1252 info->max_size, file_size);
1254 if (file_size > info->max_size) {
1255 _MMCamcorderMsgItem message;
1256 _mmcam_dbg_err("File size is greater than max size !!");
1257 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1258 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1259 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1263 if (info->restart_preview) {
1265 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1266 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1267 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1269 _mmcam_dbg_log("Set state of pipeline as READY");
1270 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1272 /* check decoder recreation */
1273 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1274 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1275 ret = MM_ERROR_CAMCORDER_INTERNAL;
1279 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1280 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1281 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1283 if (ret != MM_ERROR_NONE) {
1284 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1285 msg.param.code = ret;
1286 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1287 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1290 /* reset restart_preview for inset window layout */
1291 info->restart_preview = FALSE;
1293 /* recover preview size */
1294 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1295 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1296 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1297 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1298 _mmcam_dbg_err("Failed to set camera resolution %dx%d",
1299 info->preview_width, info->preview_height);
1302 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1303 /* Do not return when error is occurred.
1304 Recording file was created successfully, but starting pipeline failed */
1305 if (ret != MM_ERROR_NONE) {
1306 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1307 msg.param.code = ret;
1308 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1309 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1312 _mmcam_dbg_log("No need to restart preview");
1315 /* Send recording report to application */
1316 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1317 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1319 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1321 report->recording_filename = g_strdup(info->filename);
1322 msg.param.data = report;
1324 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1328 sc->pipeline_time = 0;
1330 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1331 sc->isMaxtimePausing = FALSE;
1332 hcamcorder->error_occurs = FALSE;
1334 info->video_frame_count = 0;
1335 info->audio_frame_count = 0;
1337 info->b_commiting = FALSE;
1339 /* check recording stop sound */
1340 _mmcamcorder_sound_solo_play_wait(handle);
1342 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1348 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1350 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1351 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1353 _MMCamcorderSubContext *sc = NULL;
1354 _MMCamcorderVideoInfo *videoinfo = NULL;
1355 _MMCamcorderMsgItem msg;
1356 guint64 buffer_size = 0;
1357 guint64 trailer_size = 0;
1358 guint64 max_size = 0;
1360 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1361 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1362 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1364 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1365 videoinfo = sc->info_video;
1367 /* get buffer size */
1368 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1369 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1370 return GST_PAD_PROBE_OK;
1373 buffer_size = mapinfo.size;
1374 gst_buffer_unmap(buffer, &mapinfo);
1376 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1378 g_mutex_lock(&videoinfo->size_check_lock);
1380 if (videoinfo->audio_frame_count == 0) {
1381 videoinfo->filesize += buffer_size;
1382 videoinfo->audio_frame_count++;
1383 g_mutex_unlock(&videoinfo->size_check_lock);
1384 return GST_PAD_PROBE_OK;
1387 if (sc->ferror_send || sc->isMaxsizePausing) {
1388 _mmcam_dbg_warn("Recording is paused, drop frames");
1389 g_mutex_unlock(&videoinfo->size_check_lock);
1390 return GST_PAD_PROBE_DROP;
1393 /* get trailer size */
1394 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1395 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1399 /* check max size of recorded file */
1400 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1401 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1402 GstState pipeline_state = GST_STATE_VOID_PENDING;
1403 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1404 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1405 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1406 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1407 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1409 if (!sc->isMaxsizePausing) {
1410 sc->isMaxsizePausing = TRUE;
1411 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1412 if (pipeline_state == GST_STATE_PLAYING)
1413 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1415 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1416 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1419 g_mutex_unlock(&videoinfo->size_check_lock);
1424 videoinfo->filesize += buffer_size;
1425 videoinfo->audio_frame_count++;
1427 g_mutex_unlock(&videoinfo->size_check_lock);
1429 return GST_PAD_PROBE_OK;
1433 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1438 guint64 free_space = 0;
1439 guint64 buffer_size = 0;
1440 guint64 trailer_size = 0;
1441 guint64 queued_buffer = 0;
1442 guint64 max_size = 0;
1443 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1445 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1447 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1448 _MMCamcorderMsgItem msg;
1449 _MMCamcorderSubContext *sc = NULL;
1450 _MMCamcorderVideoInfo *videoinfo = NULL;
1452 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1453 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1455 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1456 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1457 videoinfo = sc->info_video;
1459 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1460 if (sc->ferror_send) {
1461 _mmcam_dbg_warn("file write error, drop frames");
1462 return GST_PAD_PROBE_DROP;
1465 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1466 buffer_size = mapinfo.size;
1467 gst_buffer_unmap(buffer, &mapinfo);
1469 videoinfo->video_frame_count++;
1470 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1471 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1472 info->video_frame_count); */
1473 g_mutex_lock(&videoinfo->size_check_lock);
1474 videoinfo->filesize += buffer_size;
1475 g_mutex_unlock(&videoinfo->size_check_lock);
1476 return GST_PAD_PROBE_OK;
1479 /* get trailer size */
1480 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1481 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1485 /* check free space */
1486 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1488 _mmcam_dbg_err("Error occured. [%d]", ret);
1489 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1490 sc->ferror_send = TRUE;
1492 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1493 msg.param.code = MM_ERROR_FILE_READ;
1495 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1500 return GST_PAD_PROBE_DROP; /* skip this buffer */
1503 if (free_space == 0) {
1504 /* check storage state */
1505 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1507 _mmcam_dbg_warn("storage state %d", storage_state);
1509 if (storage_state == STORAGE_STATE_REMOVED ||
1510 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1511 _mmcam_dbg_err("storage was removed!");
1513 _MMCAMCORDER_LOCK(hcamcorder);
1515 if (sc->ferror_send == FALSE) {
1516 _mmcam_dbg_err("OUT_OF_STORAGE error");
1518 sc->ferror_send = TRUE;
1520 _MMCAMCORDER_UNLOCK(hcamcorder);
1522 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1523 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1525 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1527 _MMCAMCORDER_UNLOCK(hcamcorder);
1528 _mmcam_dbg_warn("error was already sent");
1531 return GST_PAD_PROBE_DROP;
1535 /* get queued buffer size */
1536 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1537 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1539 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1540 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1542 queued_buffer = aq_size + vq_size;
1544 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1545 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1546 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1547 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1548 free_space, trailer_size, buffer_size, queued_buffer);
1550 if (!sc->isMaxsizePausing) {
1551 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1552 sc->isMaxsizePausing = TRUE;
1554 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1555 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1558 return GST_PAD_PROBE_DROP;
1561 g_mutex_lock(&videoinfo->size_check_lock);
1563 /* check max size of recorded file */
1564 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1565 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1566 GstState pipeline_state = GST_STATE_VOID_PENDING;
1567 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1568 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1569 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1570 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1571 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1573 if (!sc->isMaxsizePausing) {
1574 sc->isMaxsizePausing = TRUE;
1575 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1576 if (pipeline_state == GST_STATE_PLAYING)
1577 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1579 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1580 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1583 g_mutex_unlock(&videoinfo->size_check_lock);
1585 return GST_PAD_PROBE_DROP;
1588 videoinfo->filesize += (guint64)buffer_size;
1591 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1594 g_mutex_unlock(&videoinfo->size_check_lock);
1596 return GST_PAD_PROBE_OK;
1600 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1602 guint64 trailer_size = 0;
1603 guint64 rec_pipe_time = 0;
1604 unsigned int remained_time = 0;
1606 GstClockTime b_time;
1608 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1609 _MMCamcorderMsgItem msg;
1610 _MMCamcorderSubContext *sc = NULL;
1611 _MMCamcorderVideoInfo *videoinfo = NULL;
1613 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1615 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1616 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1618 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1619 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1620 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1622 videoinfo = sc->info_video;
1624 b_time = GST_BUFFER_PTS(buffer);
1626 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1628 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1629 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1633 /* check max time */
1634 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1635 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1636 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1638 if (!sc->isMaxtimePausing) {
1639 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1641 sc->isMaxtimePausing = TRUE;
1643 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1644 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1645 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1646 msg.param.recording_status.remained_time = 0;
1647 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1649 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1650 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1653 return GST_PAD_PROBE_DROP;
1656 /* calculate remained time can be recorded */
1657 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1658 remained_time = videoinfo->max_time - rec_pipe_time;
1659 } else if (videoinfo->max_size > 0) {
1660 long double max_size = (long double)videoinfo->max_size;
1661 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1663 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1666 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1667 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1668 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1669 msg.param.recording_status.remained_time = remained_time;
1670 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1673 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1674 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1677 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1678 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1681 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1682 record_motion_rate, videoinfo->record_drop_count);
1685 /* drop some frame if fast motion */
1686 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1687 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1689 _mmcam_dbg_warn("drop frame");
1691 return GST_PAD_PROBE_DROP;
1694 videoinfo->record_drop_count = 1;
1696 _mmcam_dbg_warn("pass frame");
1700 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1701 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1704 return GST_PAD_PROBE_OK;
1708 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1710 _MMCamcorderMsgItem msg;
1711 guint64 trailer_size = 0;
1712 guint64 rec_pipe_time = 0;
1713 _MMCamcorderSubContext *sc = NULL;
1714 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1715 _MMCamcorderVideoInfo *videoinfo = NULL;
1716 unsigned int remained_time = 0;
1717 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1719 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1720 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1721 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1723 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1724 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1725 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1727 videoinfo = sc->info_video;
1729 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1730 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1731 return GST_PAD_PROBE_OK;
1734 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1736 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1737 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1741 /* calculate remained time can be recorded */
1742 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1743 remained_time = videoinfo->max_time - rec_pipe_time;
1744 } else if (videoinfo->max_size > 0) {
1745 long double max_size = (long double)videoinfo->max_size;
1746 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1748 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1751 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1752 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1753 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1755 if (!sc->isMaxtimePausing) {
1756 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1758 sc->isMaxtimePausing = TRUE;
1760 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1761 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1762 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1763 msg.param.recording_status.remained_time = 0;
1764 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1766 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1767 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1770 return GST_PAD_PROBE_DROP;
1773 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1774 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1775 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1776 msg.param.recording_status.remained_time = remained_time;
1777 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1780 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1781 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1784 return GST_PAD_PROBE_OK;
1788 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1790 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1791 double volume = 0.0;
1794 int err = MM_ERROR_UNKNOWN;
1795 char *err_name = NULL;
1796 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1799 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1800 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1802 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1803 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1804 MMCAM_AUDIO_VOLUME, &volume,
1805 MMCAM_AUDIO_FORMAT, &format,
1806 MMCAM_AUDIO_CHANNEL, &channel,
1808 if (err != MM_ERROR_NONE) {
1809 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1810 SAFE_FREE(err_name);
1814 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1816 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1818 /* Set audio stream NULL */
1820 memset(mapinfo.data, 0, mapinfo.size);
1822 /* CALL audio stream callback */
1823 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1824 MMCamcorderAudioStreamDataType stream;
1826 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1827 _mmcam_dbg_warn("Not ready for stream callback");
1828 gst_buffer_unmap(buffer, &mapinfo);
1829 return GST_PAD_PROBE_OK;
1832 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1833 GST_BUFFER_DATA(buffer), width, height, format);*/
1835 stream.data = (void *)mapinfo.data;
1836 stream.format = format;
1837 stream.channel = channel;
1838 stream.length = mapinfo.size;
1839 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1841 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1843 if (hcamcorder->astream_cb)
1844 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1846 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1849 gst_buffer_unmap(buffer, &mapinfo);
1850 return GST_PAD_PROBE_OK;
1854 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1856 gboolean bret = FALSE;
1858 switch (fileformat) {
1859 case MM_FILE_FORMAT_3GP:
1860 case MM_FILE_FORMAT_MP4:
1861 bret = __mmcamcorder_add_metadata_mp4(handle);
1864 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1872 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1876 guint64 udta_size = 0;
1877 gint64 current_pos = 0;
1878 gint64 moov_pos = 0;
1879 gint64 udta_pos = 0;
1880 gdouble longitude = 0;
1881 gdouble latitude = 0;
1882 gdouble altitude = 0;
1884 int orientation = 0;
1886 char *err_name = NULL;
1887 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1888 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1889 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1891 _MMCamcorderVideoInfo *info = NULL;
1892 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1893 _MMCamcorderSubContext *sc = NULL;
1895 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1896 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1898 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1899 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1903 info = sc->info_video;
1905 f = fopen64(info->filename, "rb+");
1907 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1908 _mmcam_dbg_err("file open failed [%s]", err_msg);
1912 mm_camcorder_get_attributes(handle, &err_name,
1913 MMCAM_TAG_LATITUDE, &latitude,
1914 MMCAM_TAG_LONGITUDE, &longitude,
1915 MMCAM_TAG_ALTITUDE, &altitude,
1916 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1917 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1920 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1921 SAFE_FREE(err_name);
1924 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1925 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1926 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1927 geo_info.longitude = longitude *10000;
1928 geo_info.latitude = latitude *10000;
1929 geo_info.altitude = altitude *10000;
1930 /* find udta container.
1931 if, there are udta container, write loci box after that
1932 else, make udta container and write loci box. */
1933 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1936 _mmcam_dbg_log("find udta container");
1939 if (fseek(f, -8L, SEEK_CUR) != 0)
1942 udta_pos = ftello(f);
1946 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1948 _mmcam_dbg_log("recorded file fread %zu", nread);
1950 udta_size = _mmcamcorder_get_container_size(buf);
1952 /* goto end of udta and write 'loci' box */
1953 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1957 if (!_mmcamcorder_write_loci(f, location_info)) {
1958 _mmcam_dbg_err("failed to write loci");
1962 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1963 _mmcam_dbg_err("failed to write geodata");
1968 current_pos = ftello(f);
1969 if (current_pos < 0)
1972 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1975 _mmcam_dbg_log("No udta container");
1976 if (fseek(f, 0, SEEK_END) != 0)
1979 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1980 _mmcam_dbg_err("failed to write udta");
1985 /* find moov container.
1986 update moov container size. */
1987 if ((current_pos = ftello(f)) < 0)
1990 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1991 gint64 internal_pos = ftello(f);
1993 _mmcam_dbg_log("found moov container");
1994 if (fseek(f, -8L, SEEK_CUR) != 0)
1997 moov_pos = ftello(f);
2001 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2004 /* add orientation info */
2005 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2006 _mmcam_dbg_err("fseeko failed : errno %d", errno);
2010 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2011 _mmcam_dbg_err("failed to find [trak] tag");
2015 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2016 _mmcam_dbg_err("failed to find [tkhd] tag");
2020 _mmcam_dbg_log("found [tkhd] tag");
2022 /* seek to start position of composition matrix */
2023 if (fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2024 /* update composition matrix for orientation */
2025 _mmcamcorder_update_composition_matrix(f, orientation);
2027 _mmcam_dbg_err("fseek failed : errno %d", errno);
2031 _mmcam_dbg_err("No 'moov' container");
2043 _mmcam_dbg_err("ftell() returns negative value.");
2049 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2051 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2052 _MMCamcorderSubContext *sc = NULL;
2054 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2056 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2057 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2059 /* check video source element */
2060 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2061 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2062 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2063 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2064 G_CALLBACK(__mmcamcorder_video_stream_cb),
2066 return MM_ERROR_NONE;
2068 _mmcam_dbg_err("videosrc element is not created yet");
2069 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2074 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2076 int ret = MM_ERROR_NONE;
2078 char *temp_filename = NULL;
2080 _MMCamcorderVideoInfo *info = NULL;
2081 _MMCamcorderSubContext *sc = NULL;
2082 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2084 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2086 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2087 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2088 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2090 info = sc->info_video;
2092 _mmcam_dbg_warn("start");
2094 /* create encoding pipeline */
2095 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2096 if (ret != MM_ERROR_NONE)
2097 goto _ERR_PREPARE_RECORD;
2099 SAFE_G_FREE(info->filename);
2101 mm_camcorder_get_attributes(handle, NULL,
2102 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2104 if (temp_filename) {
2105 info->filename = g_strdup(temp_filename);
2106 if (!info->filename) {
2107 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2108 goto _ERR_PREPARE_RECORD;
2111 _mmcam_dbg_log("Record file name [%s]", info->filename);
2112 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2114 _mmcam_dbg_log("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2115 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2118 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2120 /* Adjust display FPS */
2121 sc->display_interval = 0;
2122 sc->previous_slot_time = 0;
2124 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2125 if (ret != MM_ERROR_NONE)
2126 goto _ERR_PREPARE_RECORD;
2128 _mmcam_dbg_warn("done");
2132 _ERR_PREPARE_RECORD:
2133 /* Remove recorder pipeline and recording file which size maybe zero */
2134 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2135 if (info && info->filename) {
2136 _mmcam_dbg_log("file delete(%s)", info->filename);
2137 unlink(info->filename);