4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jeongmo Yang <jm80.yang@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 /*=======================================================================================
24 =======================================================================================*/
25 #include <gst/video/cameracontrol.h>
26 #include <gst/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
30 /*---------------------------------------------------------------------------------------
31 | GLOBAL VARIABLE DEFINITIONS for internal |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_LOCATION_INFO // for add gps information
34 #define MAX_ERROR_MESSAGE_LEN 128
36 /*---------------------------------------------------------------------------------------
37 | LOCAL VARIABLE DEFINITIONS for internal |
38 ---------------------------------------------------------------------------------------*/
39 #define _MMCAMCORDER_MINIMUM_FRAME 5
40 #define _MMCAMCORDER_RETRIAL_COUNT 10
41 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* ms */
42 #define _OFFSET_COMPOSITION_MATRIX 40L
43 #define _GOP_GEN_INTERVAL 1000000000 /*nano seconds*/
45 /*---------------------------------------------------------------------------------------
46 | LOCAL FUNCTION PROTOTYPES: |
47 ---------------------------------------------------------------------------------------*/
48 /* STATIC INTERNAL FUNCTION */
49 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
54 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
55 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
56 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
57 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
59 /*=======================================================================================
60 | FUNCTION DEFINITIONS |
61 =======================================================================================*/
62 /*---------------------------------------------------------------------------------------
63 | GLOBAL FUNCTION DEFINITIONS: |
64 ---------------------------------------------------------------------------------------*/
65 static void __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_if_fail(buffer);
72 mmf_return_if_fail(gst_buffer_n_memory(buffer));
73 mmf_return_if_fail(hcamcorder);
75 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
76 mmf_return_if_fail(sc);
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;
109 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
110 if (ret != GST_FLOW_OK &&
111 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 int audio_disable = FALSE;
135 const char* gst_element_rsink_name = NULL;
138 GstPad *srcpad = NULL;
139 GstPad *sinkpad = NULL;
141 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
142 _MMCamcorderSubContext *sc = NULL;
144 type_element *RecordsinkElement = NULL;
146 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
148 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
149 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
150 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
152 _mmcam_dbg_warn("start");
154 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
155 if (err != MM_ERROR_NONE) {
160 if(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
161 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
162 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
163 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
166 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
168 /* get audio disable */
169 mm_camcorder_get_attributes(handle, NULL,
170 MMCAM_AUDIO_DISABLE, &audio_disable,
173 if (sc->is_modified_rate || audio_disable) {
174 sc->audio_disable = TRUE;
176 sc->audio_disable = FALSE;
178 _mmcam_dbg_log("AUDIO DISABLE : %d (is_modified_rate %d, audio_disable %d)",
179 sc->audio_disable, sc->is_modified_rate, audio_disable);
181 if (sc->audio_disable == FALSE) {
182 /* create audiosrc bin */
183 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
184 if (err != MM_ERROR_NONE) {
189 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
190 if (err != MM_ERROR_NONE) {
194 if (sc->audio_disable == FALSE) {
195 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
196 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
199 /* add element and encodesink bin to encode main pipeline */
200 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
201 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
202 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
203 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
206 /* Link each element : appsrc - capsfilter - encodesink bin */
207 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
208 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
209 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
211 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
212 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
213 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
215 if (sc->audio_disable == FALSE) {
216 srcpad = gst_element_get_static_pad (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
217 sinkpad = gst_element_get_static_pad (sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
218 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
221 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
222 CONFIGURE_CATEGORY_MAIN_RECORD,
225 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
227 /* set data probe function */
229 /* register message cb */
231 /* set data probe function for audio */
233 if (sc->audio_disable == FALSE) {
234 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
235 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
236 __mmcamcorder_audioque_dataprobe, hcamcorder);
237 gst_object_unref(sinkpad);
241 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
242 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
243 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
244 gst_object_unref(srcpad);
247 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
248 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
249 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
250 __mmcamcorder_eventprobe_monitor, hcamcorder);
251 gst_object_unref(srcpad);
256 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
257 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
258 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
259 __mmcamcorder_eventprobe_monitor, hcamcorder);
260 gst_object_unref(srcpad);
264 if (sc->audio_disable) {
265 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
266 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
267 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
268 gst_object_unref(sinkpad);
272 if (!strcmp(gst_element_rsink_name, "filesink")) {
273 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
274 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
275 __mmcamcorder_video_dataprobe_record, hcamcorder);
276 gst_object_unref(srcpad);
279 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
280 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
281 __mmcamcorder_audio_dataprobe_check, hcamcorder);
282 gst_object_unref(srcpad);
286 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
288 /* register pipeline message callback */
289 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
291 gst_object_unref(bus);
294 return MM_ERROR_NONE;
296 pipeline_creation_error:
297 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++) {
298 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
300 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
305 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
307 GstPad *srcpad = NULL;
308 GstPad *sinkpad = NULL;
309 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
310 _MMCamcorderSubContext *sc = NULL;
312 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
314 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
315 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
316 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
320 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
321 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
322 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
323 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
325 /* release audiosrc bin */
326 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
327 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
330 To avoid conflicting between old elements and newly created elements,
331 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
332 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
333 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
334 It's because the pipeline of audio recording destroys at the same time,
335 and '_mmcamcorder_element_release_noti' will perfom removing handle.
337 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
339 _mmcam_dbg_log("Audio pipeline removed");
342 return MM_ERROR_NONE;
346 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
348 GstPad *reqpad = NULL;
349 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
350 _MMCamcorderSubContext *sc = NULL;
352 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
354 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
355 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
356 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
360 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
361 /* release request pad */
362 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
364 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
365 gst_object_unref(reqpad);
369 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
371 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
372 gst_object_unref(reqpad);
376 /* release encode main pipeline */
377 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
380 To avoid conflicting between old elements and newly created elements,
381 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
382 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
383 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
384 It's because the pipeline of audio recording destroys at the same time,
385 and '_mmcamcorder_element_release_noti' will perfom removing handle.
387 //_mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK);
389 _mmcam_dbg_log("Encoder pipeline removed");
392 return MM_ERROR_NONE;
396 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
398 int ret = MM_ERROR_NONE;
399 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
400 _MMCamcorderSubContext *sc = NULL;
404 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
405 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
406 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
408 _mmcam_dbg_log("start");
410 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
411 _mmcam_dbg_warn("pipeline is not existed.");
412 return MM_ERROR_NONE;
415 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
417 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
418 if (ret != MM_ERROR_NONE) {
419 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
423 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
425 /* remove audio pipeline first */
426 ret = _mmcamcorder_remove_audio_pipeline(handle);
427 if (ret != MM_ERROR_NONE) {
428 _mmcam_dbg_err("Fail to remove audio pipeline");
432 ret = _mmcamcorder_remove_encode_pipeline(handle);
433 if (ret != MM_ERROR_NONE) {
434 _mmcam_dbg_err("Fail to remove encoder pipeline");
438 /* Remove pipeline message callback */
439 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
440 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
441 hcamcorder->encode_pipeline_cb_event_id = 0;
444 /* Remove remained message */
446 GstMessage *gst_msg = NULL;
447 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
448 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
449 gst_message_unref(gst_msg);
452 gst_object_unref(bus);
456 _mmcam_dbg_log("done");
462 int _mmcamcorder_video_command(MMHandleType handle, int command)
467 int ret = MM_ERROR_NONE;
468 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
469 char *err_name = NULL;
470 char *temp_filename = NULL;
471 GstCameraControl *CameraControl = NULL;
472 GstCameraControlChannel *CameraControlChannel = NULL;
473 const GList *controls = NULL;
474 const GList *item = NULL;
477 GstElement *pipeline = NULL;
479 _MMCamcorderVideoInfo *info = NULL;
480 _MMCamcorderSubContext *sc = NULL;
481 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
483 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
485 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
486 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
487 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
488 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
490 info = sc->info_video;
492 _mmcam_dbg_log("Command(%d)", command);
494 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
497 case _MMCamcorder_CMD_RECORD:
499 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
505 int ret_free_space = 0;
506 char *dir_name = NULL;
507 guint64 free_space = 0;
508 int file_system_type = 0;
509 int root_directory_length = 0;
512 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
514 /* init record_dual_stream */
515 info->record_dual_stream = FALSE;
517 ret = mm_camcorder_get_attributes(handle, &err_name,
518 MMCAM_CAMERA_FPS, &fps,
519 MMCAM_CAMERA_WIDTH, &(info->preview_width),
520 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
521 MMCAM_VIDEO_WIDTH, &(info->video_width),
522 MMCAM_VIDEO_HEIGHT, &(info->video_height),
523 MMCAM_FILE_FORMAT, &fileformat,
524 MMCAM_TARGET_FILENAME, &temp_filename, &size,
525 MMCAM_TARGET_MAX_SIZE, &imax_size,
526 MMCAM_TARGET_TIME_LIMIT, &imax_time,
527 MMCAM_FILE_FORMAT, &(info->fileformat),
528 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
529 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
531 if (ret != MM_ERROR_NONE) {
532 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
533 SAFE_FREE (err_name);
534 goto _ERR_CAMCORDER_VIDEO_COMMAND;
537 if (temp_filename == NULL) {
538 _mmcam_dbg_err("filename is not set");
539 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
540 goto _ERR_CAMCORDER_VIDEO_COMMAND;
544 if (imax_size <= 0) {
545 info->max_size = 0; /* do not check */
547 info->max_size = ((guint64)imax_size) << 10; /* to byte */
551 if (imax_time <= 0) {
552 info->max_time = 0; /* do not check */
554 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
557 dir_name = g_path_get_dirname(temp_filename);
559 ret_free_space = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
561 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
563 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
564 /* MSDOS_SUPER_MAGIC : 0x4d44 */
565 if (file_system_type == MSDOS_SUPER_MAGIC &&
566 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
567 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
568 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
569 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
571 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
572 file_system_type, info->max_size);
575 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
581 _mmcam_dbg_err("failed to get directory name");
585 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
586 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
587 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
588 return MM_ERROR_OUT_OF_STORAGE;
591 pthread_mutex_lock(&(hcamcorder->task_thread_lock));
592 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
593 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
594 /* Play record start sound */
595 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_START_SND, FALSE);
597 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
599 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
601 if (info->video_width == 0 || info->video_height == 0) {
602 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
603 info->video_width, info->video_height, info->preview_width, info->preview_height);
604 info->video_width = info->preview_width;
605 info->video_height = info->preview_height;
608 if (info->support_dual_stream) {
609 _mmcam_dbg_warn("DUAL STREAM MODE");
611 info->record_dual_stream = TRUE;
613 /* No need to restart preview */
614 info->restart_preview = FALSE;
616 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
617 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
618 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
619 info->preview_width == info->video_width &&
620 info->preview_height == info->video_height) {
621 _mmcam_dbg_log("H264 preview mode and same resolution");
623 /* No need to restart preview */
624 info->restart_preview = FALSE;
626 /* always need to restart preview */
627 info->restart_preview = TRUE;
630 /* set recording hint */
631 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
633 if (info->restart_preview) {
634 /* stop preview and set new size */
635 _mmcam_dbg_log("restart preview");
637 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
638 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
640 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
642 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
643 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
645 if (ret != MM_ERROR_NONE) {
646 goto _ERR_CAMCORDER_VIDEO_COMMAND;
649 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
650 ret = MM_ERROR_CAMCORDER_INTERNAL;
651 goto _ERR_CAMCORDER_VIDEO_COMMAND;
654 /* Start preview again with new setting */
655 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
656 if (ret != MM_ERROR_NONE) {
657 goto _ERR_CAMCORDER_VIDEO_COMMAND;
660 if (motion_rate < 1.0) {
661 _mmcam_dbg_warn("wait for stabilization of frame");
665 _mmcam_dbg_log("no need to restart preview");
668 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
669 CONFIGURE_CATEGORY_MAIN_RECORD,
673 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
674 CONFIGURE_CATEGORY_MAIN_RECORD,
675 "PassFirstVideoFrame",
676 &(sc->pass_first_vframe));
678 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
679 sc->drop_vframe, sc->pass_first_vframe);
681 info->record_drop_count = (guint)motion_rate;
682 info->record_motion_rate = motion_rate;
683 if (sc->is_modified_rate) {
684 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
686 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
689 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
690 fps, info->record_motion_rate, info->record_timestamp_ratio);
692 /* set push buffer flag */
693 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
694 info->base_video_ts = 0;
696 /* connect video stream cb signal */
697 /*130826 Connect video stream cb for handling fast record frame cb*/
698 if (info->record_dual_stream) {
699 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE) {
700 goto _ERR_CAMCORDER_VIDEO_COMMAND;
704 /* start video stream */
705 if (info->record_dual_stream) {
706 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
708 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
710 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
711 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
713 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
715 _mmcam_dbg_err("could not get camera control");
719 /* check pre-created encode pipeline */
720 pthread_mutex_lock(&(hcamcorder->task_thread_lock));
721 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
722 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
723 /* create encoding pipeline */
724 ret =_mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
725 if (ret != MM_ERROR_NONE) {
726 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
727 goto _ERR_CAMCORDER_VIDEO_COMMAND;
730 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
732 /* check recording start sound */
733 _mmcamcorder_sound_solo_play_wait(handle);
735 /**< To fix video recording hanging
736 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
737 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
738 basetime wouldn't change if you set (GstClockTime)0.
739 3. Move set start time position below PAUSED of pipeline.
741 //gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
742 //gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
744 info->video_frame_count = 0;
745 info->is_firstframe = TRUE;
746 info->audio_frame_count = 0;
748 sc->ferror_send = FALSE;
749 sc->ferror_count = 0;
750 hcamcorder->error_occurs = FALSE;
751 sc->bget_eos = FALSE;
753 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
754 if (ret != MM_ERROR_NONE) {
755 /* stop video stream */
756 if (info->record_dual_stream) {
757 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
759 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
761 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
762 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
764 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
766 _mmcam_dbg_err("failed to get camera control");
770 /* Remove recorder pipeline and recording file which size maybe zero */
771 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
772 if (info->filename) {
773 _mmcam_dbg_log("file delete(%s)", info->filename);
774 unlink(info->filename);
776 goto _ERR_CAMCORDER_VIDEO_COMMAND;
779 /*set the camera control to create the GOP so that video record will get a new key frame*/
780 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
781 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
782 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
783 controls = gst_camera_control_list_channels(CameraControl);
784 if (controls != NULL) {
785 for (item = controls ; item && item->data ; item = item->next) {
786 CameraControlChannel = item->data;
787 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
788 if (!strcmp(CameraControlChannel->label, "new-gop")) {
789 //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
795 _mmcam_dbg_warn("failed to find new-gop control channel");
799 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
800 sc->info_image->preview_format);
805 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
806 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
807 /* generate and I-frame on resuming */
808 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
809 controls = gst_camera_control_list_channels(CameraControl);
810 if (controls != NULL) {
811 for (item = controls ; item && item->data ; item = item->next) {
812 CameraControlChannel = item->data;
813 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
814 if (!strcmp(CameraControlChannel->label, "new-gop")) {
815 //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
821 _mmcam_dbg_warn("failed to find new-gop control channel");
826 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
828 _mmcam_dbg_log("Object property settings done");
832 case _MMCamcorder_CMD_PAUSE:
834 if (info->b_commiting) {
835 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
836 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
839 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
840 if (sc->audio_disable) {
841 /* check only video frame */
842 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
844 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
845 _mmcam_dbg_err("Pause fail, frame count %llu",
846 info->video_frame_count);
847 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
849 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu",
850 count, info->video_frame_count);
853 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
855 /* check both of video and audio frame */
856 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
858 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
859 _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
860 info->video_frame_count, info->audio_frame_count);
861 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
863 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
864 count, info->video_frame_count, info->audio_frame_count);
867 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
871 /* block encodebin */
872 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
875 case _MMCamcorder_CMD_CANCEL:
877 if (info->b_commiting) {
878 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
879 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
882 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
884 if (hcamcorder->capture_in_recording == FALSE) {
886 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
887 _mmcam_dbg_err("Failed to Wait capture data");
888 hcamcorder->capture_in_recording = FALSE;
891 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
894 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
897 /* block push buffer */
898 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
900 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
901 if (ret != MM_ERROR_NONE) {
902 goto _ERR_CAMCORDER_VIDEO_COMMAND;
905 /* set recording hint */
906 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
908 /* stop video stream */
909 if (info->record_dual_stream) {
910 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
912 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
914 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
915 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
917 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
919 _mmcam_dbg_err("failed to get camera control");
923 if (info->restart_preview) {
924 /* restart preview */
925 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
926 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
928 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
930 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
931 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
932 if (ret != MM_ERROR_NONE) {
933 goto _ERR_CAMCORDER_VIDEO_COMMAND;
936 /* reset restart_preview for inset window layout */
937 info->restart_preview = FALSE;
939 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
940 ret = MM_ERROR_CAMCORDER_INTERNAL;
941 goto _ERR_CAMCORDER_VIDEO_COMMAND;
944 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
945 if (ret != MM_ERROR_NONE) {
946 goto _ERR_CAMCORDER_VIDEO_COMMAND;
950 /* remove target file */
951 if (info->filename) {
952 _mmcam_dbg_log("file delete(%s)", info->filename);
953 unlink(info->filename);
956 sc->isMaxsizePausing = FALSE;
957 sc->isMaxtimePausing = FALSE;
959 sc->display_interval = 0;
960 sc->previous_slot_time = 0;
961 info->video_frame_count = 0;
962 info->audio_frame_count = 0;
964 hcamcorder->capture_in_recording = FALSE;
967 case _MMCamcorder_CMD_COMMIT:
969 if (info->b_commiting) {
970 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
971 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
973 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
974 info->b_commiting = TRUE;
975 sc->bget_eos = FALSE;
978 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
979 if (sc->audio_disable) {
980 /* check only video frame */
981 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
982 hcamcorder->capture_in_recording == FALSE) {
984 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
985 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
986 info->video_frame_count, hcamcorder->capture_in_recording);
988 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
989 _mmcam_dbg_warn("video frames are enough. keep going...");
991 info->b_commiting = FALSE;
992 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
995 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
996 count, info->video_frame_count, hcamcorder->capture_in_recording);
999 /* check both of video and audio frame */
1000 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1001 info->audio_frame_count &&
1002 hcamcorder->capture_in_recording == FALSE) {
1004 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1005 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1006 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1008 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1009 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1011 info->b_commiting = FALSE;
1012 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1015 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1017 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1018 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1022 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1025 /* block push buffer */
1026 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1027 _mmcam_dbg_log("block push buffer to appsrc");
1029 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1030 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1031 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1033 _mmcam_dbg_err("VIDEO: send EOS failed");
1034 info->b_commiting = FALSE;
1035 ret = MM_ERROR_CAMCORDER_INTERNAL;
1036 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1039 _mmcam_dbg_err("No video stream source");
1040 info->b_commiting = FALSE;
1041 ret = MM_ERROR_CAMCORDER_INTERNAL;
1042 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1045 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1046 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1047 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1049 _mmcam_dbg_err("AUDIO: send EOS failed");
1050 info->b_commiting = FALSE;
1051 ret = MM_ERROR_CAMCORDER_INTERNAL;
1052 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1055 _mmcam_dbg_log("No audio stream");
1059 sc->display_interval = 0;
1060 sc->previous_slot_time = 0;
1063 _mmcam_dbg_log("Start to wait EOS");
1064 ret =_mmcamcorder_get_eos_message(handle);
1065 if (ret != MM_ERROR_NONE) {
1066 info->b_commiting = FALSE;
1067 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1071 hcamcorder->capture_in_recording = FALSE;
1075 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1076 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1079 return MM_ERROR_NONE;
1081 _ERR_CAMCORDER_VIDEO_COMMAND:
1082 if (command == _MMCamcorder_CMD_RECORD) {
1083 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1090 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1092 int ret = MM_ERROR_NONE;
1094 guint64 file_size = 0;
1096 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1097 _MMCamcorderSubContext *sc = NULL;
1098 _MMCamcorderVideoInfo *info = NULL;
1099 _MMCamcorderMsgItem msg;
1100 MMCamRecordingReport *report = NULL;
1102 mmf_return_val_if_fail(hcamcorder, FALSE);
1104 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1105 mmf_return_val_if_fail(sc, FALSE);
1106 mmf_return_val_if_fail(sc->info_video, FALSE);
1108 info = sc->info_video;
1112 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1113 /* Play record stop sound */
1114 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND, FALSE);
1116 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1118 _mmcamcorder_sound_init(handle);
1120 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1122 _mmcamcorder_sound_finalize(handle);
1125 /* remove blocking part */
1126 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1128 mm_camcorder_get_attributes(handle, NULL,
1129 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1132 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1133 if (ret != MM_ERROR_NONE) {
1134 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1137 /* set recording hint */
1138 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1140 /* stop video stream */
1141 if (info->record_dual_stream) {
1142 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1144 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1146 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1147 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1149 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1151 _mmcam_dbg_err("failed to get camera control");
1155 if (enabletag && !(sc->ferror_send)) {
1156 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1158 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1160 _mmcam_dbg_err("Writing location information FAILED !!");
1164 /* Check file size */
1165 if (info->max_size > 0) {
1166 _mmcamcorder_get_file_size(info->filename, &file_size);
1167 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1168 info->max_size, file_size);
1170 if (file_size > info->max_size) {
1171 _MMCamcorderMsgItem message;
1172 _mmcam_dbg_err("File size is greater than max size !!");
1173 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1174 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1175 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1179 if (info->restart_preview) {
1181 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1182 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1184 _mmcam_dbg_log("Set state of pipeline as READY");
1185 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1188 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1189 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1190 if (ret != MM_ERROR_NONE) {
1191 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1192 msg.param.code = ret;
1193 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1194 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1197 /* reset restart_preview for inset window layout */
1198 info->restart_preview = FALSE;
1200 /* recover preview size */
1201 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1203 ret =_mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1204 /* Do not return when error is occurred.
1205 Recording file was created successfully, but starting pipeline failed */
1206 if (ret != MM_ERROR_NONE) {
1207 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1208 msg.param.code = ret;
1209 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1210 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1213 _mmcam_dbg_log("No need to restart preview");
1216 /* Send recording report to application */
1217 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1218 report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport));
1220 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1222 report->recording_filename = strdup(info->filename);
1223 msg.param.data= report;
1225 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1229 sc->pipeline_time = 0;
1231 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1232 sc->isMaxtimePausing = FALSE;
1233 hcamcorder->error_occurs = FALSE;
1235 info->video_frame_count = 0;
1236 info->audio_frame_count = 0;
1238 info->b_commiting = FALSE;
1240 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1241 /* check recording stop sound */
1242 _mmcamcorder_sound_solo_play_wait(handle);
1245 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1252 * This function is record video data probing function.
1253 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1254 * this function will be called when data stream pass through the pad.
1256 * @param[in] pad probing pad which calls this function.
1257 * @param[in] buffer buffer which contains stream data.
1258 * @param[in] u_data user data.
1259 * @return This function returns true on success, or false value with error
1263 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data){
1264 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1265 switch (GST_EVENT_TYPE(event)) {
1266 case GST_EVENT_UNKNOWN:
1267 /* upstream events */
1269 case GST_EVENT_SEEK:
1270 case GST_EVENT_NAVIGATION:
1271 case GST_EVENT_LATENCY:
1272 /* downstream serialized events */
1273 case GST_EVENT_SEGMENT :
1275 case GST_EVENT_BUFFERSIZE:
1276 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1279 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1281 /* bidirectional events */
1282 case GST_EVENT_FLUSH_START:
1283 case GST_EVENT_FLUSH_STOP:
1284 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1287 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1291 return GST_PAD_PROBE_OK;
1295 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1297 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1298 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1300 _MMCamcorderSubContext *sc = NULL;
1301 _MMCamcorderVideoInfo *videoinfo = NULL;
1302 _MMCamcorderMsgItem msg;
1303 guint64 buffer_size = 0;
1304 guint64 trailer_size = 0;
1306 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1307 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1308 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1310 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1311 videoinfo = sc->info_video;
1313 /* get buffer size */
1314 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1315 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1316 return GST_PAD_PROBE_OK;
1319 buffer_size = mapinfo.size;
1320 gst_buffer_unmap(buffer, &mapinfo);
1322 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1324 pthread_mutex_lock(&(videoinfo->size_check_lock));
1326 if (videoinfo->audio_frame_count == 0) {
1327 videoinfo->filesize += buffer_size;
1328 videoinfo->audio_frame_count++;
1329 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1330 return GST_PAD_PROBE_OK;
1333 if (sc->ferror_send || sc->isMaxsizePausing) {
1334 _mmcam_dbg_warn("Recording is paused, drop frames");
1335 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1336 return GST_PAD_PROBE_DROP;
1339 /* get trailer size */
1340 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1341 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1346 /* check max size of recorded file */
1347 if (videoinfo->max_size > 0 &&
1348 videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1349 GstState pipeline_state = GST_STATE_VOID_PENDING;
1350 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1351 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1352 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1353 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1354 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1356 if (!sc->isMaxsizePausing) {
1357 sc->isMaxsizePausing = TRUE;
1358 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1359 if (pipeline_state == GST_STATE_PLAYING) {
1360 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1363 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1364 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1367 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1372 videoinfo->filesize += buffer_size;
1373 videoinfo->audio_frame_count++;
1375 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1377 return GST_PAD_PROBE_OK;
1381 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1386 guint64 free_space = 0;
1387 guint64 buffer_size = 0;
1388 guint64 trailer_size = 0;
1389 guint64 queued_buffer = 0;
1390 char *dir_name = NULL;
1391 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1394 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1395 _MMCamcorderMsgItem msg;
1396 _MMCamcorderSubContext *sc = NULL;
1397 _MMCamcorderVideoInfo *videoinfo = NULL;
1399 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1400 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1402 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1403 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1404 videoinfo = sc->info_video;
1406 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1407 if (sc->ferror_send) {
1408 _mmcam_dbg_warn("file write error, drop frames");
1409 return GST_PAD_PROBE_DROP;
1412 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1413 buffer_size = mapinfo.size;
1414 gst_buffer_unmap(buffer, &mapinfo);
1416 videoinfo->video_frame_count++;
1417 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1418 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1419 info->video_frame_count); */
1420 pthread_mutex_lock(&(videoinfo->size_check_lock));
1421 videoinfo->filesize += buffer_size;
1422 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1423 return GST_PAD_PROBE_OK;
1426 /* get trailer size */
1427 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1428 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1433 dir_name = g_path_get_dirname(videoinfo->filename);
1435 ret = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
1439 _mmcam_dbg_err("failed to get dir name from [%s]", videoinfo->filename);
1443 /*_mmcam_dbg_log("check free space for recording");*/
1446 case -2: /* file not exist */
1447 case -1: /* failed to get free space */
1448 _mmcam_dbg_err("Error occured. [%d]", ret);
1449 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1450 sc->ferror_send = TRUE;
1451 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1453 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1455 msg.param.code = MM_ERROR_FILE_READ;
1457 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1462 return GST_PAD_PROBE_DROP; /* skip this buffer */
1464 default: /* succeeded to get free space */
1465 /* check free space for recording */
1466 /* get queued buffer size */
1467 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1468 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1470 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1471 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1474 queued_buffer = aq_size + vq_size;
1476 /* check free space */
1477 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1478 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1479 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1480 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1481 free_space, trailer_size, buffer_size, queued_buffer);
1483 if (!sc->isMaxsizePausing) {
1484 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1485 sc->isMaxsizePausing = TRUE;
1487 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1488 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1491 return GST_PAD_PROBE_DROP;
1496 pthread_mutex_lock(&(videoinfo->size_check_lock));
1498 /* check max size of recorded file */
1499 if (videoinfo->max_size > 0 &&
1500 videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1501 GstState pipeline_state = GST_STATE_VOID_PENDING;
1502 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1503 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1504 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1505 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1506 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1508 if (!sc->isMaxsizePausing) {
1509 sc->isMaxsizePausing = TRUE;
1510 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1511 if (pipeline_state == GST_STATE_PLAYING) {
1512 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1515 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1516 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1519 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1521 return GST_PAD_PROBE_DROP;
1524 videoinfo->filesize += (guint64)buffer_size;
1527 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1530 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1532 return GST_PAD_PROBE_OK;
1536 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1538 guint64 trailer_size = 0;
1539 guint64 rec_pipe_time = 0;
1540 unsigned int remained_time = 0;
1542 GstClockTime b_time;
1544 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1545 _MMCamcorderMsgItem msg;
1546 _MMCamcorderSubContext *sc = NULL;
1547 _MMCamcorderVideoInfo *videoinfo = NULL;
1549 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1551 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1552 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1554 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1555 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1556 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1558 videoinfo = sc->info_video;
1560 b_time = GST_BUFFER_PTS(buffer);
1562 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1564 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1565 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1570 /* check max time */
1571 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1572 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1573 rec_pipe_time, videoinfo->max_time);
1575 if (!sc->isMaxtimePausing) {
1576 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1578 sc->isMaxtimePausing = TRUE;
1580 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1581 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1582 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1583 msg.param.recording_status.remained_time = 0;
1584 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1586 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1587 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1590 return GST_PAD_PROBE_DROP;
1593 /* calculate remained time can be recorded */
1594 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1595 remained_time = videoinfo->max_time - rec_pipe_time;
1596 } else if (videoinfo->max_size > 0) {
1597 long double max_size = (long double)videoinfo->max_size;
1598 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1600 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1603 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1604 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1605 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1606 msg.param.recording_status.remained_time = remained_time;
1607 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1610 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1611 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1614 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1615 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1618 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1619 record_motion_rate, videoinfo->record_drop_count);
1622 /* drop some frame if fast motion */
1623 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1624 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1626 _mmcam_dbg_warn("drop frame");
1628 return GST_PAD_PROBE_DROP;
1631 videoinfo->record_drop_count = 1;
1633 _mmcam_dbg_warn("pass frame");
1637 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1640 return GST_PAD_PROBE_OK;
1644 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1646 _MMCamcorderMsgItem msg;
1647 guint64 trailer_size = 0;
1648 guint64 rec_pipe_time = 0;
1649 _MMCamcorderSubContext *sc = NULL;
1650 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1651 _MMCamcorderVideoInfo *videoinfo = NULL;
1652 unsigned int remained_time = 0;
1653 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1655 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1656 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1657 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1659 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1660 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1661 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1663 videoinfo = sc->info_video;
1665 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1666 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1667 return GST_PAD_PROBE_OK;
1670 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1672 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1673 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1678 /* calculate remained time can be recorded */
1679 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1680 remained_time = videoinfo->max_time - rec_pipe_time;
1681 } else if (videoinfo->max_size > 0) {
1682 long double max_size = (long double)videoinfo->max_size;
1683 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1685 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1688 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1689 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1690 rec_pipe_time, videoinfo->max_time);
1692 if (!sc->isMaxtimePausing) {
1693 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1695 sc->isMaxtimePausing = TRUE;
1697 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1698 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1699 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1700 msg.param.recording_status.remained_time = 0;
1701 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1703 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1704 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1707 return GST_PAD_PROBE_DROP;
1710 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1711 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1712 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1713 msg.param.recording_status.remained_time = remained_time;
1714 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1717 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1718 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1721 return GST_PAD_PROBE_OK;
1725 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1727 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1728 double volume = 0.0;
1731 int err = MM_ERROR_UNKNOWN;
1732 char *err_name = NULL;
1733 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1736 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1737 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1739 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1740 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1741 MMCAM_AUDIO_VOLUME, &volume,
1742 MMCAM_AUDIO_FORMAT, &format,
1743 MMCAM_AUDIO_CHANNEL, &channel,
1745 if (err != MM_ERROR_NONE) {
1746 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1747 SAFE_FREE(err_name);
1751 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1753 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1755 /* Set audio stream NULL */
1756 if (volume == 0.0) {
1757 memset(mapinfo.data, 0, mapinfo.size);
1760 /* CALL audio stream callback */
1761 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1762 MMCamcorderAudioStreamDataType stream;
1764 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1765 _mmcam_dbg_warn("Not ready for stream callback");
1766 gst_buffer_unmap(buffer, &mapinfo);
1767 return GST_PAD_PROBE_OK;
1770 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1771 GST_BUFFER_DATA(buffer), width, height, format);*/
1773 stream.data = (void *)mapinfo.data;
1774 stream.format = format;
1775 stream.channel = channel;
1776 stream.length = mapinfo.size;
1777 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1779 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1781 if (hcamcorder->astream_cb) {
1782 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1785 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1788 gst_buffer_unmap(buffer, &mapinfo);
1789 return GST_PAD_PROBE_OK;
1793 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1795 gboolean bret = FALSE;
1797 switch (fileformat) {
1798 case MM_FILE_FORMAT_3GP:
1799 case MM_FILE_FORMAT_MP4:
1800 bret = __mmcamcorder_add_metadata_mp4(handle);
1803 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1811 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1815 guint64 udta_size = 0;
1816 gint64 current_pos = 0;
1817 gint64 moov_pos = 0;
1818 gint64 udta_pos = 0;
1819 gdouble longitude = 0;
1820 gdouble latitude = 0;
1821 gdouble altitude = 0;
1823 int orientation = 0;
1825 char *err_name = NULL;
1826 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1827 _MMCamcorderLocationInfo location_info = {0,0,0};
1828 _MMCamcorderLocationInfo geo_info = {0,0,0};
1830 _MMCamcorderVideoInfo *info = NULL;
1831 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1832 _MMCamcorderSubContext *sc = NULL;
1834 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1835 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1837 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1838 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1842 info = sc->info_video;
1844 f = fopen64(info->filename, "rb+");
1846 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1847 _mmcam_dbg_err("file open failed [%s]", err_msg);
1851 mm_camcorder_get_attributes(handle, &err_name,
1852 MMCAM_TAG_LATITUDE, &latitude,
1853 MMCAM_TAG_LONGITUDE, &longitude,
1854 MMCAM_TAG_ALTITUDE, &altitude,
1855 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1856 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1859 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1860 SAFE_FREE (err_name);
1863 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1864 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1865 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1866 geo_info.longitude = longitude *10000;
1867 geo_info.latitude = latitude *10000;
1868 geo_info.altitude = altitude *10000;
1869 /* find udta container.
1870 if, there are udta container, write loci box after that
1871 else, make udta container and write loci box. */
1872 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) {
1875 _mmcam_dbg_log("find udta container");
1878 if (fseek(f, -8L, SEEK_CUR) != 0) {
1882 udta_pos = ftello(f);
1887 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1889 _mmcam_dbg_log("recorded file fread %d", nread);
1891 udta_size = _mmcamcorder_get_container_size(buf);
1893 /* goto end of udta and write 'loci' box */
1894 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1899 if (!_mmcamcorder_write_loci(f, location_info)) {
1900 _mmcam_dbg_err("failed to write loci");
1904 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1905 _mmcam_dbg_err("failed to write geodata");
1910 current_pos = ftello(f);
1911 if (current_pos < 0) {
1915 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1919 _mmcam_dbg_log("No udta container");
1920 if (fseek(f, 0, SEEK_END) != 0) {
1924 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1925 _mmcam_dbg_err("failed to write udta");
1930 /* find moov container.
1931 update moov container size. */
1932 if((current_pos = ftello(f))<0)
1935 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) {
1936 gint64 internal_pos = ftello(f);
1938 _mmcam_dbg_log("found moov container");
1939 if (fseek(f, -8L, SEEK_CUR) !=0) {
1943 moov_pos = ftello(f);
1948 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1952 /* add orientation info */
1953 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1954 _mmcam_dbg_err("fseek failed : errno %d", errno);
1958 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','r','a','k'), FALSE)) {
1959 _mmcam_dbg_err("failed to find [trak] tag");
1963 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','k','h','d'), FALSE)) {
1964 _mmcam_dbg_err("failed to find [tkhd] tag");
1968 _mmcam_dbg_log("found [tkhd] tag");
1970 /* seek to start position of composition matrix */
1971 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
1973 /* update composition matrix for orientation */
1974 _mmcamcorder_update_composition_matrix(f, orientation);
1976 _mmcam_dbg_err("No 'moov' container");
1988 _mmcam_dbg_err("ftell() returns negative value.");
1994 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
1996 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1997 _MMCamcorderSubContext *sc = NULL;
1999 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2001 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2002 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2004 /* check video source element */
2005 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2006 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2007 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2008 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2009 G_CALLBACK(__mmcamcorder_video_stream_cb),
2011 return MM_ERROR_NONE;
2013 _mmcam_dbg_err("videosrc element is not created yet");
2014 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2019 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2021 int ret = MM_ERROR_NONE;
2023 _MMCamcorderVideoInfo *info = NULL;
2024 _MMCamcorderSubContext *sc = NULL;
2025 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2027 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2029 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2030 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2031 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2033 info = sc->info_video;
2035 _mmcam_dbg_warn("start");
2037 /* create encoding pipeline */
2038 ret =_mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2039 if (ret != MM_ERROR_NONE) {
2040 goto _ERR_PREPARE_RECORD;
2043 if (info->filename == NULL) {
2044 char *temp_filename = NULL;
2047 mm_camcorder_get_attributes(handle, NULL,
2048 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2050 if (temp_filename) {
2051 info->filename = strdup(temp_filename);
2054 if (!info->filename) {
2055 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2056 goto _ERR_PREPARE_RECORD;
2060 _mmcam_dbg_log("Record file name [%s]", info->filename);
2062 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2063 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2065 /* Adjust display FPS */
2066 sc->display_interval = 0;
2067 sc->previous_slot_time = 0;
2069 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2070 if (ret != MM_ERROR_NONE) {
2071 goto _ERR_PREPARE_RECORD;
2074 _mmcam_dbg_warn("done");
2078 _ERR_PREPARE_RECORD:
2079 /* Remove recorder pipeline and recording file which size maybe zero */
2080 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2081 if (info && info->filename) {
2082 _mmcam_dbg_log("file delete(%s)", info->filename);
2083 unlink(info->filename);