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) {
412 /* release resource */
413 ret = _mmcamcorder_resource_manager_release(resource_manager);
415 _mmcam_dbg_warn("release resource 0x%x", ret);
416 #ifdef _MMCAMCORDER_MURPHY_WAIT_TO_RELEASE_SUB_RESOURCE
417 if (resource_manager->acquire_remain < resource_manager->acquire_count) {
418 /* wait for resource release */
419 _mmcam_dbg_log("resource is not released all. wait for signal...");
420 end_time = g_get_monotonic_time() + (__MMCAMCORDER_RESOURCE_WAIT_TIME * G_TIME_SPAN_SECOND);
421 _MMCAMCORDER_RESOURCE_WAIT_UNTIL(hcamcorder, end_time);
423 #endif /* _MMCAMCORDER_MURPHY_WAIT_TO_RELEASE_SUB_RESOURCE */
426 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
428 _mmcam_dbg_warn("unlock resource");
429 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
432 return MM_ERROR_NONE;
436 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
438 int ret = MM_ERROR_NONE;
439 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
440 _MMCamcorderSubContext *sc = NULL;
444 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
445 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
446 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
448 _mmcam_dbg_log("start");
450 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
451 _mmcam_dbg_warn("pipeline is not existed.");
452 return MM_ERROR_NONE;
455 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
457 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
458 if (ret != MM_ERROR_NONE) {
459 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
463 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
465 /* remove audio pipeline first */
466 ret = _mmcamcorder_remove_audio_pipeline(handle);
467 if (ret != MM_ERROR_NONE) {
468 _mmcam_dbg_err("Fail to remove audio pipeline");
472 ret = _mmcamcorder_remove_encode_pipeline(handle);
473 if (ret != MM_ERROR_NONE) {
474 _mmcam_dbg_err("Fail to remove encoder pipeline");
478 /* Remove pipeline message callback */
479 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
480 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
481 hcamcorder->encode_pipeline_cb_event_id = 0;
484 /* Remove remained message */
486 GstMessage *gst_msg = NULL;
487 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
488 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
489 gst_message_unref(gst_msg);
492 gst_object_unref(bus);
496 _mmcam_dbg_log("done");
502 int _mmcamcorder_video_command(MMHandleType handle, int command)
507 int ret = MM_ERROR_NONE;
508 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
509 char *err_name = NULL;
510 char *temp_filename = NULL;
511 GstCameraControl *CameraControl = NULL;
512 GstCameraControlChannel *CameraControlChannel = NULL;
513 const GList *controls = NULL;
514 const GList *item = NULL;
517 GstElement *pipeline = NULL;
519 _MMCamcorderVideoInfo *info = NULL;
520 _MMCamcorderSubContext *sc = NULL;
521 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
523 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
525 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
526 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
527 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
528 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
530 info = sc->info_video;
532 _mmcam_dbg_log("Command(%d)", command);
534 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
537 case _MMCamcorder_CMD_RECORD:
539 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
545 int ret_free_space = 0;
546 char *dir_name = NULL;
547 guint64 free_space = 0;
548 int file_system_type = 0;
549 int root_directory_length = 0;
552 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
554 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
555 /* check connection */
556 ret = _mmcamcorder_resource_check_connection(&hcamcorder->resource_manager_sub);
557 if (ret != MM_ERROR_NONE)
558 goto _ERR_CAMCORDER_VIDEO_COMMAND;
560 /* create resource set */
561 ret = _mmcamcorder_resource_create_resource_set(&hcamcorder->resource_manager_sub);
562 if (ret != MM_ERROR_NONE)
563 goto _ERR_CAMCORDER_VIDEO_COMMAND;
565 hcamcorder->resource_manager_sub.acquire_count = 0;
567 /* prepare resource manager for H/W encoder */
568 ret = _mmcamcorder_resource_manager_prepare(&hcamcorder->resource_manager_sub, MM_CAMCORDER_RESOURCE_TYPE_VIDEO_ENCODER);
569 if (ret != MM_ERROR_NONE) {
570 _mmcam_dbg_err("could not prepare for video_encoder resource");
571 ret = MM_ERROR_CAMCORDER_INTERNAL;
572 goto _ERR_CAMCORDER_VIDEO_COMMAND;
575 /* acquire resources */
576 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
578 ret = _mmcamcorder_resource_manager_acquire(&hcamcorder->resource_manager_sub);
579 if (ret != MM_ERROR_NONE) {
580 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
581 _mmcam_dbg_err("could not acquire resource");
582 goto _ERR_CAMCORDER_VIDEO_COMMAND;
585 if (hcamcorder->resource_manager_sub.acquire_remain > 0) {
588 _mmcam_dbg_warn("wait for resource state change");
590 /* wait for resource state change */
591 end_time = g_get_monotonic_time() + (__MMCAMCORDER_RESOURCE_WAIT_TIME * G_TIME_SPAN_SECOND);
593 if (_MMCAMCORDER_RESOURCE_WAIT_UNTIL(hcamcorder, end_time)) {
594 _mmcam_dbg_warn("signal received");
596 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
597 _mmcam_dbg_err("timeout");
598 ret = MM_ERROR_RESOURCE_INTERNAL;
599 goto _ERR_CAMCORDER_VIDEO_COMMAND;
602 _mmcam_dbg_log("already acquired");
605 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
606 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
608 /* init record_dual_stream */
609 info->record_dual_stream = FALSE;
611 ret = mm_camcorder_get_attributes(handle, &err_name,
612 MMCAM_CAMERA_FPS, &fps,
613 MMCAM_CAMERA_WIDTH, &(info->preview_width),
614 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
615 MMCAM_VIDEO_WIDTH, &(info->video_width),
616 MMCAM_VIDEO_HEIGHT, &(info->video_height),
617 MMCAM_FILE_FORMAT, &fileformat,
618 MMCAM_TARGET_FILENAME, &temp_filename, &size,
619 MMCAM_TARGET_MAX_SIZE, &imax_size,
620 MMCAM_TARGET_TIME_LIMIT, &imax_time,
621 MMCAM_FILE_FORMAT, &(info->fileformat),
622 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
623 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
625 if (ret != MM_ERROR_NONE) {
626 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
628 goto _ERR_CAMCORDER_VIDEO_COMMAND;
631 if (temp_filename == NULL) {
632 _mmcam_dbg_err("filename is not set");
633 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
634 goto _ERR_CAMCORDER_VIDEO_COMMAND;
639 info->max_size = 0; /* do not check */
641 info->max_size = ((guint64)imax_size) << 10; /* to byte */
645 info->max_time = 0; /* do not check */
647 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
649 dir_name = g_path_get_dirname(temp_filename);
651 ret = _mmcamcorder_get_storage_info(dir_name, hcamcorder->root_directory, &hcamcorder->storage_info);
653 _mmcam_dbg_err("get storage info failed");
656 return MM_ERROR_OUT_OF_STORAGE;
659 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
661 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
663 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
664 /* MSDOS_SUPER_MAGIC : 0x4d44 */
665 if (file_system_type == MSDOS_SUPER_MAGIC &&
666 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
667 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
668 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
669 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
671 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
672 file_system_type, info->max_size);
675 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
681 _mmcam_dbg_err("failed to get directory name");
685 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
686 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
687 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
688 return MM_ERROR_OUT_OF_STORAGE;
691 g_mutex_lock(&hcamcorder->task_thread_lock);
692 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
693 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
694 /* Play record start sound */
695 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
697 g_mutex_unlock(&hcamcorder->task_thread_lock);
699 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
701 if (info->video_width == 0 || info->video_height == 0) {
702 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
703 info->video_width, info->video_height, info->preview_width, info->preview_height);
704 info->video_width = info->preview_width;
705 info->video_height = info->preview_height;
708 if (info->support_dual_stream) {
709 _mmcam_dbg_warn("DUAL STREAM MODE");
711 info->record_dual_stream = TRUE;
713 /* No need to restart preview */
714 info->restart_preview = FALSE;
716 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
717 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
718 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
719 info->preview_width == info->video_width &&
720 info->preview_height == info->video_height) {
721 _mmcam_dbg_log("H264 preview mode and same resolution");
723 /* No need to restart preview */
724 info->restart_preview = FALSE;
726 /* always need to restart preview */
727 info->restart_preview = TRUE;
730 /* set recording hint */
731 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
733 if (info->restart_preview) {
734 /* stop preview and set new size */
735 _mmcam_dbg_log("restart preview");
737 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
738 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
739 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
741 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
743 /* check decoder recreation */
744 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
745 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
746 ret = MM_ERROR_CAMCORDER_INTERNAL;
747 goto _ERR_CAMCORDER_VIDEO_COMMAND;
750 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
751 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
752 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
754 if (ret != MM_ERROR_NONE)
755 goto _ERR_CAMCORDER_VIDEO_COMMAND;
757 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
758 ret = MM_ERROR_CAMCORDER_INTERNAL;
759 goto _ERR_CAMCORDER_VIDEO_COMMAND;
762 /* Start preview again with new setting */
763 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
764 if (ret != MM_ERROR_NONE)
765 goto _ERR_CAMCORDER_VIDEO_COMMAND;
767 if (motion_rate < 1.0) {
768 _mmcam_dbg_warn("wait for stabilization of frame");
772 _mmcam_dbg_log("no need to restart preview");
775 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
776 CONFIGURE_CATEGORY_MAIN_RECORD,
780 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
781 CONFIGURE_CATEGORY_MAIN_RECORD,
782 "PassFirstVideoFrame",
783 &(sc->pass_first_vframe));
785 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
786 sc->drop_vframe, sc->pass_first_vframe);
788 info->record_drop_count = (guint)motion_rate;
789 info->record_motion_rate = motion_rate;
790 if (sc->is_modified_rate)
791 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
793 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
795 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
796 fps, info->record_motion_rate, info->record_timestamp_ratio);
798 /* set push buffer flag */
799 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
800 info->base_video_ts = 0;
802 /* connect video stream cb signal */
803 /*130826 Connect video stream cb for handling fast record frame cb*/
804 if (info->record_dual_stream) {
805 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
806 goto _ERR_CAMCORDER_VIDEO_COMMAND;
809 /* start video stream */
810 if (info->record_dual_stream) {
811 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
813 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
815 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
816 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
818 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
820 _mmcam_dbg_err("could not get camera control");
824 /* check pre-created encode pipeline */
825 g_mutex_lock(&hcamcorder->task_thread_lock);
826 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
827 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
828 /* create encoding pipeline */
829 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
830 if (ret != MM_ERROR_NONE) {
831 g_mutex_unlock(&hcamcorder->task_thread_lock);
832 goto _ERR_CAMCORDER_VIDEO_COMMAND;
835 g_mutex_unlock(&hcamcorder->task_thread_lock);
837 /* check recording start sound */
838 _mmcamcorder_sound_solo_play_wait(handle);
840 /**< To fix video recording hanging
841 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
842 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
843 basetime wouldn't change if you set (GstClockTime)0.
844 3. Move set start time position below PAUSED of pipeline.
847 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
848 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
851 info->video_frame_count = 0;
852 info->is_firstframe = TRUE;
853 info->audio_frame_count = 0;
855 sc->ferror_send = FALSE;
856 sc->ferror_count = 0;
857 hcamcorder->error_occurs = FALSE;
858 sc->bget_eos = FALSE;
859 sc->muxed_stream_offset = 0;
861 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
862 if (ret != MM_ERROR_NONE) {
863 /* stop video stream */
864 if (info->record_dual_stream) {
865 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
867 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
869 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
870 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
872 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
874 _mmcam_dbg_err("failed to get camera control");
878 /* Remove recorder pipeline and recording file which size maybe zero */
879 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
880 if (info->filename) {
881 _mmcam_dbg_log("file delete(%s)", info->filename);
882 unlink(info->filename);
884 goto _ERR_CAMCORDER_VIDEO_COMMAND;
887 /*set the camera control to create the GOP so that video record will get a new key frame*/
888 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
889 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
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");
906 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
907 sc->info_image->preview_format);
912 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
913 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
914 /* generate and I-frame on resuming */
915 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
916 controls = gst_camera_control_list_channels(CameraControl);
917 if (controls != NULL) {
918 for (item = controls ; item && item->data ; item = item->next) {
919 CameraControlChannel = item->data;
920 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
921 if (!strcmp(CameraControlChannel->label, "new-gop")) {
922 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
928 _mmcam_dbg_warn("failed to find new-gop control channel");
932 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
934 _mmcam_dbg_log("Object property settings done");
938 case _MMCamcorder_CMD_PAUSE:
940 if (info->b_commiting) {
941 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
942 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
945 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
946 if (sc->audio_disable) {
947 /* check only video frame */
948 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
950 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
951 _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
952 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
954 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", count, info->video_frame_count);
957 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
959 /* check both of video and audio frame */
960 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
962 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
963 _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
964 info->video_frame_count, info->audio_frame_count);
965 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
967 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
968 count, info->video_frame_count, info->audio_frame_count);
971 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
975 /* block encodebin */
976 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
979 case _MMCamcorder_CMD_CANCEL:
981 if (info->b_commiting) {
982 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
983 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
986 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
988 if (hcamcorder->capture_in_recording == FALSE) {
990 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
991 _mmcam_dbg_err("Failed to Wait capture data");
992 hcamcorder->capture_in_recording = FALSE;
995 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
998 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1001 /* block push buffer */
1002 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1004 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1005 if (ret != MM_ERROR_NONE)
1006 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1008 /* set recording hint */
1009 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1011 /* stop video stream */
1012 if (info->record_dual_stream) {
1013 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1014 if (CameraControl) {
1015 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1017 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1018 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1020 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1022 _mmcam_dbg_err("failed to get camera control");
1026 if (info->restart_preview) {
1027 /* restart preview */
1028 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1029 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1030 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1032 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1034 /* check decoder recreation */
1035 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1036 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1037 ret = MM_ERROR_CAMCORDER_INTERNAL;
1040 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1041 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1042 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1044 if (ret != MM_ERROR_NONE)
1045 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1047 /* reset restart_preview for inset window layout */
1048 info->restart_preview = FALSE;
1050 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1051 ret = MM_ERROR_CAMCORDER_INTERNAL;
1052 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1055 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1056 if (ret != MM_ERROR_NONE)
1057 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1060 /* remove target file */
1061 if (info->filename) {
1062 _mmcam_dbg_log("file delete(%s)", info->filename);
1063 unlink(info->filename);
1066 sc->isMaxsizePausing = FALSE;
1067 sc->isMaxtimePausing = FALSE;
1069 sc->display_interval = 0;
1070 sc->previous_slot_time = 0;
1071 info->video_frame_count = 0;
1072 info->audio_frame_count = 0;
1074 hcamcorder->capture_in_recording = FALSE;
1077 case _MMCamcorder_CMD_COMMIT:
1079 if (info->b_commiting) {
1080 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
1081 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1083 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
1084 info->b_commiting = TRUE;
1085 sc->bget_eos = FALSE;
1088 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1089 if (sc->audio_disable) {
1090 /* check only video frame */
1091 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1092 hcamcorder->capture_in_recording == FALSE) {
1094 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1095 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1096 info->video_frame_count, hcamcorder->capture_in_recording);
1098 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1099 _mmcam_dbg_warn("video frames are enough. keep going...");
1101 info->b_commiting = FALSE;
1102 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1105 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1106 count, info->video_frame_count, hcamcorder->capture_in_recording);
1109 /* check both of video and audio frame */
1110 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1111 info->audio_frame_count &&
1112 hcamcorder->capture_in_recording == FALSE) {
1114 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1115 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1116 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1118 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1119 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1121 info->b_commiting = FALSE;
1122 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1125 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1127 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1128 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1132 if (hcamcorder->capture_in_recording) {
1133 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1134 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1135 _mmcam_dbg_warn("signal received");
1137 _mmcam_dbg_warn("timeout");
1140 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1144 /* block push buffer */
1145 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1146 _mmcam_dbg_log("block push buffer to appsrc");
1148 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1149 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1150 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1152 _mmcam_dbg_err("VIDEO: send EOS failed");
1153 info->b_commiting = FALSE;
1154 ret = MM_ERROR_CAMCORDER_INTERNAL;
1155 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1158 _mmcam_dbg_err("No video stream source");
1159 info->b_commiting = FALSE;
1160 ret = MM_ERROR_CAMCORDER_INTERNAL;
1161 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1164 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1165 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1166 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1168 _mmcam_dbg_err("AUDIO: send EOS failed");
1169 info->b_commiting = FALSE;
1170 ret = MM_ERROR_CAMCORDER_INTERNAL;
1171 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1174 _mmcam_dbg_log("No audio stream");
1178 sc->display_interval = 0;
1179 sc->previous_slot_time = 0;
1182 _mmcam_dbg_log("Start to wait EOS");
1183 ret = _mmcamcorder_get_eos_message(handle);
1184 if (ret != MM_ERROR_NONE) {
1185 info->b_commiting = FALSE;
1186 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1190 hcamcorder->capture_in_recording = FALSE;
1194 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1195 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1198 return MM_ERROR_NONE;
1200 _ERR_CAMCORDER_VIDEO_COMMAND:
1201 if (command == _MMCamcorder_CMD_RECORD)
1202 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1208 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1210 int ret = MM_ERROR_NONE;
1212 guint64 file_size = 0;
1214 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1215 _MMCamcorderSubContext *sc = NULL;
1216 _MMCamcorderVideoInfo *info = NULL;
1217 _MMCamcorderMsgItem msg;
1218 MMCamRecordingReport *report = NULL;
1220 mmf_return_val_if_fail(hcamcorder, FALSE);
1222 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1223 mmf_return_val_if_fail(sc, FALSE);
1224 mmf_return_val_if_fail(sc->info_video, FALSE);
1226 info = sc->info_video;
1230 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1231 /* Play record stop sound */
1232 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1234 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1236 _mmcamcorder_sound_init(handle);
1238 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1240 _mmcamcorder_sound_finalize(handle);
1243 /* remove blocking part */
1244 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1246 mm_camcorder_get_attributes(handle, NULL,
1247 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1250 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1251 if (ret != MM_ERROR_NONE)
1252 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1254 /* set recording hint */
1255 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1257 /* stop video stream */
1258 if (info->record_dual_stream) {
1259 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1261 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1263 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1264 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1266 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1268 _mmcam_dbg_err("failed to get camera control");
1272 if (enabletag && !(sc->ferror_send)) {
1273 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1275 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1277 _mmcam_dbg_err("Writing location information FAILED !!");
1281 /* Check file size */
1282 if (info->max_size > 0) {
1283 _mmcamcorder_get_file_size(info->filename, &file_size);
1284 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1285 info->max_size, file_size);
1287 if (file_size > info->max_size) {
1288 _MMCamcorderMsgItem message;
1289 _mmcam_dbg_err("File size is greater than max size !!");
1290 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1291 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1292 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1296 if (info->restart_preview) {
1298 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1299 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1300 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1302 _mmcam_dbg_log("Set state of pipeline as READY");
1303 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1305 /* check decoder recreation */
1306 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1307 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1308 ret = MM_ERROR_CAMCORDER_INTERNAL;
1312 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1313 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1314 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1316 if (ret != MM_ERROR_NONE) {
1317 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1318 msg.param.code = ret;
1319 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1320 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1323 /* reset restart_preview for inset window layout */
1324 info->restart_preview = FALSE;
1326 /* recover preview size */
1327 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1329 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1330 /* Do not return when error is occurred.
1331 Recording file was created successfully, but starting pipeline failed */
1332 if (ret != MM_ERROR_NONE) {
1333 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1334 msg.param.code = ret;
1335 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1336 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1339 _mmcam_dbg_log("No need to restart preview");
1342 /* Send recording report to application */
1343 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1344 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1346 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1348 report->recording_filename = g_strdup(info->filename);
1349 msg.param.data = report;
1351 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1355 sc->pipeline_time = 0;
1357 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1358 sc->isMaxtimePausing = FALSE;
1359 hcamcorder->error_occurs = FALSE;
1361 info->video_frame_count = 0;
1362 info->audio_frame_count = 0;
1364 info->b_commiting = FALSE;
1366 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1367 /* check recording stop sound */
1368 _mmcamcorder_sound_solo_play_wait(handle);
1371 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1377 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1379 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1380 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1382 _MMCamcorderSubContext *sc = NULL;
1383 _MMCamcorderVideoInfo *videoinfo = NULL;
1384 _MMCamcorderMsgItem msg;
1385 guint64 buffer_size = 0;
1386 guint64 trailer_size = 0;
1387 guint64 max_size = 0;
1389 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1390 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1391 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1393 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1394 videoinfo = sc->info_video;
1396 /* get buffer size */
1397 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1398 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1399 return GST_PAD_PROBE_OK;
1402 buffer_size = mapinfo.size;
1403 gst_buffer_unmap(buffer, &mapinfo);
1405 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1407 g_mutex_lock(&videoinfo->size_check_lock);
1409 if (videoinfo->audio_frame_count == 0) {
1410 videoinfo->filesize += buffer_size;
1411 videoinfo->audio_frame_count++;
1412 g_mutex_unlock(&videoinfo->size_check_lock);
1413 return GST_PAD_PROBE_OK;
1416 if (sc->ferror_send || sc->isMaxsizePausing) {
1417 _mmcam_dbg_warn("Recording is paused, drop frames");
1418 g_mutex_unlock(&videoinfo->size_check_lock);
1419 return GST_PAD_PROBE_DROP;
1422 /* get trailer size */
1423 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1424 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1429 /* check max size of recorded file */
1430 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1431 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1432 GstState pipeline_state = GST_STATE_VOID_PENDING;
1433 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1434 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1435 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1436 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1437 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1439 if (!sc->isMaxsizePausing) {
1440 sc->isMaxsizePausing = TRUE;
1441 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1442 if (pipeline_state == GST_STATE_PLAYING)
1443 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1445 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1446 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1449 g_mutex_unlock(&videoinfo->size_check_lock);
1454 videoinfo->filesize += buffer_size;
1455 videoinfo->audio_frame_count++;
1457 g_mutex_unlock(&videoinfo->size_check_lock);
1459 return GST_PAD_PROBE_OK;
1463 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1468 guint64 free_space = 0;
1469 guint64 buffer_size = 0;
1470 guint64 trailer_size = 0;
1471 guint64 queued_buffer = 0;
1472 guint64 max_size = 0;
1473 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1475 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1477 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1478 _MMCamcorderMsgItem msg;
1479 _MMCamcorderSubContext *sc = NULL;
1480 _MMCamcorderVideoInfo *videoinfo = NULL;
1482 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1483 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1485 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1486 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1487 videoinfo = sc->info_video;
1489 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1490 if (sc->ferror_send) {
1491 _mmcam_dbg_warn("file write error, drop frames");
1492 return GST_PAD_PROBE_DROP;
1495 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1496 buffer_size = mapinfo.size;
1497 gst_buffer_unmap(buffer, &mapinfo);
1499 videoinfo->video_frame_count++;
1500 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1501 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1502 info->video_frame_count); */
1503 g_mutex_lock(&videoinfo->size_check_lock);
1504 videoinfo->filesize += buffer_size;
1505 g_mutex_unlock(&videoinfo->size_check_lock);
1506 return GST_PAD_PROBE_OK;
1509 /* get trailer size */
1510 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1511 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1516 /* check free space */
1517 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1519 _mmcam_dbg_err("Error occured. [%d]", ret);
1520 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1521 sc->ferror_send = TRUE;
1523 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1524 msg.param.code = MM_ERROR_FILE_READ;
1526 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1531 return GST_PAD_PROBE_DROP; /* skip this buffer */
1534 if (free_space == 0) {
1535 /* check storage state */
1536 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1538 _mmcam_dbg_warn("storage state %d", storage_state);
1540 if (storage_state == STORAGE_STATE_REMOVED ||
1541 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1542 _mmcam_dbg_err("storage was removed!");
1544 _MMCAMCORDER_LOCK(hcamcorder);
1546 if (sc->ferror_send == FALSE) {
1547 _mmcam_dbg_err("OUT_OF_STORAGE error");
1549 sc->ferror_send = TRUE;
1551 _MMCAMCORDER_UNLOCK(hcamcorder);
1553 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1554 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1556 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1558 _MMCAMCORDER_UNLOCK(hcamcorder);
1559 _mmcam_dbg_warn("error was already sent");
1562 return GST_PAD_PROBE_DROP;
1566 /* get queued buffer size */
1567 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1568 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1571 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1572 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1575 queued_buffer = aq_size + vq_size;
1577 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1578 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1579 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1580 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1581 free_space, trailer_size, buffer_size, queued_buffer);
1583 if (!sc->isMaxsizePausing) {
1584 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1585 sc->isMaxsizePausing = TRUE;
1587 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1588 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1591 return GST_PAD_PROBE_DROP;
1594 g_mutex_lock(&videoinfo->size_check_lock);
1596 /* check max size of recorded file */
1597 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1598 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1599 GstState pipeline_state = GST_STATE_VOID_PENDING;
1600 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1601 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1602 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1603 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1604 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1606 if (!sc->isMaxsizePausing) {
1607 sc->isMaxsizePausing = TRUE;
1608 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1609 if (pipeline_state == GST_STATE_PLAYING)
1610 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1612 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1613 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1616 g_mutex_unlock(&videoinfo->size_check_lock);
1618 return GST_PAD_PROBE_DROP;
1621 videoinfo->filesize += (guint64)buffer_size;
1624 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1627 g_mutex_unlock(&videoinfo->size_check_lock);
1629 return GST_PAD_PROBE_OK;
1633 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1635 guint64 trailer_size = 0;
1636 guint64 rec_pipe_time = 0;
1637 unsigned int remained_time = 0;
1639 GstClockTime b_time;
1641 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1642 _MMCamcorderMsgItem msg;
1643 _MMCamcorderSubContext *sc = NULL;
1644 _MMCamcorderVideoInfo *videoinfo = NULL;
1646 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1648 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1649 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1651 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1652 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1653 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1655 videoinfo = sc->info_video;
1657 b_time = GST_BUFFER_PTS(buffer);
1659 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1661 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1662 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1667 /* check max time */
1668 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1669 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1670 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1672 if (!sc->isMaxtimePausing) {
1673 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1675 sc->isMaxtimePausing = TRUE;
1677 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1678 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1679 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1680 msg.param.recording_status.remained_time = 0;
1681 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1683 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1684 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1687 return GST_PAD_PROBE_DROP;
1690 /* calculate remained time can be recorded */
1691 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1692 remained_time = videoinfo->max_time - rec_pipe_time;
1693 } else if (videoinfo->max_size > 0) {
1694 long double max_size = (long double)videoinfo->max_size;
1695 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1697 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1700 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1701 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1702 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1703 msg.param.recording_status.remained_time = remained_time;
1704 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1707 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1708 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1711 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1712 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1715 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1716 record_motion_rate, videoinfo->record_drop_count);
1719 /* drop some frame if fast motion */
1720 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1721 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1723 _mmcam_dbg_warn("drop frame");
1725 return GST_PAD_PROBE_DROP;
1728 videoinfo->record_drop_count = 1;
1730 _mmcam_dbg_warn("pass frame");
1734 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1735 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1738 return GST_PAD_PROBE_OK;
1742 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1744 _MMCamcorderMsgItem msg;
1745 guint64 trailer_size = 0;
1746 guint64 rec_pipe_time = 0;
1747 _MMCamcorderSubContext *sc = NULL;
1748 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1749 _MMCamcorderVideoInfo *videoinfo = NULL;
1750 unsigned int remained_time = 0;
1751 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1753 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1754 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1755 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1757 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1758 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1759 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1761 videoinfo = sc->info_video;
1763 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1764 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1765 return GST_PAD_PROBE_OK;
1768 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1770 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1771 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1776 /* calculate remained time can be recorded */
1777 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1778 remained_time = videoinfo->max_time - rec_pipe_time;
1779 } else if (videoinfo->max_size > 0) {
1780 long double max_size = (long double)videoinfo->max_size;
1781 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1783 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1786 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1787 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1788 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1790 if (!sc->isMaxtimePausing) {
1791 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1793 sc->isMaxtimePausing = TRUE;
1795 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1796 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1797 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1798 msg.param.recording_status.remained_time = 0;
1799 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1801 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1802 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1805 return GST_PAD_PROBE_DROP;
1808 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1809 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1810 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1811 msg.param.recording_status.remained_time = remained_time;
1812 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1815 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1816 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1819 return GST_PAD_PROBE_OK;
1823 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1825 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1826 double volume = 0.0;
1829 int err = MM_ERROR_UNKNOWN;
1830 char *err_name = NULL;
1831 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1834 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1835 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1837 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1838 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1839 MMCAM_AUDIO_VOLUME, &volume,
1840 MMCAM_AUDIO_FORMAT, &format,
1841 MMCAM_AUDIO_CHANNEL, &channel,
1843 if (err != MM_ERROR_NONE) {
1844 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1845 SAFE_FREE(err_name);
1849 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1851 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1853 /* Set audio stream NULL */
1855 memset(mapinfo.data, 0, mapinfo.size);
1857 /* CALL audio stream callback */
1858 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1859 MMCamcorderAudioStreamDataType stream;
1861 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1862 _mmcam_dbg_warn("Not ready for stream callback");
1863 gst_buffer_unmap(buffer, &mapinfo);
1864 return GST_PAD_PROBE_OK;
1867 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1868 GST_BUFFER_DATA(buffer), width, height, format);*/
1870 stream.data = (void *)mapinfo.data;
1871 stream.format = format;
1872 stream.channel = channel;
1873 stream.length = mapinfo.size;
1874 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1876 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1878 if (hcamcorder->astream_cb)
1879 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1881 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1884 gst_buffer_unmap(buffer, &mapinfo);
1885 return GST_PAD_PROBE_OK;
1889 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1891 gboolean bret = FALSE;
1893 switch (fileformat) {
1894 case MM_FILE_FORMAT_3GP:
1895 case MM_FILE_FORMAT_MP4:
1896 bret = __mmcamcorder_add_metadata_mp4(handle);
1899 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1907 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1911 guint64 udta_size = 0;
1912 gint64 current_pos = 0;
1913 gint64 moov_pos = 0;
1914 gint64 udta_pos = 0;
1915 gdouble longitude = 0;
1916 gdouble latitude = 0;
1917 gdouble altitude = 0;
1919 int orientation = 0;
1921 char *err_name = NULL;
1922 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1923 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1924 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1926 _MMCamcorderVideoInfo *info = NULL;
1927 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1928 _MMCamcorderSubContext *sc = NULL;
1930 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1931 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1933 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1934 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1938 info = sc->info_video;
1940 f = fopen64(info->filename, "rb+");
1942 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1943 _mmcam_dbg_err("file open failed [%s]", err_msg);
1947 mm_camcorder_get_attributes(handle, &err_name,
1948 MMCAM_TAG_LATITUDE, &latitude,
1949 MMCAM_TAG_LONGITUDE, &longitude,
1950 MMCAM_TAG_ALTITUDE, &altitude,
1951 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1952 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1955 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1956 SAFE_FREE(err_name);
1959 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1960 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1961 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1962 geo_info.longitude = longitude *10000;
1963 geo_info.latitude = latitude *10000;
1964 geo_info.altitude = altitude *10000;
1965 /* find udta container.
1966 if, there are udta container, write loci box after that
1967 else, make udta container and write loci box. */
1968 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1971 _mmcam_dbg_log("find udta container");
1974 if (fseek(f, -8L, SEEK_CUR) != 0)
1977 udta_pos = ftello(f);
1981 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1983 _mmcam_dbg_log("recorded file fread %d", nread);
1985 udta_size = _mmcamcorder_get_container_size(buf);
1987 /* goto end of udta and write 'loci' box */
1988 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1992 if (!_mmcamcorder_write_loci(f, location_info)) {
1993 _mmcam_dbg_err("failed to write loci");
1997 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1998 _mmcam_dbg_err("failed to write geodata");
2003 current_pos = ftello(f);
2004 if (current_pos < 0)
2007 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
2010 _mmcam_dbg_log("No udta container");
2011 if (fseek(f, 0, SEEK_END) != 0)
2014 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
2015 _mmcam_dbg_err("failed to write udta");
2020 /* find moov container.
2021 update moov container size. */
2022 if ((current_pos = ftello(f)) < 0)
2025 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
2026 gint64 internal_pos = ftello(f);
2028 _mmcam_dbg_log("found moov container");
2029 if (fseek(f, -8L, SEEK_CUR) != 0)
2032 moov_pos = ftello(f);
2036 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2039 /* add orientation info */
2040 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2041 _mmcam_dbg_err("fseek failed : errno %d", errno);
2045 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2046 _mmcam_dbg_err("failed to find [trak] tag");
2050 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2051 _mmcam_dbg_err("failed to find [tkhd] tag");
2055 _mmcam_dbg_log("found [tkhd] tag");
2057 /* seek to start position of composition matrix */
2058 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
2060 /* update composition matrix for orientation */
2061 _mmcamcorder_update_composition_matrix(f, orientation);
2063 _mmcam_dbg_err("No 'moov' container");
2075 _mmcam_dbg_err("ftell() returns negative value.");
2081 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2083 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2084 _MMCamcorderSubContext *sc = NULL;
2086 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2088 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2089 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2091 /* check video source element */
2092 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2093 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2094 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2095 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2096 G_CALLBACK(__mmcamcorder_video_stream_cb),
2098 return MM_ERROR_NONE;
2100 _mmcam_dbg_err("videosrc element is not created yet");
2101 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2106 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2108 int ret = MM_ERROR_NONE;
2110 _MMCamcorderVideoInfo *info = NULL;
2111 _MMCamcorderSubContext *sc = NULL;
2112 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2114 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2116 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2117 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2118 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2120 info = sc->info_video;
2122 _mmcam_dbg_warn("start");
2124 /* create encoding pipeline */
2125 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2126 if (ret != MM_ERROR_NONE)
2127 goto _ERR_PREPARE_RECORD;
2129 if (info->filename == NULL) {
2130 char *temp_filename = NULL;
2133 mm_camcorder_get_attributes(handle, NULL,
2134 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2137 info->filename = g_strdup(temp_filename);
2139 if (!info->filename) {
2140 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2141 goto _ERR_PREPARE_RECORD;
2145 _mmcam_dbg_log("Record file name [%s]", info->filename);
2147 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2148 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2150 /* Adjust display FPS */
2151 sc->display_interval = 0;
2152 sc->previous_slot_time = 0;
2154 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2155 if (ret != MM_ERROR_NONE)
2156 goto _ERR_PREPARE_RECORD;
2158 _mmcam_dbg_warn("done");
2162 _ERR_PREPARE_RECORD:
2163 /* Remove recorder pipeline and recording file which size maybe zero */
2164 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2165 if (info && info->filename) {
2166 _mmcam_dbg_log("file delete(%s)", info->filename);
2167 unlink(info->filename);