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/interfaces/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
44 /*---------------------------------------------------------------------------------------
45 | LOCAL FUNCTION PROTOTYPES: |
46 ---------------------------------------------------------------------------------------*/
47 /* STATIC INTERNAL FUNCTION */
48 static void __mmcamcorder_video_stream_cb(GstElement *element, GstBuffer *buffer, gpointer u_data);
49 static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buffer, gpointer u_data);
50 static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data);
51 static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, gpointer u_data);
52 static gboolean __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstBuffer *buffer, gpointer u_data);
53 static gboolean __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstBuffer *buffer, gpointer u_data);
54 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
55 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
56 static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, gpointer u_data);
58 /*=======================================================================================
59 | FUNCTION DEFINITIONS |
60 =======================================================================================*/
61 /*---------------------------------------------------------------------------------------
62 | GLOBAL FUNCTION DEFINITIONS: |
63 ---------------------------------------------------------------------------------------*/
64 static void __mmcamcorder_video_stream_cb(GstElement *element, GstBuffer *buffer, gpointer u_data)
66 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
67 _MMCamcorderSubContext *sc = NULL;
69 mmf_return_if_fail(buffer);
70 mmf_return_if_fail(GST_BUFFER_DATA(buffer));
71 mmf_return_if_fail(hcamcorder);
73 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
74 mmf_return_if_fail(sc);
77 _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
78 sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
81 /* push buffer in appsrc to encode */
82 if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
83 sc->info_video->record_dual_stream &&
84 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
85 GstFlowReturn ret = 0;
86 GstClock *pipe_clock = NULL;
87 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
88 GstPad *capsfilter_pad = 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 timestamp = GST_BUFFER_TIMESTAMP(buffer) - (gst_clock_get_time(pipe_clock) - GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
97 gst_object_unref(pipe_clock);
98 sc->info_video->prev_video_ts = timestamp;
102 if(sc->info_video->is_firstframe) {
103 sc->info_video->is_firstframe = FALSE;
104 sc->info_video->prev_video_ts = GST_BUFFER_TIMESTAMP(buffer);
107 GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP (buffer) - sc->info_video->prev_video_ts;
109 capsfilter_pad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
110 if (capsfilter_pad) {
111 gst_buffer_set_caps(buffer, GST_PAD_CAPS(capsfilter_pad));
112 gst_object_unref(capsfilter_pad);
113 capsfilter_pad = NULL;
115 _mmcam_dbg_warn("failed to get static pad : encsink_filter - src");
118 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
119 if (ret != GST_FLOW_OK &&
120 ret != GST_FLOW_WRONG_STATE) {
121 _mmcam_dbg_err("gst_app_src_push_buffer failed [0x%x]", ret);
122 gst_buffer_unref(buffer);
126 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
128 _mmcam_dbg_warn("unref video buffer immediately - push encoding buffer %d",
129 sc->info_video->push_encoding_buffer);
131 gst_buffer_unref(buffer);
139 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
142 int err = MM_ERROR_NONE;
143 int audio_disable = FALSE;
144 const char* gst_element_rsink_name = NULL;
147 GstPad *srcpad = NULL;
148 GstPad *sinkpad = NULL;
150 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
151 _MMCamcorderSubContext *sc = NULL;
153 type_element *RecordsinkElement = NULL;
155 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
157 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
158 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
159 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
161 _mmcam_dbg_warn("start");
163 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
164 if (err != MM_ERROR_NONE) {
169 if(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
170 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
171 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
172 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
175 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
177 /* get audio disable */
178 mm_camcorder_get_attributes(handle, NULL,
179 MMCAM_AUDIO_DISABLE, &audio_disable,
182 if (sc->is_modified_rate || audio_disable) {
183 sc->audio_disable = TRUE;
185 sc->audio_disable = FALSE;
187 _mmcam_dbg_log("AUDIO DISABLE : %d (is_modified_rate %d, audio_disable %d)",
188 sc->audio_disable, sc->is_modified_rate, audio_disable);
190 if (sc->audio_disable == FALSE) {
191 /* create audiosrc bin */
192 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
193 if (err != MM_ERROR_NONE) {
198 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
199 if (err != MM_ERROR_NONE) {
203 if (sc->audio_disable == FALSE) {
204 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
205 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
208 /* add element and encodesink bin to encode main pipeline */
209 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
210 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
211 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
212 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
215 /* Link each element : appsrc - capsfilter - encodesink bin */
216 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
217 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
218 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
220 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
221 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
222 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
224 if (sc->audio_disable == FALSE) {
225 srcpad = gst_element_get_static_pad (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
226 sinkpad = gst_element_get_static_pad (sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
227 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
230 _mmcamcorder_conf_get_element(hcamcorder->conf_main,
231 CONFIGURE_CATEGORY_MAIN_RECORD,
234 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
236 /* set data probe function */
238 /* register message cb */
240 /* set data probe function for audio */
242 if (sc->audio_disable == FALSE) {
243 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
244 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
245 __mmcamcorder_audioque_dataprobe, hcamcorder);
246 gst_object_unref(sinkpad);
250 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
251 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
252 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
253 gst_object_unref(srcpad);
256 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
257 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
258 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
259 __mmcamcorder_eventprobe_monitor, hcamcorder);
260 gst_object_unref(srcpad);
265 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
266 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
267 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
268 __mmcamcorder_eventprobe_monitor, hcamcorder);
269 gst_object_unref(srcpad);
273 if (sc->audio_disable) {
274 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
275 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
276 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
277 gst_object_unref(sinkpad);
281 if (!strcmp(gst_element_rsink_name, "filesink")) {
282 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
283 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
284 __mmcamcorder_video_dataprobe_record, hcamcorder);
285 gst_object_unref(srcpad);
288 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
289 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
290 __mmcamcorder_audio_dataprobe_check, hcamcorder);
291 gst_object_unref(srcpad);
295 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
297 /* register pipeline message callback */
298 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
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;
361 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
363 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
364 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
365 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
369 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
370 /* release request pad */
371 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
373 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
374 gst_object_unref(reqpad);
378 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
380 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
381 gst_object_unref(reqpad);
385 /* release encode main pipeline */
386 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
389 To avoid conflicting between old elements and newly created elements,
390 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
391 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
392 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
393 It's because the pipeline of audio recording destroys at the same time,
394 and '_mmcamcorder_element_release_noti' will perfom removing handle.
396 //_mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK);
398 _mmcam_dbg_log("Encoder pipeline removed");
401 return MM_ERROR_NONE;
405 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
407 int ret = MM_ERROR_NONE;
408 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
409 _MMCamcorderSubContext *sc = NULL;
413 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
414 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
415 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
417 _mmcam_dbg_log("start");
419 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
420 _mmcam_dbg_warn("pipeline is not existed.");
421 return MM_ERROR_NONE;
424 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
426 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
427 if (ret != MM_ERROR_NONE) {
428 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
432 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
434 /* remove audio pipeline first */
435 ret = _mmcamcorder_remove_audio_pipeline(handle);
436 if (ret != MM_ERROR_NONE) {
437 _mmcam_dbg_err("Fail to remove audio pipeline");
441 ret = _mmcamcorder_remove_encode_pipeline(handle);
442 if (ret != MM_ERROR_NONE) {
443 _mmcam_dbg_err("Fail to remove encoder pipeline");
447 /* Remove pipeline message callback */
448 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
449 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
450 hcamcorder->encode_pipeline_cb_event_id = 0;
453 /* Remove remained message */
455 GstMessage *gst_msg = NULL;
456 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
457 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
458 gst_message_unref(gst_msg);
461 gst_object_unref(bus);
465 _mmcam_dbg_log("done");
471 int _mmcamcorder_video_command(MMHandleType handle, int command)
475 int ret = MM_ERROR_NONE;
476 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
477 char *err_name = NULL;
478 char *temp_filename = NULL;
481 GstElement *pipeline = NULL;
483 _MMCamcorderVideoInfo *info = NULL;
484 _MMCamcorderSubContext *sc = NULL;
485 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
487 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
489 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
490 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
491 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
492 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
494 info = sc->info_video;
496 _mmcam_dbg_log("Command(%d)", command);
498 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
501 case _MMCamcorder_CMD_RECORD:
503 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
509 int ret_free_space = 0;
510 char *dir_name = NULL;
511 guint64 free_space = 0;
512 guint64 free_space_exceptsystem = 0;
513 int file_system_type = 0;
516 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
518 /* init record_dual_stream */
519 info->record_dual_stream = FALSE;
521 ret = mm_camcorder_get_attributes(handle, &err_name,
522 MMCAM_CAMERA_FPS, &fps,
523 MMCAM_CAMERA_WIDTH, &(info->preview_width),
524 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
525 MMCAM_VIDEO_WIDTH, &(info->video_width),
526 MMCAM_VIDEO_HEIGHT, &(info->video_height),
527 MMCAM_FILE_FORMAT, &fileformat,
528 MMCAM_TARGET_FILENAME, &temp_filename, &size,
529 MMCAM_TARGET_MAX_SIZE, &imax_size,
530 MMCAM_TARGET_TIME_LIMIT, &imax_time,
531 MMCAM_FILE_FORMAT, &(info->fileformat),
532 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
534 if (ret != MM_ERROR_NONE) {
535 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
536 SAFE_FREE (err_name);
537 goto _ERR_CAMCORDER_VIDEO_COMMAND;
540 if (temp_filename == NULL) {
541 _mmcam_dbg_err("filename is not set");
542 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
543 goto _ERR_CAMCORDER_VIDEO_COMMAND;
547 if (imax_size <= 0) {
548 info->max_size = 0; /* do not check */
550 info->max_size = ((guint64)imax_size) << 10; /* to byte */
554 if (imax_time <= 0) {
555 info->max_time = 0; /* do not check */
557 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
560 dir_name = g_path_get_dirname(temp_filename);
562 ret_free_space = _mmcamcorder_get_freespace(dir_name, &free_space);
563 if(_mmcamcorder_check_file_path(dir_name)) {
564 ret_free_space = _mmcamcorder_get_freespace_except_system(&free_space_exceptsystem);
565 hcamcorder->system_memory = free_space - free_space_exceptsystem;
566 free_space = free_space - hcamcorder->system_memory;
569 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "], system [%" G_GUINT64_FORMAT "]",
570 dir_name, free_space, hcamcorder->system_memory);
572 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
573 /* MSDOS_SUPER_MAGIC : 0x4d44 */
574 if (file_system_type == MSDOS_SUPER_MAGIC &&
575 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
576 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
577 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
578 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
580 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
581 file_system_type, info->max_size);
584 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
590 _mmcam_dbg_err("failed to get directory name");
594 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
595 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
596 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
597 return MM_ERROR_OUT_OF_STORAGE;
600 pthread_mutex_lock(&(hcamcorder->task_thread_lock));
601 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
602 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
603 /* Play record start sound */
604 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_START_SND, FALSE);
606 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
608 /* check restart_preview */
610 if (info->preview_width != info->video_width &&
611 info->preview_height != info->video_height) {
612 info->restart_preview = TRUE;
614 info->restart_preview = FALSE;
617 if (info->restart_preview) {
618 /* stop preview and set new size */
619 _mmcam_dbg_log("restart preview");
621 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
622 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
624 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
626 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
627 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
629 if (ret != MM_ERROR_NONE) {
630 goto _ERR_CAMCORDER_VIDEO_COMMAND;
633 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
634 ret = MM_ERROR_CAMCORDER_INTERNAL;
635 goto _ERR_CAMCORDER_VIDEO_COMMAND;
638 /* Start preview again with new setting */
639 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
640 if (ret != MM_ERROR_NONE) {
641 goto _ERR_CAMCORDER_VIDEO_COMMAND;
644 if (motion_rate < 1.0) {
645 _mmcam_dbg_warn("wait for stabilization of frame");
649 _mmcam_dbg_log("no need to restart preview");
652 _mmcamcorder_conf_get_value_int(hcamcorder->conf_main,
653 CONFIGURE_CATEGORY_MAIN_RECORD,
657 _mmcamcorder_conf_get_value_int(hcamcorder->conf_main,
658 CONFIGURE_CATEGORY_MAIN_RECORD,
659 "PassFirstVideoFrame",
660 &(sc->pass_first_vframe));
662 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
663 sc->drop_vframe, sc->pass_first_vframe);
665 info->record_drop_count = (guint)motion_rate;
666 info->record_motion_rate = motion_rate;
667 if (sc->is_modified_rate) {
668 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
670 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
673 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
674 fps, info->record_motion_rate, info->record_timestamp_ratio);
676 /* set push buffer flag */
677 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
678 info->prev_video_ts = 0;
680 /* connect video stream cb signal */
681 /*130826 Connect video stream cb for handling fast record frame cb*/
682 if (info->record_dual_stream) {
683 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE) {
684 goto _ERR_CAMCORDER_VIDEO_COMMAND;
688 /* start video stream */
689 if (info->record_dual_stream) {
690 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
692 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
694 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
695 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
697 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
699 _mmcam_dbg_err("could not get camera control");
703 /* check pre-created encode pipeline */
704 pthread_mutex_lock(&(hcamcorder->task_thread_lock));
705 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
706 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
707 /* create encoding pipeline */
708 ret =_mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
709 if (ret != MM_ERROR_NONE) {
710 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
711 goto _ERR_CAMCORDER_VIDEO_COMMAND;
714 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
716 /* check recording start sound */
717 _mmcamcorder_sound_solo_play_wait(handle);
719 /**< To fix video recording hanging
720 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
721 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
722 basetime wouldn't change if you set (GstClockTime)0.
723 3. Move set start time position below PAUSED of pipeline.
725 //gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
726 //gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
728 info->video_frame_count = 0;
729 info->is_firstframe = TRUE;
730 info->audio_frame_count = 0;
732 sc->ferror_send = FALSE;
733 sc->ferror_count = 0;
734 sc->error_occurs = FALSE;
735 sc->bget_eos = FALSE;
737 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
738 if (ret != MM_ERROR_NONE) {
739 /* stop video stream */
740 if (info->record_dual_stream) {
741 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
743 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
745 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
746 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
748 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
750 _mmcam_dbg_err("failed to get camera control");
754 /* Remove recorder pipeline and recording file which size maybe zero */
755 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
756 if (info->filename) {
757 _mmcam_dbg_log("file delete(%s)", info->filename);
758 unlink(info->filename);
760 goto _ERR_CAMCORDER_VIDEO_COMMAND;
766 mm_camcorder_get_attributes(handle, NULL, MMCAM_VIDEO_ENCODER, &video_enc, NULL);
767 if (video_enc == MM_VIDEO_CODEC_MPEG4) {
768 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "force-i-frame", TRUE);
771 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
773 _mmcam_dbg_log("Object property settings done");
777 case _MMCamcorder_CMD_PAUSE:
781 if (info->b_commiting) {
782 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
783 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
786 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
787 if (sc->audio_disable) {
788 /* check only video frame */
789 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
791 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
792 _mmcam_dbg_err("Pause fail, frame count %" G_GUINT64_FORMAT "",
793 info->video_frame_count);
794 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
796 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %" G_GUINT64_FORMAT "",
797 count, info->video_frame_count);
800 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
802 /* check both of video and audio frame */
803 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
805 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
806 _mmcam_dbg_err("Pause fail, frame count VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
807 info->video_frame_count, info->audio_frame_count);
808 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
810 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
811 count, info->video_frame_count, info->audio_frame_count);
814 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
818 /* block encodebin */
819 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
822 case _MMCamcorder_CMD_CANCEL:
824 if (info->b_commiting) {
825 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
826 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
829 /* block push buffer */
830 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
832 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
833 if (ret != MM_ERROR_NONE) {
834 goto _ERR_CAMCORDER_VIDEO_COMMAND;
837 /* stop video stream */
838 if (info->record_dual_stream) {
839 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
841 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
843 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
844 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
846 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
848 _mmcam_dbg_err("failed to get camera control");
852 if (info->restart_preview) {
853 /* restart preview */
854 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
855 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
857 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
859 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
860 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
861 if (ret != MM_ERROR_NONE) {
862 goto _ERR_CAMCORDER_VIDEO_COMMAND;
865 /* reset restart_preview for inset window layout */
866 info->restart_preview = FALSE;
868 ret = _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
869 if (ret != MM_ERROR_NONE) {
870 goto _ERR_CAMCORDER_VIDEO_COMMAND;
873 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
874 if (ret != MM_ERROR_NONE) {
875 goto _ERR_CAMCORDER_VIDEO_COMMAND;
879 /* remove target file */
880 if (info->filename) {
881 _mmcam_dbg_log("file delete(%s)", info->filename);
882 unlink(info->filename);
885 sc->isMaxsizePausing = FALSE;
886 sc->isMaxtimePausing = FALSE;
888 sc->display_interval = 0;
889 sc->previous_slot_time = 0;
890 info->video_frame_count = 0;
891 info->audio_frame_count = 0;
895 case _MMCamcorder_CMD_COMMIT:
899 if (info->b_commiting) {
900 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
901 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
903 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
904 info->b_commiting = TRUE;
905 sc->bget_eos = FALSE;
908 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
909 if (sc->audio_disable) {
910 /* check only video frame */
911 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
913 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
914 _mmcam_dbg_err("Commit fail, frame count is %" G_GUINT64_FORMAT "",
915 info->video_frame_count);
916 info->b_commiting = FALSE;
917 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
919 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %" G_GUINT64_FORMAT "",
920 count, info->video_frame_count);
923 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
925 /* check both of video and audio frame */
926 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
928 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
929 _mmcam_dbg_err("Commit fail, VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
930 info->video_frame_count, info->audio_frame_count);
932 info->b_commiting = FALSE;
933 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
935 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
936 count, info->video_frame_count, info->audio_frame_count);
939 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
943 /* block push buffer */
944 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
945 _mmcam_dbg_log("block push buffer to appsrc");
947 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
948 ret = gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos());
949 _mmcam_dbg_warn("send eos to appsrc result : %d", ret);
952 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
953 ret = gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
954 _mmcam_dbg_warn("send eos to audiosrc result : %d", ret);
958 sc->display_interval = 0;
959 sc->previous_slot_time = 0;
961 /* init system memory size */
962 hcamcorder->system_memory=0;
965 _mmcam_dbg_log("Start to wait EOS");
966 ret =_mmcamcorder_get_eos_message(handle);
967 if (ret != MM_ERROR_NONE) {
968 info->b_commiting = FALSE;
969 goto _ERR_CAMCORDER_VIDEO_COMMAND;
974 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
975 goto _ERR_CAMCORDER_VIDEO_COMMAND;
978 return MM_ERROR_NONE;
980 _ERR_CAMCORDER_VIDEO_COMMAND:
981 if (command == _MMCamcorder_CMD_RECORD) {
982 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
989 int _mmcamcorder_video_handle_eos(MMHandleType handle)
991 int ret = MM_ERROR_NONE;
993 guint64 file_size = 0;
995 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
996 _MMCamcorderSubContext *sc = NULL;
997 _MMCamcorderVideoInfo *info = NULL;
998 _MMCamcorderMsgItem msg;
999 MMCamRecordingReport *report = NULL;
1001 mmf_return_val_if_fail(hcamcorder, FALSE);
1003 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1004 mmf_return_val_if_fail(sc, FALSE);
1005 mmf_return_val_if_fail(sc->info_video, FALSE);
1007 info = sc->info_video;
1011 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1012 /* Play record stop sound */
1013 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND, FALSE);
1015 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1017 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
1018 _mmcamcorder_sound_init(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND);
1019 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
1020 _mmcamcorder_sound_init(handle);
1021 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
1023 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1025 _mmcamcorder_sound_finalize(handle);
1028 /* remove blocking part */
1029 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1031 mm_camcorder_get_attributes(handle, NULL,
1032 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1035 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1036 if (ret != MM_ERROR_NONE) {
1037 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1040 /* stop video stream */
1041 if (info->record_dual_stream) {
1042 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1044 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1046 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1047 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1049 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1051 _mmcam_dbg_err("failed to get camera control");
1055 if (enabletag && !(sc->ferror_send)) {
1056 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1058 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1060 _mmcam_dbg_err("Writing location information FAILED !!");
1064 /* Check file size */
1065 if (info->max_size > 0) {
1066 _mmcamcorder_get_file_size(info->filename, &file_size);
1067 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1068 info->max_size, file_size);
1070 if (file_size > info->max_size) {
1071 _MMCamcorderMsgItem message;
1072 _mmcam_dbg_err("File size is greater than max size !!");
1073 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1074 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1075 _mmcamcroder_send_message((MMHandleType)hcamcorder, &message);
1079 if (info->restart_preview) {
1081 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1082 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1084 _mmcam_dbg_log("Set state of pipeline as READY");
1085 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1088 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1089 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1090 if (ret != MM_ERROR_NONE) {
1091 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1092 msg.param.code = ret;
1093 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1094 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1097 /* reset restart_preview for inset window layout */
1098 info->restart_preview = FALSE;
1100 /* recover preview size */
1101 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1103 ret =_mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1104 /* Do not return when error is occurred.
1105 Recording file was created successfully, but starting pipeline failed */
1106 if (ret != MM_ERROR_NONE) {
1107 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1108 msg.param.code = ret;
1109 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1110 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1113 _mmcam_dbg_log("No need to restart preview");
1116 /* Send recording report to application */
1117 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1118 report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport));
1120 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1122 report->recording_filename = strdup(info->filename);
1123 msg.param.data= report;
1125 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1129 sc->pipeline_time = 0;
1131 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1132 sc->isMaxtimePausing = FALSE;
1133 sc->error_occurs = FALSE;
1135 info->video_frame_count = 0;
1136 info->audio_frame_count = 0;
1138 info->b_commiting = FALSE;
1140 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1141 /* check recording stop sound */
1142 _mmcamcorder_sound_solo_play_wait(handle);
1145 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1152 * This function is record video data probing function.
1153 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1154 * this function will be called when data stream pass through the pad.
1156 * @param[in] pad probing pad which calls this function.
1157 * @param[in] buffer buffer which contains stream data.
1158 * @param[in] u_data user data.
1159 * @return This function returns true on success, or false value with error
1163 static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, gpointer u_data)
1165 switch (GST_EVENT_TYPE(event)) {
1166 case GST_EVENT_UNKNOWN:
1167 /* upstream events */
1169 case GST_EVENT_SEEK:
1170 case GST_EVENT_NAVIGATION:
1171 case GST_EVENT_LATENCY:
1172 /* downstream serialized events */
1173 case GST_EVENT_NEWSEGMENT :
1175 case GST_EVENT_BUFFERSIZE:
1176 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1179 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1181 /* bidirectional events */
1182 case GST_EVENT_FLUSH_START:
1183 case GST_EVENT_FLUSH_STOP:
1184 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1187 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1195 static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1197 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1198 _MMCamcorderSubContext *sc = NULL;
1199 _MMCamcorderVideoInfo *info = NULL;
1200 _MMCamcorderMsgItem msg;
1201 guint64 buffer_size = 0;
1202 guint64 trailer_size = 0;
1204 mmf_return_val_if_fail(hcamcorder, TRUE);
1205 mmf_return_val_if_fail(buffer, FALSE);
1206 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1208 mmf_return_val_if_fail(sc && sc->info_video, TRUE);
1209 info = sc->info_video;
1211 /* get buffer size */
1212 buffer_size = GST_BUFFER_SIZE(buffer);
1214 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1216 pthread_mutex_lock(&(info->size_check_lock));
1218 if (info->audio_frame_count == 0) {
1219 info->filesize += buffer_size;
1220 info->audio_frame_count++;
1221 pthread_mutex_unlock(&(info->size_check_lock));
1225 if (sc->ferror_send || sc->isMaxsizePausing) {
1226 _mmcam_dbg_warn("Recording is paused, drop frames");
1227 pthread_mutex_unlock(&(info->size_check_lock));
1231 /* get trailer size */
1232 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1233 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1238 /* check max size of recorded file */
1239 if (info->max_size > 0 &&
1240 info->max_size < info->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1241 GstState pipeline_state = GST_STATE_VOID_PENDING;
1242 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1243 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1244 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1245 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1246 info->max_size, info->filesize, buffer_size, trailer_size);
1248 if (!sc->isMaxsizePausing) {
1249 sc->isMaxsizePausing = TRUE;
1250 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1251 if (pipeline_state == GST_STATE_PLAYING) {
1252 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1255 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1256 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1259 pthread_mutex_unlock(&(info->size_check_lock));
1264 info->filesize += buffer_size;
1265 info->audio_frame_count++;
1267 pthread_mutex_unlock(&(info->size_check_lock));
1273 static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1278 guint64 free_space = 0;
1279 guint64 buffer_size = 0;
1280 guint64 trailer_size = 0;
1281 guint64 queued_buffer = 0;
1282 char *filename = NULL;
1284 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1285 _MMCamcorderMsgItem msg;
1286 _MMCamcorderSubContext *sc = NULL;
1287 _MMCamcorderVideoInfo *info = NULL;
1289 mmf_return_val_if_fail(hcamcorder, TRUE);
1290 mmf_return_val_if_fail(buffer, FALSE);
1292 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1293 mmf_return_val_if_fail(sc && sc->info_video, TRUE);
1294 info = sc->info_video;
1296 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1297 if (sc->ferror_send) {
1298 _mmcam_dbg_warn("file write error, drop frames");
1302 info->video_frame_count++;
1303 if (info->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1304 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1305 info->video_frame_count); */
1306 pthread_mutex_lock(&(info->size_check_lock));
1307 info->filesize += (guint64)GST_BUFFER_SIZE(buffer);
1308 pthread_mutex_unlock(&(info->size_check_lock));
1312 buffer_size = GST_BUFFER_SIZE(buffer);
1314 /* get trailer size */
1315 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1316 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1321 filename = info->filename;
1322 ret = _mmcamcorder_get_freespace(filename, &free_space);
1324 if(_mmcamcorder_check_file_path(filename) && hcamcorder->system_memory) {
1325 free_space = free_space - hcamcorder->system_memory;
1328 /*_mmcam_dbg_log("check free space for recording");*/
1331 case -2: /* file not exist */
1332 case -1: /* failed to get free space */
1333 _mmcam_dbg_err("Error occured. [%d]", ret);
1334 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1335 sc->ferror_send = TRUE;
1336 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1338 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1340 msg.param.code = MM_ERROR_FILE_READ;
1342 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1347 return FALSE; /* skip this buffer */
1349 default: /* succeeded to get free space */
1350 /* check free space for recording */
1351 /* get queued buffer size */
1352 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1353 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1355 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1356 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1359 queued_buffer = aq_size + vq_size;
1361 /* check free space */
1362 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1363 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1364 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1365 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1366 free_space, trailer_size, buffer_size, queued_buffer);
1368 if (!sc->isMaxsizePausing) {
1369 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1370 sc->isMaxsizePausing = TRUE;
1372 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1373 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1381 pthread_mutex_lock(&(info->size_check_lock));
1383 /* check max size of recorded file */
1384 if (info->max_size > 0 &&
1385 info->max_size < info->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1386 GstState pipeline_state = GST_STATE_VOID_PENDING;
1387 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1388 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1389 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1390 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1391 info->max_size, info->filesize, buffer_size, trailer_size);
1393 if (!sc->isMaxsizePausing) {
1394 sc->isMaxsizePausing = TRUE;
1395 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1396 if (pipeline_state == GST_STATE_PLAYING) {
1397 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1400 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1401 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1404 pthread_mutex_unlock(&(info->size_check_lock));
1409 info->filesize += (guint64)buffer_size;
1412 _mmcam_dbg_log("filesize %lld Byte, ", info->filesize);
1415 pthread_mutex_unlock(&(info->size_check_lock));
1421 static gboolean __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1423 guint64 trailer_size = 0;
1424 guint64 rec_pipe_time = 0;
1425 unsigned int remained_time = 0;
1427 GstClockTime b_time;
1429 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1430 _MMCamcorderMsgItem msg;
1431 _MMCamcorderSubContext *sc = NULL;
1432 _MMCamcorderVideoInfo *info = NULL;
1434 mmf_return_val_if_fail(buffer, FALSE);
1435 mmf_return_val_if_fail(hcamcorder, TRUE);
1437 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1438 mmf_return_val_if_fail(sc, TRUE);
1439 mmf_return_val_if_fail(sc->info_video, TRUE);
1441 info = sc->info_video;
1443 b_time = GST_BUFFER_TIMESTAMP(buffer);
1445 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1447 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1448 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1453 /* check max time */
1454 if (info->max_time > 0 && rec_pipe_time > info->max_time) {
1455 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1456 rec_pipe_time, info->max_time);
1458 if (!sc->isMaxtimePausing) {
1459 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1461 sc->isMaxtimePausing = TRUE;
1463 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1464 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1465 msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10);
1466 msg.param.recording_status.remained_time = 0;
1467 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1469 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1470 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1476 /* calculate remained time can be recorded */
1477 if (info->max_time > 0 && info->max_time < (remained_time + rec_pipe_time)) {
1478 remained_time = info->max_time - rec_pipe_time;
1479 } else if (info->max_size > 0) {
1480 long double max_size = (long double)info->max_size;
1481 long double current_size = (long double)(info->filesize + trailer_size);
1483 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1486 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1487 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1488 msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10);
1489 msg.param.recording_status.remained_time = remained_time;
1490 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1493 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1494 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1497 if (info->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1498 guint record_motion_rate = (guint)info->record_motion_rate;
1501 _mmcam_dbg_log("record_motion_rate %d, info->record_drop_count %d",
1502 record_motion_rate, info->record_drop_count);
1505 /* drop some frame if fast motion */
1506 if (info->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1507 if (record_motion_rate != (info->record_drop_count++)) {
1509 _mmcam_dbg_warn("drop frame");
1514 info->record_drop_count = 1;
1516 _mmcam_dbg_warn("pass frame");
1520 GST_BUFFER_TIMESTAMP(buffer) = b_time * (info->record_timestamp_ratio);
1527 static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1529 _MMCamcorderMsgItem msg;
1530 guint64 trailer_size = 0;
1531 guint64 rec_pipe_time = 0;
1532 _MMCamcorderSubContext *sc = NULL;
1533 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1534 _MMCamcorderVideoInfo *info = NULL;
1535 unsigned int remained_time = 0;
1537 mmf_return_val_if_fail(buffer, FALSE);
1538 mmf_return_val_if_fail(hcamcorder, TRUE);
1539 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1541 mmf_return_val_if_fail(sc, TRUE);
1542 mmf_return_val_if_fail(sc->info_video, TRUE);
1543 mmf_return_val_if_fail(sc->element, TRUE);
1545 info = sc->info_video;
1547 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buffer))) {
1548 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1552 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1554 if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) {
1555 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1560 /* calculate remained time can be recorded */
1561 if (info->max_time > 0 && info->max_time < (remained_time + rec_pipe_time)) {
1562 remained_time = info->max_time - rec_pipe_time;
1563 } else if (info->max_size > 0) {
1564 long double max_size = (long double)info->max_size;
1565 long double current_size = (long double)(info->filesize + trailer_size);
1567 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1570 if (info->max_time > 0 && rec_pipe_time > info->max_time) {
1571 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1572 rec_pipe_time, info->max_time);
1574 if (!sc->isMaxtimePausing) {
1575 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1577 sc->isMaxtimePausing = TRUE;
1579 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1580 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1581 msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10);
1582 msg.param.recording_status.remained_time = 0;
1583 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1585 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1586 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1592 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1593 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1594 msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10);
1595 msg.param.recording_status.remained_time = remained_time;
1596 _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg);
1599 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1600 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1607 static gboolean __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstBuffer *buffer, gpointer u_data)
1609 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1610 double volume = 0.0;
1613 int err = MM_ERROR_UNKNOWN;
1614 char *err_name = NULL;
1616 mmf_return_val_if_fail(buffer, FALSE);
1617 mmf_return_val_if_fail(hcamcorder, FALSE);
1619 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1620 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1621 MMCAM_AUDIO_VOLUME, &volume,
1622 MMCAM_AUDIO_FORMAT, &format,
1623 MMCAM_AUDIO_CHANNEL, &channel,
1625 if (err != MM_ERROR_NONE) {
1626 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1627 SAFE_FREE(err_name);
1631 /* Set audio stream NULL */
1632 if (volume == 0.0) {
1633 memset(GST_BUFFER_DATA(buffer), 0, GST_BUFFER_SIZE(buffer));
1636 /* CALL audio stream callback */
1637 if (hcamcorder->astream_cb && buffer && GST_BUFFER_DATA(buffer)) {
1638 MMCamcorderAudioStreamDataType stream;
1640 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1641 _mmcam_dbg_warn("Not ready for stream callback");
1645 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1646 GST_BUFFER_DATA(buffer), width, height, format);*/
1648 stream.data = (void *)GST_BUFFER_DATA(buffer);
1649 stream.format = format;
1650 stream.channel = channel;
1651 stream.length = GST_BUFFER_SIZE(buffer);
1652 stream.timestamp = (unsigned int)(GST_BUFFER_TIMESTAMP(buffer)/1000000); /* nano -> milli second */
1654 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1656 if (hcamcorder->astream_cb) {
1657 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1660 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1667 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1669 gboolean bret = FALSE;
1671 switch (fileformat) {
1672 case MM_FILE_FORMAT_3GP:
1673 case MM_FILE_FORMAT_MP4:
1674 bret = __mmcamcorder_add_metadata_mp4(handle);
1677 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1685 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1689 guint64 udta_size = 0;
1690 gint64 current_pos = 0;
1691 gint64 moov_pos = 0;
1692 gint64 udta_pos = 0;
1693 gdouble longitude = 0;
1694 gdouble latitude = 0;
1695 gdouble altitude = 0;
1697 int orientation = 0;
1699 char *err_name = NULL;
1700 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1701 _MMCamcorderLocationInfo location_info = {0,0,0};
1702 _MMCamcorderLocationInfo geo_info = {0,0,0};
1704 _MMCamcorderVideoInfo *info = NULL;
1705 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1706 _MMCamcorderSubContext *sc = NULL;
1708 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1709 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1711 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1712 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1716 info = sc->info_video;
1718 f = fopen(info->filename, "rb+");
1720 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1721 _mmcam_dbg_err("file open failed [%s]", err_msg);
1725 mm_camcorder_get_attributes(handle, &err_name,
1726 MMCAM_TAG_LATITUDE, &latitude,
1727 MMCAM_TAG_LONGITUDE, &longitude,
1728 MMCAM_TAG_ALTITUDE, &altitude,
1729 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1730 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1733 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1734 SAFE_FREE (err_name);
1737 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1738 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1739 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1740 geo_info.longitude = longitude *10000;
1741 geo_info.latitude = latitude *10000;
1742 geo_info.altitude = altitude *10000;
1743 /* find udta container.
1744 if, there are udta container, write loci box after that
1745 else, make udta container and write loci box. */
1746 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) {
1749 _mmcam_dbg_log("find udta container");
1752 if (fseek(f, -8L, SEEK_CUR) != 0) {
1756 udta_pos = ftell(f);
1761 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1763 _mmcam_dbg_log("recorded file fread %d", nread);
1765 udta_size = _mmcamcorder_get_container_size(buf);
1767 /* goto end of udta and write 'loci' box */
1768 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1773 if (!_mmcamcorder_write_loci(f, location_info)) {
1774 _mmcam_dbg_err("failed to write loci");
1778 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1779 _mmcam_dbg_err("failed to write geodata");
1784 current_pos = ftell(f);
1785 if (current_pos < 0) {
1789 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1793 _mmcam_dbg_log("No udta container");
1794 if (fseek(f, 0, SEEK_END) != 0) {
1798 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1799 _mmcam_dbg_err("failed to write udta");
1804 /* find moov container.
1805 update moov container size. */
1806 if((current_pos = ftell(f))<0)
1809 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) {
1810 gint64 internal_pos = ftell(f);
1812 _mmcam_dbg_log("found moov container");
1813 if (fseek(f, -8L, SEEK_CUR) !=0) {
1817 moov_pos = ftell(f);
1822 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1826 /* add orientation info */
1827 if (fseek(f, internal_pos, SEEK_SET) < 0) {
1828 _mmcam_dbg_err("fseek failed : errno %d", errno);
1832 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','r','a','k'), FALSE)) {
1833 _mmcam_dbg_err("failed to find [trak] tag");
1837 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','k','h','d'), FALSE)) {
1838 _mmcam_dbg_err("failed to find [tkhd] tag");
1842 _mmcam_dbg_log("found [tkhd] tag");
1844 /* seek to start position of composition matrix */
1845 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
1847 /* update composition matrix for orientation */
1848 _mmcamcorder_update_composition_matrix(f, orientation);
1850 _mmcam_dbg_err("No 'moov' container");
1862 _mmcam_dbg_err("ftell() returns negative value.");
1868 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
1870 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1871 _MMCamcorderSubContext *sc = NULL;
1873 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1875 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1876 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1878 /* check video source element */
1879 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
1880 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
1881 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
1882 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
1883 G_CALLBACK(__mmcamcorder_video_stream_cb),
1885 return MM_ERROR_NONE;
1887 _mmcam_dbg_err("videosrc element is not created yet");
1888 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
1893 int _mmcamcorder_video_prepare_record(MMHandleType handle)
1895 int ret = MM_ERROR_NONE;
1897 _MMCamcorderVideoInfo *info = NULL;
1898 _MMCamcorderSubContext *sc = NULL;
1899 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1901 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1903 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1904 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1905 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1907 info = sc->info_video;
1909 _mmcam_dbg_warn("start");
1911 /* create encoding pipeline */
1912 ret =_mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
1913 if (ret != MM_ERROR_NONE) {
1914 goto _ERR_PREPARE_RECORD;
1917 if (info->filename == NULL) {
1918 char *temp_filename = NULL;
1921 mm_camcorder_get_attributes(handle, NULL,
1922 MMCAM_TARGET_FILENAME, &temp_filename, &size,
1924 if (temp_filename) {
1925 info->filename = strdup(temp_filename);
1928 if (!info->filename) {
1929 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
1930 goto _ERR_PREPARE_RECORD;
1934 _mmcam_dbg_log("Record file name [%s]", info->filename);
1936 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
1937 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
1939 /* Adjust display FPS */
1940 sc->display_interval = 0;
1941 sc->previous_slot_time = 0;
1943 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
1944 if (ret != MM_ERROR_NONE) {
1945 goto _ERR_PREPARE_RECORD;
1948 _mmcam_dbg_warn("done");
1952 _ERR_PREPARE_RECORD:
1953 /* Remove recorder pipeline and recording file which size maybe zero */
1954 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1955 if (info && info->filename) {
1956 _mmcam_dbg_log("file delete(%s)", info->filename);
1957 unlink(info->filename);