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*/
45 /*---------------------------------------------------------------------------------------
46 | LOCAL FUNCTION PROTOTYPES: |
47 ---------------------------------------------------------------------------------------*/
48 /* STATIC INTERNAL FUNCTION */
49 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
54 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
55 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
56 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
58 /*=======================================================================================
59 | FUNCTION DEFINITIONS |
60 =======================================================================================*/
61 /*---------------------------------------------------------------------------------------
62 | GLOBAL FUNCTION DEFINITIONS: |
63 ---------------------------------------------------------------------------------------*/
64 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
66 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
67 _MMCamcorderSubContext *sc = NULL;
69 GstBuffer *buffer = gst_sample_get_buffer(sample);
70 mmf_return_val_if_fail(buffer, FALSE);
71 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
72 mmf_return_val_if_fail(hcamcorder, FALSE);
74 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
75 mmf_return_val_if_fail(sc, FALSE);
78 _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
79 sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
82 /* push buffer in appsrc to encode */
83 if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
84 sc->info_video->record_dual_stream &&
85 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
86 GstFlowReturn ret = 0;
87 GstClock *pipe_clock = NULL;
89 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
90 if (sc->info_video->is_firstframe) {
91 sc->info_video->is_firstframe = FALSE;
92 pipe_clock = GST_ELEMENT_CLOCK(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
94 gst_object_ref(pipe_clock);
95 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);
96 gst_object_unref(pipe_clock);
100 if (sc->info_video->is_firstframe) {
101 sc->info_video->is_firstframe = FALSE;
102 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer);
106 GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS(buffer) - sc->info_video->base_video_ts;
107 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
109 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
110 if (ret != GST_FLOW_OK && ret != GST_FLOW_FLUSHING) {
111 _mmcam_dbg_err("gst_app_src_push_buffer failed [0x%x]", ret);
112 gst_buffer_unref(buffer);
116 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
118 _mmcam_dbg_warn("unref video buffer immediately - push encoding buffer %d",
119 sc->info_video->push_encoding_buffer);
121 gst_buffer_unref(buffer);
129 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
132 int err = MM_ERROR_NONE;
133 int audio_disable = FALSE;
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, &audio_disable,
171 if (sc->is_modified_rate || audio_disable)
172 sc->audio_disable = TRUE;
174 sc->audio_disable = FALSE;
176 _mmcam_dbg_log("AUDIO DISABLE : %d (is_modified_rate %d, audio_disable %d)",
177 sc->audio_disable, sc->is_modified_rate, audio_disable);
179 if (sc->audio_disable == FALSE) {
180 /* create audiosrc bin */
181 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
182 if (err != MM_ERROR_NONE)
186 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
187 if (err != MM_ERROR_NONE)
190 if (sc->audio_disable == FALSE) {
191 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
192 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
195 /* add element and encodesink bin to encode main pipeline */
196 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
197 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
198 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
199 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
202 /* Link each element : appsrc - capsfilter - encodesink bin */
203 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
204 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
205 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
207 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
208 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
209 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
211 if (sc->audio_disable == FALSE) {
212 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
213 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
214 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
217 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
218 CONFIGURE_CATEGORY_MAIN_RECORD,
221 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
223 /* set data probe function */
225 /* register message cb */
227 /* set data probe functions */
228 if (sc->audio_disable == FALSE) {
229 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
230 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
231 __mmcamcorder_audioque_dataprobe, hcamcorder);
232 gst_object_unref(sinkpad);
236 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
237 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
238 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
239 gst_object_unref(srcpad);
242 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
243 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
244 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
245 __mmcamcorder_eventprobe_monitor, hcamcorder);
246 gst_object_unref(srcpad);
251 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
252 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
253 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
254 __mmcamcorder_eventprobe_monitor, hcamcorder);
255 gst_object_unref(srcpad);
259 if (sc->audio_disable) {
260 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
261 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
262 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
263 gst_object_unref(sinkpad);
267 if (!strcmp(gst_element_rsink_name, "filesink")) {
268 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
269 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
270 __mmcamcorder_video_dataprobe_record, hcamcorder);
271 gst_object_unref(srcpad);
274 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
275 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
276 __mmcamcorder_audio_dataprobe_check, hcamcorder);
277 gst_object_unref(srcpad);
281 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
282 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
283 __mmcamcorder_muxed_dataprobe, hcamcorder);
284 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
285 __mmcamcorder_eventprobe_monitor, hcamcorder);
286 gst_object_unref(sinkpad);
289 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
291 /* register pipeline message callback */
292 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
294 /* set sync handler */
295 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
297 gst_object_unref(bus);
300 return MM_ERROR_NONE;
302 pipeline_creation_error:
303 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
304 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
306 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
311 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
313 GstPad *srcpad = NULL;
314 GstPad *sinkpad = NULL;
315 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
316 _MMCamcorderSubContext *sc = NULL;
318 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
320 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
321 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
322 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
326 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
327 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
328 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
329 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
331 /* release audiosrc bin */
332 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
333 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
336 To avoid conflicting between old elements and newly created elements,
337 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
338 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
339 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
340 It's because the pipeline of audio recording destroys at the same time,
341 and '_mmcamcorder_element_release_noti' will perfom removing handle.
343 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
345 _mmcam_dbg_log("Audio pipeline removed");
348 return MM_ERROR_NONE;
352 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
354 GstPad *reqpad = NULL;
355 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
356 _MMCamcorderSubContext *sc = NULL;
357 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
358 int ret = MM_ERROR_NONE;
359 MMCamcorderResourceManager *resource_manager = NULL;
360 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
362 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
364 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
365 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
366 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
370 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
371 /* release request pad */
372 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
374 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
375 gst_object_unref(reqpad);
379 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
381 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
382 gst_object_unref(reqpad);
386 /* release encode main pipeline */
387 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
390 To avoid conflicting between old elements and newly created elements,
391 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
392 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
393 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
394 It's because the pipeline of audio recording destroys at the same time,
395 and '_mmcamcorder_element_release_noti' will perfom removing handle.
397 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
398 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
400 _mmcam_dbg_warn("Encoder pipeline removed");
402 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
403 resource_manager = &hcamcorder->resource_manager_sub;
405 _mmcam_dbg_warn("lock resource - cb calling %d", resource_manager->is_release_cb_calling);
407 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
409 if (resource_manager->is_release_cb_calling == FALSE) {
410 /* release resource */
411 ret = _mmcamcorder_resource_manager_release(resource_manager);
413 _mmcam_dbg_warn("release resource 0x%x", ret);
414 #ifdef _MMCAMCORDER_MURPHY_WAIT_TO_RELEASE_SUB_RESOURCE
415 if (resource_manager->acquire_remain < resource_manager->acquire_count) {
416 /* wait for resource release */
417 gint64 end_time = g_get_monotonic_time() + (__MMCAMCORDER_RESOURCE_WAIT_TIME * G_TIME_SPAN_SECOND);
418 _mmcam_dbg_log("resource is not released all. wait for signal...");
419 _MMCAMCORDER_RESOURCE_WAIT_UNTIL(hcamcorder, end_time);
421 #endif /* _MMCAMCORDER_MURPHY_WAIT_TO_RELEASE_SUB_RESOURCE */
424 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
426 _mmcam_dbg_warn("unlock resource");
427 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
430 return MM_ERROR_NONE;
434 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
436 int ret = MM_ERROR_NONE;
437 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
438 _MMCamcorderSubContext *sc = NULL;
442 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
443 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
444 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
446 _mmcam_dbg_log("start");
448 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
449 _mmcam_dbg_warn("pipeline is not existed.");
450 return MM_ERROR_NONE;
453 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
455 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
456 if (ret != MM_ERROR_NONE) {
457 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
461 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
463 /* remove audio pipeline first */
464 ret = _mmcamcorder_remove_audio_pipeline(handle);
465 if (ret != MM_ERROR_NONE) {
466 _mmcam_dbg_err("Fail to remove audio pipeline");
470 ret = _mmcamcorder_remove_encode_pipeline(handle);
471 if (ret != MM_ERROR_NONE) {
472 _mmcam_dbg_err("Fail to remove encoder pipeline");
476 /* Remove pipeline message callback */
477 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
478 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
479 hcamcorder->encode_pipeline_cb_event_id = 0;
482 /* Remove remained message */
484 GstMessage *gst_msg = NULL;
485 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
486 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
487 gst_message_unref(gst_msg);
490 gst_object_unref(bus);
494 _mmcam_dbg_log("done");
500 int _mmcamcorder_video_command(MMHandleType handle, int command)
505 int ret = MM_ERROR_NONE;
506 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
507 char *err_name = NULL;
508 char *temp_filename = NULL;
509 GstCameraControl *CameraControl = NULL;
510 GstCameraControlChannel *CameraControlChannel = NULL;
511 const GList *controls = NULL;
512 const GList *item = NULL;
515 GstElement *pipeline = NULL;
517 _MMCamcorderVideoInfo *info = NULL;
518 _MMCamcorderSubContext *sc = NULL;
519 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
521 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
523 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
524 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
525 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
526 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
528 info = sc->info_video;
530 _mmcam_dbg_log("Command(%d)", command);
532 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
535 case _MMCamcorder_CMD_RECORD:
537 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
543 int ret_free_space = 0;
544 char *dir_name = NULL;
545 guint64 free_space = 0;
546 int file_system_type = 0;
547 int root_directory_length = 0;
550 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
552 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
553 /* check connection */
554 ret = _mmcamcorder_resource_check_connection(&hcamcorder->resource_manager_sub);
555 if (ret != MM_ERROR_NONE)
556 goto _ERR_CAMCORDER_VIDEO_COMMAND;
558 /* create resource set */
559 ret = _mmcamcorder_resource_create_resource_set(&hcamcorder->resource_manager_sub);
560 if (ret != MM_ERROR_NONE)
561 goto _ERR_CAMCORDER_VIDEO_COMMAND;
563 hcamcorder->resource_manager_sub.acquire_count = 0;
565 /* prepare resource manager for H/W encoder */
566 ret = _mmcamcorder_resource_manager_prepare(&hcamcorder->resource_manager_sub, MM_CAMCORDER_RESOURCE_TYPE_VIDEO_ENCODER);
567 if (ret != MM_ERROR_NONE) {
568 _mmcam_dbg_err("could not prepare for video_encoder resource");
569 ret = MM_ERROR_CAMCORDER_INTERNAL;
570 goto _ERR_CAMCORDER_VIDEO_COMMAND;
573 /* acquire resources */
574 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
576 ret = _mmcamcorder_resource_manager_acquire(&hcamcorder->resource_manager_sub);
577 if (ret != MM_ERROR_NONE) {
578 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
579 _mmcam_dbg_err("could not acquire resource");
580 goto _ERR_CAMCORDER_VIDEO_COMMAND;
583 if (hcamcorder->resource_manager_sub.acquire_remain > 0) {
586 _mmcam_dbg_warn("wait for resource state change");
588 /* wait for resource state change */
589 end_time = g_get_monotonic_time() + (__MMCAMCORDER_RESOURCE_WAIT_TIME * G_TIME_SPAN_SECOND);
591 if (_MMCAMCORDER_RESOURCE_WAIT_UNTIL(hcamcorder, end_time)) {
592 _mmcam_dbg_warn("signal received");
594 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
595 _mmcam_dbg_err("timeout");
596 ret = MM_ERROR_RESOURCE_INTERNAL;
597 goto _ERR_CAMCORDER_VIDEO_COMMAND;
600 _mmcam_dbg_log("already acquired");
603 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
604 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
606 /* init record_dual_stream */
607 info->record_dual_stream = FALSE;
609 ret = mm_camcorder_get_attributes(handle, &err_name,
610 MMCAM_CAMERA_FPS, &fps,
611 MMCAM_CAMERA_WIDTH, &(info->preview_width),
612 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
613 MMCAM_VIDEO_WIDTH, &(info->video_width),
614 MMCAM_VIDEO_HEIGHT, &(info->video_height),
615 MMCAM_FILE_FORMAT, &fileformat,
616 MMCAM_TARGET_FILENAME, &temp_filename, &size,
617 MMCAM_TARGET_MAX_SIZE, &imax_size,
618 MMCAM_TARGET_TIME_LIMIT, &imax_time,
619 MMCAM_FILE_FORMAT, &(info->fileformat),
620 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
621 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
623 if (ret != MM_ERROR_NONE) {
624 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
626 goto _ERR_CAMCORDER_VIDEO_COMMAND;
629 if (temp_filename == NULL) {
630 _mmcam_dbg_err("filename is not set");
631 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
632 goto _ERR_CAMCORDER_VIDEO_COMMAND;
637 info->max_size = 0; /* do not check */
639 info->max_size = ((guint64)imax_size) << 10; /* to byte */
643 info->max_time = 0; /* do not check */
645 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
647 dir_name = g_path_get_dirname(temp_filename);
649 ret = _mmcamcorder_get_storage_info(dir_name, hcamcorder->root_directory, &hcamcorder->storage_info);
651 _mmcam_dbg_err("get storage info failed");
654 return MM_ERROR_OUT_OF_STORAGE;
657 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
659 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
661 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
662 /* MSDOS_SUPER_MAGIC : 0x4d44 */
663 if (file_system_type == MSDOS_SUPER_MAGIC &&
664 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
665 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
666 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
667 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
669 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
670 file_system_type, info->max_size);
673 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
679 _mmcam_dbg_err("failed to get directory name");
683 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
684 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
685 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
686 return MM_ERROR_OUT_OF_STORAGE;
689 g_mutex_lock(&hcamcorder->task_thread_lock);
690 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
691 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
692 /* Play record start sound */
693 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
695 g_mutex_unlock(&hcamcorder->task_thread_lock);
697 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
699 if (info->video_width == 0 || info->video_height == 0) {
700 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
701 info->video_width, info->video_height, info->preview_width, info->preview_height);
702 info->video_width = info->preview_width;
703 info->video_height = info->preview_height;
706 if (info->support_dual_stream) {
707 _mmcam_dbg_warn("DUAL STREAM MODE");
709 info->record_dual_stream = TRUE;
711 /* No need to restart preview */
712 info->restart_preview = FALSE;
714 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
715 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
716 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
717 info->preview_width == info->video_width &&
718 info->preview_height == info->video_height) {
719 _mmcam_dbg_log("H264 preview mode and same resolution");
721 /* No need to restart preview */
722 info->restart_preview = FALSE;
724 /* always need to restart preview */
725 info->restart_preview = TRUE;
728 /* set recording hint */
729 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
731 if (info->restart_preview) {
732 /* stop preview and set new size */
733 _mmcam_dbg_log("restart preview");
735 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
736 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
737 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
739 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
741 /* check decoder recreation */
742 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
743 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
744 ret = MM_ERROR_CAMCORDER_INTERNAL;
745 goto _ERR_CAMCORDER_VIDEO_COMMAND;
748 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
749 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
750 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
752 if (ret != MM_ERROR_NONE)
753 goto _ERR_CAMCORDER_VIDEO_COMMAND;
755 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
756 ret = MM_ERROR_CAMCORDER_INTERNAL;
757 goto _ERR_CAMCORDER_VIDEO_COMMAND;
760 /* Start preview again with new setting */
761 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
762 if (ret != MM_ERROR_NONE)
763 goto _ERR_CAMCORDER_VIDEO_COMMAND;
765 if (motion_rate < 1.0) {
766 _mmcam_dbg_warn("wait for stabilization of frame");
770 _mmcam_dbg_log("no need to restart preview");
773 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
774 CONFIGURE_CATEGORY_MAIN_RECORD,
778 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
779 CONFIGURE_CATEGORY_MAIN_RECORD,
780 "PassFirstVideoFrame",
781 &(sc->pass_first_vframe));
783 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
784 sc->drop_vframe, sc->pass_first_vframe);
786 info->record_drop_count = (guint)motion_rate;
787 info->record_motion_rate = motion_rate;
788 if (sc->is_modified_rate)
789 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
791 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
793 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
794 fps, info->record_motion_rate, info->record_timestamp_ratio);
796 /* set push buffer flag */
797 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
798 info->base_video_ts = 0;
800 /* connect video stream cb signal */
801 /*130826 Connect video stream cb for handling fast record frame cb*/
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_firstframe = 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 camera control to create 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 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
888 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
889 controls = gst_camera_control_list_channels(CameraControl);
890 if (controls != NULL) {
891 for (item = controls ; item && item->data ; item = item->next) {
892 CameraControlChannel = item->data;
893 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
894 if (!strcmp(CameraControlChannel->label, "new-gop")) {
895 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
901 _mmcam_dbg_warn("failed to find new-gop control channel");
904 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
905 sc->info_image->preview_format);
910 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
911 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
912 /* generate and I-frame on resuming */
913 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
914 controls = gst_camera_control_list_channels(CameraControl);
915 if (controls != NULL) {
916 for (item = controls ; item && item->data ; item = item->next) {
917 CameraControlChannel = item->data;
918 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
919 if (!strcmp(CameraControlChannel->label, "new-gop")) {
920 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
926 _mmcam_dbg_warn("failed to find new-gop control channel");
930 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
932 _mmcam_dbg_log("Object property settings done");
936 case _MMCamcorder_CMD_PAUSE:
938 if (info->b_commiting) {
939 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
940 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
943 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
944 if (sc->audio_disable) {
945 /* check only video frame */
946 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
948 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
949 _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
950 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
952 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", count, info->video_frame_count);
955 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
957 /* check both of video and audio frame */
958 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
960 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
961 _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
962 info->video_frame_count, info->audio_frame_count);
963 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
965 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
966 count, info->video_frame_count, info->audio_frame_count);
969 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
973 /* block encodebin */
974 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
977 case _MMCamcorder_CMD_CANCEL:
979 if (info->b_commiting) {
980 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
981 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
984 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
986 if (hcamcorder->capture_in_recording == FALSE) {
988 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
989 _mmcam_dbg_err("Failed to Wait capture data");
990 hcamcorder->capture_in_recording = FALSE;
993 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
996 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
999 /* block push buffer */
1000 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1002 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1003 if (ret != MM_ERROR_NONE)
1004 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1006 /* set recording hint */
1007 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1009 /* stop video stream */
1010 if (info->record_dual_stream) {
1011 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1012 if (CameraControl) {
1013 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1015 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1016 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1018 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1020 _mmcam_dbg_err("failed to get camera control");
1024 if (info->restart_preview) {
1025 /* restart preview */
1026 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1027 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1028 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1030 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1032 /* check decoder recreation */
1033 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1034 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1035 ret = MM_ERROR_CAMCORDER_INTERNAL;
1038 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1039 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1040 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1042 if (ret != MM_ERROR_NONE)
1043 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1045 /* reset restart_preview for inset window layout */
1046 info->restart_preview = FALSE;
1048 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1049 ret = MM_ERROR_CAMCORDER_INTERNAL;
1050 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1053 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1054 if (ret != MM_ERROR_NONE)
1055 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1058 /* remove target file */
1059 if (info->filename) {
1060 _mmcam_dbg_log("file delete(%s)", info->filename);
1061 unlink(info->filename);
1064 sc->isMaxsizePausing = FALSE;
1065 sc->isMaxtimePausing = FALSE;
1067 sc->display_interval = 0;
1068 sc->previous_slot_time = 0;
1069 info->video_frame_count = 0;
1070 info->audio_frame_count = 0;
1072 hcamcorder->capture_in_recording = FALSE;
1075 case _MMCamcorder_CMD_COMMIT:
1077 if (info->b_commiting) {
1078 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
1079 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1081 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
1082 info->b_commiting = TRUE;
1083 sc->bget_eos = FALSE;
1086 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1087 if (sc->audio_disable) {
1088 /* check only video frame */
1089 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1090 hcamcorder->capture_in_recording == FALSE) {
1092 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1093 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1094 info->video_frame_count, hcamcorder->capture_in_recording);
1096 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1097 _mmcam_dbg_warn("video frames are enough. keep going...");
1099 info->b_commiting = FALSE;
1100 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1103 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1104 count, info->video_frame_count, hcamcorder->capture_in_recording);
1107 /* check both of video and audio frame */
1108 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1109 info->audio_frame_count &&
1110 hcamcorder->capture_in_recording == FALSE) {
1112 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1113 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1114 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1116 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1117 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1119 info->b_commiting = FALSE;
1120 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1123 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1125 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1126 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1130 if (hcamcorder->capture_in_recording) {
1131 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1132 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1133 _mmcam_dbg_warn("signal received");
1135 _mmcam_dbg_warn("timeout");
1138 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1142 /* block push buffer */
1143 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1144 _mmcam_dbg_log("block push buffer to appsrc");
1146 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1147 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1148 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1150 _mmcam_dbg_err("VIDEO: send EOS failed");
1151 info->b_commiting = FALSE;
1152 ret = MM_ERROR_CAMCORDER_INTERNAL;
1153 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1156 _mmcam_dbg_err("No video stream source");
1157 info->b_commiting = FALSE;
1158 ret = MM_ERROR_CAMCORDER_INTERNAL;
1159 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1162 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1163 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1164 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1166 _mmcam_dbg_err("AUDIO: send EOS failed");
1167 info->b_commiting = FALSE;
1168 ret = MM_ERROR_CAMCORDER_INTERNAL;
1169 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1172 _mmcam_dbg_log("No audio stream");
1176 sc->display_interval = 0;
1177 sc->previous_slot_time = 0;
1180 _mmcam_dbg_log("Start to wait EOS");
1181 ret = _mmcamcorder_get_eos_message(handle);
1182 if (ret != MM_ERROR_NONE) {
1183 info->b_commiting = FALSE;
1184 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1188 hcamcorder->capture_in_recording = FALSE;
1192 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1193 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1196 return MM_ERROR_NONE;
1198 _ERR_CAMCORDER_VIDEO_COMMAND:
1199 if (command == _MMCamcorder_CMD_RECORD)
1200 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1206 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1208 int ret = MM_ERROR_NONE;
1210 guint64 file_size = 0;
1212 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1213 _MMCamcorderSubContext *sc = NULL;
1214 _MMCamcorderVideoInfo *info = NULL;
1215 _MMCamcorderMsgItem msg;
1216 MMCamRecordingReport *report = NULL;
1218 mmf_return_val_if_fail(hcamcorder, FALSE);
1220 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1221 mmf_return_val_if_fail(sc, FALSE);
1222 mmf_return_val_if_fail(sc->info_video, FALSE);
1224 info = sc->info_video;
1228 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1229 /* Play record stop sound */
1230 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1232 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1234 _mmcamcorder_sound_init(handle);
1236 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1238 _mmcamcorder_sound_finalize(handle);
1241 /* remove blocking part */
1242 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1244 mm_camcorder_get_attributes(handle, NULL,
1245 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1248 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1249 if (ret != MM_ERROR_NONE)
1250 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1252 /* set recording hint */
1253 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1255 /* stop video stream */
1256 if (info->record_dual_stream) {
1257 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1259 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1261 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1262 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1264 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1266 _mmcam_dbg_err("failed to get camera control");
1270 if (enabletag && !(sc->ferror_send)) {
1271 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1273 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1275 _mmcam_dbg_err("Writing location information FAILED !!");
1279 /* Check file size */
1280 if (info->max_size > 0) {
1281 _mmcamcorder_get_file_size(info->filename, &file_size);
1282 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1283 info->max_size, file_size);
1285 if (file_size > info->max_size) {
1286 _MMCamcorderMsgItem message;
1287 _mmcam_dbg_err("File size is greater than max size !!");
1288 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1289 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1290 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1294 if (info->restart_preview) {
1296 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1297 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1298 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1300 _mmcam_dbg_log("Set state of pipeline as READY");
1301 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1303 /* check decoder recreation */
1304 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1305 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1306 ret = MM_ERROR_CAMCORDER_INTERNAL;
1310 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1311 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1312 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1314 if (ret != MM_ERROR_NONE) {
1315 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1316 msg.param.code = ret;
1317 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1318 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1321 /* reset restart_preview for inset window layout */
1322 info->restart_preview = FALSE;
1324 /* recover preview size */
1325 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1327 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1328 /* Do not return when error is occurred.
1329 Recording file was created successfully, but starting pipeline failed */
1330 if (ret != MM_ERROR_NONE) {
1331 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1332 msg.param.code = ret;
1333 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1334 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1337 _mmcam_dbg_log("No need to restart preview");
1340 /* Send recording report to application */
1341 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1342 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1344 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1346 report->recording_filename = g_strdup(info->filename);
1347 msg.param.data = report;
1349 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1353 sc->pipeline_time = 0;
1355 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1356 sc->isMaxtimePausing = FALSE;
1357 hcamcorder->error_occurs = FALSE;
1359 info->video_frame_count = 0;
1360 info->audio_frame_count = 0;
1362 info->b_commiting = FALSE;
1364 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1365 /* check recording stop sound */
1366 _mmcamcorder_sound_solo_play_wait(handle);
1369 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1375 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1377 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1378 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1380 _MMCamcorderSubContext *sc = NULL;
1381 _MMCamcorderVideoInfo *videoinfo = NULL;
1382 _MMCamcorderMsgItem msg;
1383 guint64 buffer_size = 0;
1384 guint64 trailer_size = 0;
1385 guint64 max_size = 0;
1387 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1388 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1389 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1391 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1392 videoinfo = sc->info_video;
1394 /* get buffer size */
1395 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1396 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1397 return GST_PAD_PROBE_OK;
1400 buffer_size = mapinfo.size;
1401 gst_buffer_unmap(buffer, &mapinfo);
1403 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1405 g_mutex_lock(&videoinfo->size_check_lock);
1407 if (videoinfo->audio_frame_count == 0) {
1408 videoinfo->filesize += buffer_size;
1409 videoinfo->audio_frame_count++;
1410 g_mutex_unlock(&videoinfo->size_check_lock);
1411 return GST_PAD_PROBE_OK;
1414 if (sc->ferror_send || sc->isMaxsizePausing) {
1415 _mmcam_dbg_warn("Recording is paused, drop frames");
1416 g_mutex_unlock(&videoinfo->size_check_lock);
1417 return GST_PAD_PROBE_DROP;
1420 /* get trailer size */
1421 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1422 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1427 /* check max size of recorded file */
1428 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1429 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1430 GstState pipeline_state = GST_STATE_VOID_PENDING;
1431 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1432 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1433 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1434 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1435 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1437 if (!sc->isMaxsizePausing) {
1438 sc->isMaxsizePausing = TRUE;
1439 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1440 if (pipeline_state == GST_STATE_PLAYING)
1441 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1443 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1444 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1447 g_mutex_unlock(&videoinfo->size_check_lock);
1452 videoinfo->filesize += buffer_size;
1453 videoinfo->audio_frame_count++;
1455 g_mutex_unlock(&videoinfo->size_check_lock);
1457 return GST_PAD_PROBE_OK;
1461 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1466 guint64 free_space = 0;
1467 guint64 buffer_size = 0;
1468 guint64 trailer_size = 0;
1469 guint64 queued_buffer = 0;
1470 guint64 max_size = 0;
1471 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1473 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1475 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1476 _MMCamcorderMsgItem msg;
1477 _MMCamcorderSubContext *sc = NULL;
1478 _MMCamcorderVideoInfo *videoinfo = NULL;
1480 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1481 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1483 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1484 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1485 videoinfo = sc->info_video;
1487 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1488 if (sc->ferror_send) {
1489 _mmcam_dbg_warn("file write error, drop frames");
1490 return GST_PAD_PROBE_DROP;
1493 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1494 buffer_size = mapinfo.size;
1495 gst_buffer_unmap(buffer, &mapinfo);
1497 videoinfo->video_frame_count++;
1498 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1499 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1500 info->video_frame_count); */
1501 g_mutex_lock(&videoinfo->size_check_lock);
1502 videoinfo->filesize += buffer_size;
1503 g_mutex_unlock(&videoinfo->size_check_lock);
1504 return GST_PAD_PROBE_OK;
1507 /* get trailer size */
1508 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1509 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1514 /* check free space */
1515 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1517 _mmcam_dbg_err("Error occured. [%d]", ret);
1518 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1519 sc->ferror_send = TRUE;
1521 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1522 msg.param.code = MM_ERROR_FILE_READ;
1524 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1529 return GST_PAD_PROBE_DROP; /* skip this buffer */
1532 if (free_space == 0) {
1533 /* check storage state */
1534 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1536 _mmcam_dbg_warn("storage state %d", storage_state);
1538 if (storage_state == STORAGE_STATE_REMOVED ||
1539 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1540 _mmcam_dbg_err("storage was removed!");
1542 _MMCAMCORDER_LOCK(hcamcorder);
1544 if (sc->ferror_send == FALSE) {
1545 _mmcam_dbg_err("OUT_OF_STORAGE error");
1547 sc->ferror_send = TRUE;
1549 _MMCAMCORDER_UNLOCK(hcamcorder);
1551 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1552 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1554 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1556 _MMCAMCORDER_UNLOCK(hcamcorder);
1557 _mmcam_dbg_warn("error was already sent");
1560 return GST_PAD_PROBE_DROP;
1564 /* get queued buffer size */
1565 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1566 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1569 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1570 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1573 queued_buffer = aq_size + vq_size;
1575 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1576 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1577 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1578 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1579 free_space, trailer_size, buffer_size, queued_buffer);
1581 if (!sc->isMaxsizePausing) {
1582 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1583 sc->isMaxsizePausing = TRUE;
1585 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1586 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1589 return GST_PAD_PROBE_DROP;
1592 g_mutex_lock(&videoinfo->size_check_lock);
1594 /* check max size of recorded file */
1595 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1596 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1597 GstState pipeline_state = GST_STATE_VOID_PENDING;
1598 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1599 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1600 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1601 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1602 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1604 if (!sc->isMaxsizePausing) {
1605 sc->isMaxsizePausing = TRUE;
1606 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1607 if (pipeline_state == GST_STATE_PLAYING)
1608 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1610 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1611 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1614 g_mutex_unlock(&videoinfo->size_check_lock);
1616 return GST_PAD_PROBE_DROP;
1619 videoinfo->filesize += (guint64)buffer_size;
1622 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1625 g_mutex_unlock(&videoinfo->size_check_lock);
1627 return GST_PAD_PROBE_OK;
1631 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1633 guint64 trailer_size = 0;
1634 guint64 rec_pipe_time = 0;
1635 unsigned int remained_time = 0;
1637 GstClockTime b_time;
1639 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1640 _MMCamcorderMsgItem msg;
1641 _MMCamcorderSubContext *sc = NULL;
1642 _MMCamcorderVideoInfo *videoinfo = NULL;
1644 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1646 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1647 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1649 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1650 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1651 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1653 videoinfo = sc->info_video;
1655 b_time = GST_BUFFER_PTS(buffer);
1657 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1659 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1660 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1665 /* check max time */
1666 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1667 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1668 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1670 if (!sc->isMaxtimePausing) {
1671 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1673 sc->isMaxtimePausing = TRUE;
1675 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1676 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1677 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1678 msg.param.recording_status.remained_time = 0;
1679 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1681 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1682 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1685 return GST_PAD_PROBE_DROP;
1688 /* calculate remained time can be recorded */
1689 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1690 remained_time = videoinfo->max_time - rec_pipe_time;
1691 } else if (videoinfo->max_size > 0) {
1692 long double max_size = (long double)videoinfo->max_size;
1693 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1695 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1698 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1699 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1700 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1701 msg.param.recording_status.remained_time = remained_time;
1702 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1705 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1706 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1709 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1710 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1713 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1714 record_motion_rate, videoinfo->record_drop_count);
1717 /* drop some frame if fast motion */
1718 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1719 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1721 _mmcam_dbg_warn("drop frame");
1723 return GST_PAD_PROBE_DROP;
1726 videoinfo->record_drop_count = 1;
1728 _mmcam_dbg_warn("pass frame");
1732 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1733 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1736 return GST_PAD_PROBE_OK;
1740 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1742 _MMCamcorderMsgItem msg;
1743 guint64 trailer_size = 0;
1744 guint64 rec_pipe_time = 0;
1745 _MMCamcorderSubContext *sc = NULL;
1746 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1747 _MMCamcorderVideoInfo *videoinfo = NULL;
1748 unsigned int remained_time = 0;
1749 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1751 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1752 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1753 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1755 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1756 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1757 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1759 videoinfo = sc->info_video;
1761 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1762 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1763 return GST_PAD_PROBE_OK;
1766 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1768 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1769 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1774 /* calculate remained time can be recorded */
1775 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1776 remained_time = videoinfo->max_time - rec_pipe_time;
1777 } else if (videoinfo->max_size > 0) {
1778 long double max_size = (long double)videoinfo->max_size;
1779 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1781 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1784 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1785 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1786 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1788 if (!sc->isMaxtimePausing) {
1789 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1791 sc->isMaxtimePausing = TRUE;
1793 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1794 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1795 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1796 msg.param.recording_status.remained_time = 0;
1797 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1799 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1800 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1803 return GST_PAD_PROBE_DROP;
1806 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1807 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1808 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1809 msg.param.recording_status.remained_time = remained_time;
1810 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1813 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1814 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1817 return GST_PAD_PROBE_OK;
1821 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1823 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1824 double volume = 0.0;
1827 int err = MM_ERROR_UNKNOWN;
1828 char *err_name = NULL;
1829 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1832 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1833 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1835 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1836 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1837 MMCAM_AUDIO_VOLUME, &volume,
1838 MMCAM_AUDIO_FORMAT, &format,
1839 MMCAM_AUDIO_CHANNEL, &channel,
1841 if (err != MM_ERROR_NONE) {
1842 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1843 SAFE_FREE(err_name);
1847 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1849 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1851 /* Set audio stream NULL */
1853 memset(mapinfo.data, 0, mapinfo.size);
1855 /* CALL audio stream callback */
1856 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1857 MMCamcorderAudioStreamDataType stream;
1859 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1860 _mmcam_dbg_warn("Not ready for stream callback");
1861 gst_buffer_unmap(buffer, &mapinfo);
1862 return GST_PAD_PROBE_OK;
1865 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1866 GST_BUFFER_DATA(buffer), width, height, format);*/
1868 stream.data = (void *)mapinfo.data;
1869 stream.format = format;
1870 stream.channel = channel;
1871 stream.length = mapinfo.size;
1872 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1874 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1876 if (hcamcorder->astream_cb)
1877 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1879 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1882 gst_buffer_unmap(buffer, &mapinfo);
1883 return GST_PAD_PROBE_OK;
1887 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1889 gboolean bret = FALSE;
1891 switch (fileformat) {
1892 case MM_FILE_FORMAT_3GP:
1893 case MM_FILE_FORMAT_MP4:
1894 bret = __mmcamcorder_add_metadata_mp4(handle);
1897 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1905 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1909 guint64 udta_size = 0;
1910 gint64 current_pos = 0;
1911 gint64 moov_pos = 0;
1912 gint64 udta_pos = 0;
1913 gdouble longitude = 0;
1914 gdouble latitude = 0;
1915 gdouble altitude = 0;
1917 int orientation = 0;
1919 char *err_name = NULL;
1920 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1921 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1922 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1924 _MMCamcorderVideoInfo *info = NULL;
1925 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1926 _MMCamcorderSubContext *sc = NULL;
1928 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1929 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1931 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1932 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1936 info = sc->info_video;
1938 f = fopen64(info->filename, "rb+");
1940 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1941 _mmcam_dbg_err("file open failed [%s]", err_msg);
1945 mm_camcorder_get_attributes(handle, &err_name,
1946 MMCAM_TAG_LATITUDE, &latitude,
1947 MMCAM_TAG_LONGITUDE, &longitude,
1948 MMCAM_TAG_ALTITUDE, &altitude,
1949 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1950 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1953 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1954 SAFE_FREE(err_name);
1957 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1958 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1959 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1960 geo_info.longitude = longitude *10000;
1961 geo_info.latitude = latitude *10000;
1962 geo_info.altitude = altitude *10000;
1963 /* find udta container.
1964 if, there are udta container, write loci box after that
1965 else, make udta container and write loci box. */
1966 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1969 _mmcam_dbg_log("find udta container");
1972 if (fseek(f, -8L, SEEK_CUR) != 0)
1975 udta_pos = ftello(f);
1979 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1981 _mmcam_dbg_log("recorded file fread %d", nread);
1983 udta_size = _mmcamcorder_get_container_size(buf);
1985 /* goto end of udta and write 'loci' box */
1986 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1990 if (!_mmcamcorder_write_loci(f, location_info)) {
1991 _mmcam_dbg_err("failed to write loci");
1995 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1996 _mmcam_dbg_err("failed to write geodata");
2001 current_pos = ftello(f);
2002 if (current_pos < 0)
2005 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
2008 _mmcam_dbg_log("No udta container");
2009 if (fseek(f, 0, SEEK_END) != 0)
2012 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
2013 _mmcam_dbg_err("failed to write udta");
2018 /* find moov container.
2019 update moov container size. */
2020 if ((current_pos = ftello(f)) < 0)
2023 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
2024 gint64 internal_pos = ftello(f);
2026 _mmcam_dbg_log("found moov container");
2027 if (fseek(f, -8L, SEEK_CUR) != 0)
2030 moov_pos = ftello(f);
2034 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2037 /* add orientation info */
2038 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2039 _mmcam_dbg_err("fseek failed : errno %d", errno);
2043 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2044 _mmcam_dbg_err("failed to find [trak] tag");
2048 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2049 _mmcam_dbg_err("failed to find [tkhd] tag");
2053 _mmcam_dbg_log("found [tkhd] tag");
2055 /* seek to start position of composition matrix */
2056 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
2058 /* update composition matrix for orientation */
2059 _mmcamcorder_update_composition_matrix(f, orientation);
2061 _mmcam_dbg_err("No 'moov' container");
2073 _mmcam_dbg_err("ftell() returns negative value.");
2079 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2081 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2082 _MMCamcorderSubContext *sc = NULL;
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 && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2089 /* check video source element */
2090 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2091 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2092 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2093 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2094 G_CALLBACK(__mmcamcorder_video_stream_cb),
2096 return MM_ERROR_NONE;
2098 _mmcam_dbg_err("videosrc element is not created yet");
2099 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2104 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2106 int ret = MM_ERROR_NONE;
2108 _MMCamcorderVideoInfo *info = NULL;
2109 _MMCamcorderSubContext *sc = NULL;
2110 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2112 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2114 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2115 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2116 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2118 info = sc->info_video;
2120 _mmcam_dbg_warn("start");
2122 /* create encoding pipeline */
2123 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2124 if (ret != MM_ERROR_NONE)
2125 goto _ERR_PREPARE_RECORD;
2127 if (info->filename == NULL) {
2128 char *temp_filename = NULL;
2131 mm_camcorder_get_attributes(handle, NULL,
2132 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2135 info->filename = g_strdup(temp_filename);
2137 if (!info->filename) {
2138 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2139 goto _ERR_PREPARE_RECORD;
2143 _mmcam_dbg_log("Record file name [%s]", info->filename);
2145 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2146 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2148 /* Adjust display FPS */
2149 sc->display_interval = 0;
2150 sc->previous_slot_time = 0;
2152 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2153 if (ret != MM_ERROR_NONE)
2154 goto _ERR_PREPARE_RECORD;
2156 _mmcam_dbg_warn("done");
2160 _ERR_PREPARE_RECORD:
2161 /* Remove recorder pipeline and recording file which size maybe zero */
2162 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2163 if (info && info->filename) {
2164 _mmcam_dbg_log("file delete(%s)", info->filename);
2165 unlink(info->filename);