4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jeongmo Yang <jm80.yang@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 /*=======================================================================================
24 =======================================================================================*/
25 #include <gst/video/cameracontrol.h>
26 #include <gst/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
30 /*---------------------------------------------------------------------------------------
31 | GLOBAL VARIABLE DEFINITIONS for internal |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_LOCATION_INFO /* for add gps information */
34 #define MAX_ERROR_MESSAGE_LEN 128
36 /*---------------------------------------------------------------------------------------
37 | LOCAL VARIABLE DEFINITIONS for internal |
38 ---------------------------------------------------------------------------------------*/
39 #define _MMCAMCORDER_MINIMUM_FRAME 5
40 #define _MMCAMCORDER_RETRIAL_COUNT 10
41 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* ms */
42 #define _OFFSET_COMPOSITION_MATRIX 40L
43 #define _GOP_GEN_INTERVAL 1000000000 /*nano seconds*/
44 #define _MMCAMCORDER_VIDEO_MINIMUM_SPACE (_MMCAMCORDER_MINIMUM_SPACE << 1) /* byte */
46 /*---------------------------------------------------------------------------------------
47 | LOCAL FUNCTION PROTOTYPES: |
48 ---------------------------------------------------------------------------------------*/
49 /* STATIC INTERNAL FUNCTION */
50 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
54 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
55 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
56 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
57 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
59 /*=======================================================================================
60 | FUNCTION DEFINITIONS |
61 =======================================================================================*/
62 /*---------------------------------------------------------------------------------------
63 | GLOBAL FUNCTION DEFINITIONS: |
64 ---------------------------------------------------------------------------------------*/
65 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
67 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
68 _MMCamcorderSubContext *sc = NULL;
70 GstBuffer *buffer = gst_sample_get_buffer(sample);
71 mmf_return_val_if_fail(buffer, FALSE);
72 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
73 mmf_return_val_if_fail(hcamcorder, FALSE);
75 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
76 mmf_return_val_if_fail(sc, FALSE);
79 _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
80 sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
83 /* push buffer in appsrc to encode */
84 if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
85 sc->info_video->record_dual_stream &&
86 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
87 GstFlowReturn ret = 0;
88 GstClock *pipe_clock = NULL;
90 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
91 if (sc->info_video->is_firstframe) {
92 sc->info_video->is_firstframe = FALSE;
93 pipe_clock = GST_ELEMENT_CLOCK(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
95 gst_object_ref(pipe_clock);
96 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer) - (gst_clock_get_time(pipe_clock) - GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
97 gst_object_unref(pipe_clock);
101 if (sc->info_video->is_firstframe) {
102 sc->info_video->is_firstframe = FALSE;
103 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer);
107 GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS(buffer) - sc->info_video->base_video_ts;
108 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
110 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
111 if (ret != GST_FLOW_OK && ret != GST_FLOW_FLUSHING) {
112 _mmcam_dbg_err("gst_app_src_push_buffer failed [0x%x]", ret);
113 gst_buffer_unref(buffer);
117 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
119 _mmcam_dbg_warn("unref video buffer immediately - push encoding buffer %d",
120 sc->info_video->push_encoding_buffer);
122 gst_buffer_unref(buffer);
130 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
133 int err = MM_ERROR_NONE;
134 const char* gst_element_rsink_name = NULL;
137 GstPad *srcpad = NULL;
138 GstPad *sinkpad = NULL;
140 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
141 _MMCamcorderSubContext *sc = NULL;
143 type_element *RecordsinkElement = NULL;
145 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
147 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
148 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
149 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
151 _mmcam_dbg_warn("start");
153 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
154 if (err != MM_ERROR_NONE)
158 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
159 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
160 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
161 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
164 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
166 /* get audio disable */
167 mm_camcorder_get_attributes(handle, NULL,
168 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
171 _mmcam_dbg_log("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d",
172 sc->audio_disable, sc->is_modified_rate);
174 sc->audio_disable |= sc->is_modified_rate;
176 if (sc->audio_disable == FALSE) {
177 /* create audiosrc bin */
178 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
179 if (err != MM_ERROR_NONE)
183 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
184 if (err != MM_ERROR_NONE)
187 if (sc->audio_disable == FALSE) {
188 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
189 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
192 /* add element and encodesink bin to encode main pipeline */
193 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
194 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
195 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
196 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
199 /* Link each element : appsrc - capsfilter - encodesink bin */
200 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
201 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
202 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
204 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
205 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
206 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
208 if (sc->audio_disable == FALSE) {
209 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
210 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
211 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
214 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
215 CONFIGURE_CATEGORY_MAIN_RECORD,
218 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
220 if (!gst_element_rsink_name) {
221 _mmcam_dbg_err("failed to get recordsink name");
222 err = MM_ERROR_CAMCORDER_INTERNAL;
223 goto pipeline_creation_error;
226 /* set data probe function */
228 /* register message cb */
230 /* set data probe functions */
231 if (sc->audio_disable == FALSE) {
232 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
233 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
234 __mmcamcorder_audioque_dataprobe, hcamcorder);
235 gst_object_unref(sinkpad);
239 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
240 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
241 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
242 gst_object_unref(srcpad);
245 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
246 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
247 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
248 __mmcamcorder_eventprobe_monitor, hcamcorder);
249 gst_object_unref(srcpad);
254 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
255 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
256 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
257 __mmcamcorder_eventprobe_monitor, hcamcorder);
258 gst_object_unref(srcpad);
262 if (sc->audio_disable) {
263 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
264 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
265 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
266 gst_object_unref(sinkpad);
270 if (!strcmp(gst_element_rsink_name, "filesink")) {
271 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
272 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
273 __mmcamcorder_video_dataprobe_record, hcamcorder);
274 gst_object_unref(srcpad);
277 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
278 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
279 __mmcamcorder_audio_dataprobe_check, hcamcorder);
280 gst_object_unref(srcpad);
284 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
285 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
286 __mmcamcorder_muxed_dataprobe, hcamcorder);
287 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
288 __mmcamcorder_eventprobe_monitor, hcamcorder);
289 gst_object_unref(sinkpad);
292 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
294 /* register pipeline message callback */
295 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
297 /* set sync handler */
298 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
300 gst_object_unref(bus);
303 return MM_ERROR_NONE;
305 pipeline_creation_error:
306 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
307 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
309 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
314 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
316 GstPad *srcpad = NULL;
317 GstPad *sinkpad = NULL;
318 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
319 _MMCamcorderSubContext *sc = NULL;
321 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
323 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
324 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
325 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
329 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
330 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
331 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
332 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
334 /* release audiosrc bin */
335 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
336 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
339 To avoid conflicting between old elements and newly created elements,
340 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
341 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
342 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
343 It's because the pipeline of audio recording destroys at the same time,
344 and '_mmcamcorder_element_release_noti' will perfom removing handle.
346 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
348 _mmcam_dbg_log("Audio pipeline removed");
351 return MM_ERROR_NONE;
355 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
357 GstPad *reqpad = NULL;
358 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
359 _MMCamcorderSubContext *sc = NULL;
360 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
361 int ret = MM_ERROR_NONE;
362 MMCamcorderResourceManager *resource_manager = NULL;
363 #endif /* _MMCAMCORDER_MURPHY_SUPPORT */
365 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
367 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
368 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
369 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
373 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
374 /* release request pad */
375 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
377 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
378 gst_object_unref(reqpad);
382 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
384 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
385 gst_object_unref(reqpad);
389 /* release encode main pipeline */
390 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
393 To avoid conflicting between old elements and newly created elements,
394 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
395 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
396 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
397 It's because the pipeline of audio recording destroys at the same time,
398 and '_mmcamcorder_element_release_noti' will perfom removing handle.
400 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
401 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
403 _mmcam_dbg_warn("Encoder pipeline removed");
405 #ifdef _MMCAMCORDER_MURPHY_SUPPORT
406 resource_manager = &hcamcorder->resource_manager_sub;
408 _mmcam_dbg_warn("lock resource - cb calling %d", resource_manager->is_release_cb_calling);
410 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
412 if (resource_manager->is_release_cb_calling == FALSE) {
413 /* release resource */
414 ret = _mmcamcorder_resource_manager_release(resource_manager);
416 _mmcam_dbg_warn("release resource 0x%x", ret);
418 if (resource_manager->acquire_remain < resource_manager->acquire_count) {
419 /* wait for resource release */
420 gint64 end_time = g_get_monotonic_time() + (__MMCAMCORDER_RESOURCE_WAIT_TIME * G_TIME_SPAN_SECOND);
421 _mmcam_dbg_log("resource is not released all. wait for signal...");
422 _MMCAMCORDER_RESOURCE_WAIT_UNTIL(hcamcorder, end_time);
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 && !hcamcorder->mstream_cb) {
632 _mmcam_dbg_err("filename is not set and muxed stream cb is NULL");
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 %lu",
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");
686 (ret_free_space == -1 || free_space <= _MMCAMCORDER_VIDEO_MINIMUM_SPACE)) {
687 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
688 ret_free_space, free_space, _MMCAMCORDER_VIDEO_MINIMUM_SPACE);
689 return MM_ERROR_OUT_OF_STORAGE;
692 g_mutex_lock(&hcamcorder->task_thread_lock);
693 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
694 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
695 /* Play record start sound */
696 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
698 g_mutex_unlock(&hcamcorder->task_thread_lock);
700 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
702 if (info->video_width == 0 || info->video_height == 0) {
703 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
704 info->video_width, info->video_height, info->preview_width, info->preview_height);
705 info->video_width = info->preview_width;
706 info->video_height = info->preview_height;
709 if (info->support_dual_stream) {
710 _mmcam_dbg_warn("DUAL STREAM MODE");
712 info->record_dual_stream = TRUE;
714 /* No need to restart preview */
715 info->restart_preview = FALSE;
717 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
718 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
719 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
720 info->preview_width == info->video_width &&
721 info->preview_height == info->video_height) {
722 _mmcam_dbg_log("H264 preview mode and same resolution");
724 /* No need to restart preview */
725 info->restart_preview = FALSE;
727 /* always need to restart preview */
728 info->restart_preview = TRUE;
731 /* set recording hint */
732 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
734 if (info->restart_preview) {
735 /* stop preview and set new size */
736 _mmcam_dbg_log("restart preview");
738 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
739 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
740 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
742 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
744 /* check decoder recreation */
745 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
746 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
747 ret = MM_ERROR_CAMCORDER_INTERNAL;
748 goto _ERR_CAMCORDER_VIDEO_COMMAND;
751 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
752 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
753 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
755 if (ret != MM_ERROR_NONE)
756 goto _ERR_CAMCORDER_VIDEO_COMMAND;
758 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
759 ret = MM_ERROR_CAMCORDER_INTERNAL;
760 goto _ERR_CAMCORDER_VIDEO_COMMAND;
763 /* Start preview again with new setting */
764 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
765 if (ret != MM_ERROR_NONE)
766 goto _ERR_CAMCORDER_VIDEO_COMMAND;
768 if (motion_rate < 1.0) {
769 _mmcam_dbg_warn("wait for stabilization of frame");
773 _mmcam_dbg_log("no need to restart preview");
776 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
777 CONFIGURE_CATEGORY_MAIN_RECORD,
781 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
782 CONFIGURE_CATEGORY_MAIN_RECORD,
783 "PassFirstVideoFrame",
784 &(sc->pass_first_vframe));
786 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
787 sc->drop_vframe, sc->pass_first_vframe);
789 info->record_drop_count = (guint)motion_rate;
790 info->record_motion_rate = motion_rate;
791 if (sc->is_modified_rate)
792 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
794 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
796 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
797 fps, info->record_motion_rate, info->record_timestamp_ratio);
799 /* set push buffer flag */
800 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
801 info->base_video_ts = 0;
803 /* connect video stream cb signal */
804 /*130826 Connect video stream cb for handling fast record frame cb*/
805 if (info->record_dual_stream) {
806 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
807 goto _ERR_CAMCORDER_VIDEO_COMMAND;
810 /* start video stream */
811 if (info->record_dual_stream) {
812 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
814 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
816 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
817 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
819 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
821 _mmcam_dbg_err("could not get camera control");
825 /* check pre-created encode pipeline */
826 g_mutex_lock(&hcamcorder->task_thread_lock);
827 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
828 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
829 /* create encoding pipeline */
830 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
831 if (ret != MM_ERROR_NONE) {
832 g_mutex_unlock(&hcamcorder->task_thread_lock);
833 goto _ERR_CAMCORDER_VIDEO_COMMAND;
836 g_mutex_unlock(&hcamcorder->task_thread_lock);
838 /* check recording start sound */
839 _mmcamcorder_sound_solo_play_wait(handle);
841 /**< To fix video recording hanging
842 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
843 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
844 basetime wouldn't change if you set (GstClockTime)0.
845 3. Move set start time position below PAUSED of pipeline.
848 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
849 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
852 info->video_frame_count = 0;
853 info->is_firstframe = TRUE;
854 info->audio_frame_count = 0;
856 sc->ferror_send = FALSE;
857 sc->ferror_count = 0;
858 hcamcorder->error_occurs = FALSE;
859 sc->bget_eos = FALSE;
860 sc->muxed_stream_offset = 0;
862 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
863 if (ret != MM_ERROR_NONE) {
864 /* stop video stream */
865 if (info->record_dual_stream) {
866 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
868 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
870 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
871 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
873 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
875 _mmcam_dbg_err("failed to get camera control");
879 /* Remove recorder pipeline and recording file which size maybe zero */
880 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
881 if (info->filename) {
882 _mmcam_dbg_log("file delete(%s)", info->filename);
883 unlink(info->filename);
885 goto _ERR_CAMCORDER_VIDEO_COMMAND;
888 /*set the camera control to create the GOP so that video record will get a new key frame*/
889 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
890 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
891 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
892 controls = gst_camera_control_list_channels(CameraControl);
893 if (controls != NULL) {
894 for (item = controls ; item && item->data ; item = item->next) {
895 CameraControlChannel = item->data;
896 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
897 if (!strcmp(CameraControlChannel->label, "new-gop")) {
898 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
904 _mmcam_dbg_warn("failed to find new-gop control channel");
907 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
908 sc->info_image->preview_format);
913 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
914 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
915 /* generate and I-frame on resuming */
916 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
917 controls = gst_camera_control_list_channels(CameraControl);
918 if (controls != NULL) {
919 for (item = controls ; item && item->data ; item = item->next) {
920 CameraControlChannel = item->data;
921 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
922 if (!strcmp(CameraControlChannel->label, "new-gop")) {
923 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
929 _mmcam_dbg_warn("failed to find new-gop control channel");
933 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
935 _mmcam_dbg_log("Object property settings done");
939 case _MMCamcorder_CMD_PAUSE:
941 if (info->b_commiting) {
942 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
943 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
946 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
947 if (sc->audio_disable) {
948 /* check only video frame */
949 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
951 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
952 _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
953 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
955 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", count, info->video_frame_count);
958 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
960 /* check both of video and audio frame */
961 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
963 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
964 _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
965 info->video_frame_count, info->audio_frame_count);
966 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
968 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
969 count, info->video_frame_count, info->audio_frame_count);
972 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
976 /* block encodebin */
977 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
980 case _MMCamcorder_CMD_CANCEL:
982 if (info->b_commiting) {
983 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
984 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
987 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
989 if (hcamcorder->capture_in_recording == FALSE) {
991 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
992 _mmcam_dbg_err("Failed to Wait capture data");
993 hcamcorder->capture_in_recording = FALSE;
996 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
999 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1002 /* block push buffer */
1003 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1005 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1006 if (ret != MM_ERROR_NONE)
1007 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1009 /* set recording hint */
1010 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1012 /* stop video stream */
1013 if (info->record_dual_stream) {
1014 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1015 if (CameraControl) {
1016 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1018 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1019 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1021 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1023 _mmcam_dbg_err("failed to get camera control");
1027 if (info->restart_preview) {
1028 /* restart preview */
1029 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1030 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1031 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1033 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1035 /* check decoder recreation */
1036 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1037 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1038 ret = MM_ERROR_CAMCORDER_INTERNAL;
1041 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1042 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1043 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1045 if (ret != MM_ERROR_NONE)
1046 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1048 /* reset restart_preview for inset window layout */
1049 info->restart_preview = FALSE;
1051 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1052 ret = MM_ERROR_CAMCORDER_INTERNAL;
1053 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1056 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1057 if (ret != MM_ERROR_NONE)
1058 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1061 /* remove target file */
1062 if (info->filename) {
1063 _mmcam_dbg_log("file delete(%s)", info->filename);
1064 unlink(info->filename);
1067 sc->isMaxsizePausing = FALSE;
1068 sc->isMaxtimePausing = FALSE;
1070 sc->display_interval = 0;
1071 sc->previous_slot_time = 0;
1072 info->video_frame_count = 0;
1073 info->audio_frame_count = 0;
1075 hcamcorder->capture_in_recording = FALSE;
1078 case _MMCamcorder_CMD_COMMIT:
1082 if (info->b_commiting) {
1083 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
1084 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1086 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
1087 info->b_commiting = TRUE;
1088 sc->bget_eos = FALSE;
1091 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1092 if (sc->audio_disable) {
1093 /* check only video frame */
1094 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1095 hcamcorder->capture_in_recording == FALSE) {
1097 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1098 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1099 info->video_frame_count, hcamcorder->capture_in_recording);
1101 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1102 _mmcam_dbg_warn("video frames are enough. keep going...");
1104 info->b_commiting = FALSE;
1105 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1108 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1109 count, info->video_frame_count, hcamcorder->capture_in_recording);
1112 /* check both of video and audio frame */
1113 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1114 info->audio_frame_count &&
1115 hcamcorder->capture_in_recording == FALSE) {
1117 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1118 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1119 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1121 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1122 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1124 info->b_commiting = FALSE;
1125 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1128 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1130 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1131 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1135 if (hcamcorder->capture_in_recording) {
1136 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1137 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1138 _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 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1149 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1150 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1151 ret = MM_ERROR_OUT_OF_STORAGE;
1152 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1155 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1156 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1157 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1159 _mmcam_dbg_err("VIDEO: send EOS failed");
1160 info->b_commiting = FALSE;
1161 ret = MM_ERROR_CAMCORDER_INTERNAL;
1162 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1165 _mmcam_dbg_err("No video stream source");
1166 info->b_commiting = FALSE;
1167 ret = MM_ERROR_CAMCORDER_INTERNAL;
1168 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1171 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1172 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1173 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1175 _mmcam_dbg_err("AUDIO: send EOS failed");
1176 info->b_commiting = FALSE;
1177 ret = MM_ERROR_CAMCORDER_INTERNAL;
1178 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1181 _mmcam_dbg_log("No audio stream");
1185 sc->display_interval = 0;
1186 sc->previous_slot_time = 0;
1189 _mmcam_dbg_log("Start to wait EOS");
1190 ret = _mmcamcorder_get_eos_message(handle);
1191 if (ret != MM_ERROR_NONE) {
1192 info->b_commiting = FALSE;
1193 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1197 hcamcorder->capture_in_recording = FALSE;
1201 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1202 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1205 return MM_ERROR_NONE;
1207 _ERR_CAMCORDER_VIDEO_COMMAND:
1208 if (command == _MMCamcorder_CMD_RECORD)
1209 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1215 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1217 int ret = MM_ERROR_NONE;
1219 guint64 file_size = 0;
1221 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1222 _MMCamcorderSubContext *sc = NULL;
1223 _MMCamcorderVideoInfo *info = NULL;
1224 _MMCamcorderMsgItem msg;
1225 MMCamRecordingReport *report = NULL;
1227 mmf_return_val_if_fail(hcamcorder, FALSE);
1229 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1230 mmf_return_val_if_fail(sc, FALSE);
1231 mmf_return_val_if_fail(sc->info_video, FALSE);
1233 info = sc->info_video;
1237 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1238 /* Play record stop sound */
1239 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1241 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1243 _mmcamcorder_sound_init(handle);
1245 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1247 _mmcamcorder_sound_finalize(handle);
1250 /* remove blocking part */
1251 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1253 mm_camcorder_get_attributes(handle, NULL,
1254 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1257 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1258 if (ret != MM_ERROR_NONE)
1259 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1261 /* set recording hint */
1262 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1264 /* stop video stream */
1265 if (info->record_dual_stream) {
1266 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1268 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1270 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1271 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1273 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1275 _mmcam_dbg_err("failed to get camera control");
1279 if (enabletag && !(sc->ferror_send)) {
1280 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1281 _mmcam_dbg_log("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1284 /* Check file size */
1285 if (info->max_size > 0) {
1286 _mmcamcorder_get_file_size(info->filename, &file_size);
1287 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1288 info->max_size, file_size);
1290 if (file_size > info->max_size) {
1291 _MMCamcorderMsgItem message;
1292 _mmcam_dbg_err("File size is greater than max size !!");
1293 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1294 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1295 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1299 if (info->restart_preview) {
1301 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1302 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1303 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1305 _mmcam_dbg_log("Set state of pipeline as READY");
1306 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1308 /* check decoder recreation */
1309 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1310 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1311 ret = MM_ERROR_CAMCORDER_INTERNAL;
1315 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1316 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1317 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1319 if (ret != MM_ERROR_NONE) {
1320 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1321 msg.param.code = ret;
1322 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1323 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1326 /* reset restart_preview for inset window layout */
1327 info->restart_preview = FALSE;
1329 /* recover preview size */
1330 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1331 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1332 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1333 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1334 _mmcam_dbg_err("Failed to set camera resolution %dx%d",
1335 info->preview_width, info->preview_height);
1338 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1339 /* Do not return when error is occurred.
1340 Recording file was created successfully, but starting pipeline failed */
1341 if (ret != MM_ERROR_NONE) {
1342 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1343 msg.param.code = ret;
1344 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1345 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1348 _mmcam_dbg_log("No need to restart preview");
1351 /* Send recording report to application */
1352 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1353 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1355 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1357 report->recording_filename = g_strdup(info->filename);
1358 msg.param.data = report;
1360 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1364 sc->pipeline_time = 0;
1366 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1367 sc->isMaxtimePausing = FALSE;
1368 hcamcorder->error_occurs = FALSE;
1370 info->video_frame_count = 0;
1371 info->audio_frame_count = 0;
1373 info->b_commiting = FALSE;
1375 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1376 /* check recording stop sound */
1377 _mmcamcorder_sound_solo_play_wait(handle);
1380 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1386 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1388 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1389 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1391 _MMCamcorderSubContext *sc = NULL;
1392 _MMCamcorderVideoInfo *videoinfo = NULL;
1393 _MMCamcorderMsgItem msg;
1394 guint64 buffer_size = 0;
1395 guint64 trailer_size = 0;
1396 guint64 max_size = 0;
1398 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1399 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1400 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1402 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1403 videoinfo = sc->info_video;
1405 /* get buffer size */
1406 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1407 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1408 return GST_PAD_PROBE_OK;
1411 buffer_size = mapinfo.size;
1412 gst_buffer_unmap(buffer, &mapinfo);
1414 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1416 g_mutex_lock(&videoinfo->size_check_lock);
1418 if (videoinfo->audio_frame_count == 0) {
1419 videoinfo->filesize += buffer_size;
1420 videoinfo->audio_frame_count++;
1421 g_mutex_unlock(&videoinfo->size_check_lock);
1422 return GST_PAD_PROBE_OK;
1425 if (sc->ferror_send || sc->isMaxsizePausing) {
1426 _mmcam_dbg_warn("Recording is paused, drop frames");
1427 g_mutex_unlock(&videoinfo->size_check_lock);
1428 return GST_PAD_PROBE_DROP;
1431 /* get trailer size */
1432 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1433 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1437 /* check max size of recorded file */
1438 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1439 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1440 GstState pipeline_state = GST_STATE_VOID_PENDING;
1441 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1442 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1443 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1444 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1445 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1447 if (!sc->isMaxsizePausing) {
1448 sc->isMaxsizePausing = TRUE;
1449 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1450 if (pipeline_state == GST_STATE_PLAYING)
1451 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1453 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1454 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1457 g_mutex_unlock(&videoinfo->size_check_lock);
1462 videoinfo->filesize += buffer_size;
1463 videoinfo->audio_frame_count++;
1465 g_mutex_unlock(&videoinfo->size_check_lock);
1467 return GST_PAD_PROBE_OK;
1471 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1476 guint64 free_space = 0;
1477 guint64 buffer_size = 0;
1478 guint64 trailer_size = 0;
1479 guint64 queued_buffer = 0;
1480 guint64 max_size = 0;
1481 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1483 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1485 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1486 _MMCamcorderMsgItem msg;
1487 _MMCamcorderSubContext *sc = NULL;
1488 _MMCamcorderVideoInfo *videoinfo = NULL;
1490 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1491 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1493 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1494 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1495 videoinfo = sc->info_video;
1497 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1498 if (sc->ferror_send) {
1499 _mmcam_dbg_warn("file write error, drop frames");
1500 return GST_PAD_PROBE_DROP;
1503 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1504 buffer_size = mapinfo.size;
1505 gst_buffer_unmap(buffer, &mapinfo);
1507 videoinfo->video_frame_count++;
1508 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1509 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1510 info->video_frame_count); */
1511 g_mutex_lock(&videoinfo->size_check_lock);
1512 videoinfo->filesize += buffer_size;
1513 g_mutex_unlock(&videoinfo->size_check_lock);
1514 return GST_PAD_PROBE_OK;
1517 /* get trailer size */
1518 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1519 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1523 /* check free space */
1524 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1526 _mmcam_dbg_err("Error occured. [%d]", ret);
1527 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1528 sc->ferror_send = TRUE;
1530 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1531 msg.param.code = MM_ERROR_FILE_READ;
1533 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1538 return GST_PAD_PROBE_DROP; /* skip this buffer */
1541 if (free_space == 0) {
1542 /* check storage state */
1543 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1545 _mmcam_dbg_warn("storage state %d", storage_state);
1547 if (storage_state == STORAGE_STATE_REMOVED ||
1548 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1549 _mmcam_dbg_err("storage was removed!");
1551 _MMCAMCORDER_LOCK(hcamcorder);
1553 if (sc->ferror_send == FALSE) {
1554 _mmcam_dbg_err("OUT_OF_STORAGE error");
1556 sc->ferror_send = TRUE;
1558 _MMCAMCORDER_UNLOCK(hcamcorder);
1560 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1561 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1563 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1565 _MMCAMCORDER_UNLOCK(hcamcorder);
1566 _mmcam_dbg_warn("error was already sent");
1569 return GST_PAD_PROBE_DROP;
1573 /* get queued buffer size */
1574 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1575 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1577 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1578 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1580 queued_buffer = aq_size + vq_size;
1582 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1583 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1584 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1585 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1586 free_space, trailer_size, buffer_size, queued_buffer);
1588 if (!sc->isMaxsizePausing) {
1589 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1590 sc->isMaxsizePausing = TRUE;
1592 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1593 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1596 return GST_PAD_PROBE_DROP;
1599 g_mutex_lock(&videoinfo->size_check_lock);
1601 /* check max size of recorded file */
1602 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1603 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1604 GstState pipeline_state = GST_STATE_VOID_PENDING;
1605 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1606 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1607 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1608 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1609 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1611 if (!sc->isMaxsizePausing) {
1612 sc->isMaxsizePausing = TRUE;
1613 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1614 if (pipeline_state == GST_STATE_PLAYING)
1615 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1617 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1618 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1621 g_mutex_unlock(&videoinfo->size_check_lock);
1623 return GST_PAD_PROBE_DROP;
1626 videoinfo->filesize += (guint64)buffer_size;
1629 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1632 g_mutex_unlock(&videoinfo->size_check_lock);
1634 return GST_PAD_PROBE_OK;
1638 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1640 guint64 trailer_size = 0;
1641 guint64 rec_pipe_time = 0;
1642 unsigned int remained_time = 0;
1644 GstClockTime b_time;
1646 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1647 _MMCamcorderMsgItem msg;
1648 _MMCamcorderSubContext *sc = NULL;
1649 _MMCamcorderVideoInfo *videoinfo = NULL;
1651 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1653 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1654 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1656 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1657 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1658 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1660 videoinfo = sc->info_video;
1662 b_time = GST_BUFFER_PTS(buffer);
1664 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1666 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1667 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1671 /* check max time */
1672 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1673 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1674 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1676 if (!sc->isMaxtimePausing) {
1677 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1679 sc->isMaxtimePausing = TRUE;
1681 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1682 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1683 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1684 msg.param.recording_status.remained_time = 0;
1685 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1687 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1688 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1691 return GST_PAD_PROBE_DROP;
1694 /* calculate remained time can be recorded */
1695 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1696 remained_time = videoinfo->max_time - rec_pipe_time;
1697 } else if (videoinfo->max_size > 0) {
1698 long double max_size = (long double)videoinfo->max_size;
1699 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1701 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1704 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1705 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1706 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1707 msg.param.recording_status.remained_time = remained_time;
1708 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1711 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1712 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1715 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1716 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1719 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1720 record_motion_rate, videoinfo->record_drop_count);
1723 /* drop some frame if fast motion */
1724 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1725 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1727 _mmcam_dbg_warn("drop frame");
1729 return GST_PAD_PROBE_DROP;
1732 videoinfo->record_drop_count = 1;
1734 _mmcam_dbg_warn("pass frame");
1738 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1739 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1742 return GST_PAD_PROBE_OK;
1746 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1748 _MMCamcorderMsgItem msg;
1749 guint64 trailer_size = 0;
1750 guint64 rec_pipe_time = 0;
1751 _MMCamcorderSubContext *sc = NULL;
1752 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1753 _MMCamcorderVideoInfo *videoinfo = NULL;
1754 unsigned int remained_time = 0;
1755 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1757 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1758 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1759 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1761 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1762 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1763 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1765 videoinfo = sc->info_video;
1767 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1768 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1769 return GST_PAD_PROBE_OK;
1772 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1774 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1775 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1779 /* calculate remained time can be recorded */
1780 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1781 remained_time = videoinfo->max_time - rec_pipe_time;
1782 } else if (videoinfo->max_size > 0) {
1783 long double max_size = (long double)videoinfo->max_size;
1784 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1786 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1789 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1790 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1791 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1793 if (!sc->isMaxtimePausing) {
1794 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1796 sc->isMaxtimePausing = TRUE;
1798 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1799 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1800 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1801 msg.param.recording_status.remained_time = 0;
1802 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1804 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1805 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1808 return GST_PAD_PROBE_DROP;
1811 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1812 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1813 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1814 msg.param.recording_status.remained_time = remained_time;
1815 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1818 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1819 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1822 return GST_PAD_PROBE_OK;
1826 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1828 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1829 double volume = 0.0;
1832 int err = MM_ERROR_UNKNOWN;
1833 char *err_name = NULL;
1834 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1837 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1838 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1840 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1841 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1842 MMCAM_AUDIO_VOLUME, &volume,
1843 MMCAM_AUDIO_FORMAT, &format,
1844 MMCAM_AUDIO_CHANNEL, &channel,
1846 if (err != MM_ERROR_NONE) {
1847 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1848 SAFE_FREE(err_name);
1852 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1854 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1856 /* Set audio stream NULL */
1858 memset(mapinfo.data, 0, mapinfo.size);
1860 /* CALL audio stream callback */
1861 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1862 MMCamcorderAudioStreamDataType stream;
1864 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1865 _mmcam_dbg_warn("Not ready for stream callback");
1866 gst_buffer_unmap(buffer, &mapinfo);
1867 return GST_PAD_PROBE_OK;
1870 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1871 GST_BUFFER_DATA(buffer), width, height, format);*/
1873 stream.data = (void *)mapinfo.data;
1874 stream.format = format;
1875 stream.channel = channel;
1876 stream.length = mapinfo.size;
1877 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1879 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1881 if (hcamcorder->astream_cb)
1882 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1884 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1887 gst_buffer_unmap(buffer, &mapinfo);
1888 return GST_PAD_PROBE_OK;
1892 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1894 gboolean bret = FALSE;
1896 switch (fileformat) {
1897 case MM_FILE_FORMAT_3GP:
1898 case MM_FILE_FORMAT_MP4:
1899 bret = __mmcamcorder_add_metadata_mp4(handle);
1902 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1910 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1914 guint64 udta_size = 0;
1915 gint64 current_pos = 0;
1916 gint64 moov_pos = 0;
1917 gint64 udta_pos = 0;
1918 gdouble longitude = 0;
1919 gdouble latitude = 0;
1920 gdouble altitude = 0;
1922 int orientation = 0;
1924 char *err_name = NULL;
1925 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1926 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1927 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1929 _MMCamcorderVideoInfo *info = NULL;
1930 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1931 _MMCamcorderSubContext *sc = NULL;
1933 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1934 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1936 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1937 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1941 info = sc->info_video;
1943 f = fopen64(info->filename, "rb+");
1945 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1946 _mmcam_dbg_err("file open failed [%s]", err_msg);
1950 mm_camcorder_get_attributes(handle, &err_name,
1951 MMCAM_TAG_LATITUDE, &latitude,
1952 MMCAM_TAG_LONGITUDE, &longitude,
1953 MMCAM_TAG_ALTITUDE, &altitude,
1954 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1955 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1958 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1959 SAFE_FREE(err_name);
1962 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1963 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1964 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1965 geo_info.longitude = longitude *10000;
1966 geo_info.latitude = latitude *10000;
1967 geo_info.altitude = altitude *10000;
1968 /* find udta container.
1969 if, there are udta container, write loci box after that
1970 else, make udta container and write loci box. */
1971 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1974 _mmcam_dbg_log("find udta container");
1977 if (fseek(f, -8L, SEEK_CUR) != 0)
1980 udta_pos = ftello(f);
1984 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1986 _mmcam_dbg_log("recorded file fread %d", nread);
1988 udta_size = _mmcamcorder_get_container_size(buf);
1990 /* goto end of udta and write 'loci' box */
1991 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1995 if (!_mmcamcorder_write_loci(f, location_info)) {
1996 _mmcam_dbg_err("failed to write loci");
2000 if (!_mmcamcorder_write_geodata(f, geo_info)) {
2001 _mmcam_dbg_err("failed to write geodata");
2006 current_pos = ftello(f);
2007 if (current_pos < 0)
2010 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
2013 _mmcam_dbg_log("No udta container");
2014 if (fseek(f, 0, SEEK_END) != 0)
2017 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
2018 _mmcam_dbg_err("failed to write udta");
2023 /* find moov container.
2024 update moov container size. */
2025 if ((current_pos = ftello(f)) < 0)
2028 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
2029 gint64 internal_pos = ftello(f);
2031 _mmcam_dbg_log("found moov container");
2032 if (fseek(f, -8L, SEEK_CUR) != 0)
2035 moov_pos = ftello(f);
2039 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2042 /* add orientation info */
2043 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2044 _mmcam_dbg_err("fseeko failed : errno %d", errno);
2048 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2049 _mmcam_dbg_err("failed to find [trak] tag");
2053 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2054 _mmcam_dbg_err("failed to find [tkhd] tag");
2058 _mmcam_dbg_log("found [tkhd] tag");
2060 /* seek to start position of composition matrix */
2061 if (fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2062 /* update composition matrix for orientation */
2063 _mmcamcorder_update_composition_matrix(f, orientation);
2065 _mmcam_dbg_err("fseek failed : errno %d", errno);
2069 _mmcam_dbg_err("No 'moov' container");
2081 _mmcam_dbg_err("ftell() returns negative value.");
2087 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2089 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2090 _MMCamcorderSubContext *sc = NULL;
2092 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2094 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2095 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2097 /* check video source element */
2098 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2099 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2100 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2101 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2102 G_CALLBACK(__mmcamcorder_video_stream_cb),
2104 return MM_ERROR_NONE;
2106 _mmcam_dbg_err("videosrc element is not created yet");
2107 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2112 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2114 int ret = MM_ERROR_NONE;
2116 char *temp_filename = NULL;
2118 _MMCamcorderVideoInfo *info = NULL;
2119 _MMCamcorderSubContext *sc = NULL;
2120 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2122 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2124 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2125 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2126 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2128 info = sc->info_video;
2130 _mmcam_dbg_warn("start");
2132 /* create encoding pipeline */
2133 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2134 if (ret != MM_ERROR_NONE)
2135 goto _ERR_PREPARE_RECORD;
2137 SAFE_G_FREE(info->filename);
2139 mm_camcorder_get_attributes(handle, NULL,
2140 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2142 if (temp_filename) {
2143 info->filename = g_strdup(temp_filename);
2144 if (!info->filename) {
2145 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2146 goto _ERR_PREPARE_RECORD;
2149 _mmcam_dbg_log("Record file name [%s]", info->filename);
2150 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2152 _mmcam_dbg_log("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2153 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2156 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2158 /* Adjust display FPS */
2159 sc->display_interval = 0;
2160 sc->previous_slot_time = 0;
2162 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2163 if (ret != MM_ERROR_NONE)
2164 goto _ERR_PREPARE_RECORD;
2166 _mmcam_dbg_warn("done");
2170 _ERR_PREPARE_RECORD:
2171 /* Remove recorder pipeline and recording file which size maybe zero */
2172 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2173 if (info && info->filename) {
2174 _mmcam_dbg_log("file delete(%s)", info->filename);
2175 unlink(info->filename);