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)
466 int ret = MM_ERROR_NONE;
467 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
468 char *err_name = NULL;
469 char *temp_filename = NULL;
470 GstCameraControl *CameraControl = NULL;
471 GstCameraControlChannel *CameraControlChannel = NULL;
472 const GList *controls = NULL;
473 const GList *item = NULL;
476 GstElement *pipeline = NULL;
478 _MMCamcorderVideoInfo *info = NULL;
479 _MMCamcorderSubContext *sc = NULL;
480 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
482 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
484 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
485 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
486 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
487 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
489 info = sc->info_video;
491 _mmcam_dbg_log("Command(%d)", command);
493 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
496 case _MMCamcorder_CMD_RECORD:
498 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
504 int ret_free_space = 0;
505 char *dir_name = NULL;
506 guint64 free_space = 0;
507 int file_system_type = 0;
510 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
512 /* init record_dual_stream */
513 info->record_dual_stream = FALSE;
515 ret = mm_camcorder_get_attributes(handle, &err_name,
516 MMCAM_CAMERA_FPS, &fps,
517 MMCAM_CAMERA_WIDTH, &(info->preview_width),
518 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
519 MMCAM_VIDEO_WIDTH, &(info->video_width),
520 MMCAM_VIDEO_HEIGHT, &(info->video_height),
521 MMCAM_FILE_FORMAT, &fileformat,
522 MMCAM_TARGET_FILENAME, &temp_filename, &size,
523 MMCAM_TARGET_MAX_SIZE, &imax_size,
524 MMCAM_TARGET_TIME_LIMIT, &imax_time,
525 MMCAM_FILE_FORMAT, &(info->fileformat),
526 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
528 if (ret != MM_ERROR_NONE) {
529 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
530 SAFE_FREE (err_name);
531 goto _ERR_CAMCORDER_VIDEO_COMMAND;
534 if (temp_filename == NULL) {
535 _mmcam_dbg_err("filename is not set");
536 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
537 goto _ERR_CAMCORDER_VIDEO_COMMAND;
541 if (imax_size <= 0) {
542 info->max_size = 0; /* do not check */
544 info->max_size = ((guint64)imax_size) << 10; /* to byte */
548 if (imax_time <= 0) {
549 info->max_time = 0; /* do not check */
551 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
554 dir_name = g_path_get_dirname(temp_filename);
556 ret_free_space = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
558 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
560 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
561 /* MSDOS_SUPER_MAGIC : 0x4d44 */
562 if (file_system_type == MSDOS_SUPER_MAGIC &&
563 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
564 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
565 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
566 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
568 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
569 file_system_type, info->max_size);
572 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
578 _mmcam_dbg_err("failed to get directory name");
582 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
583 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
584 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
585 return MM_ERROR_OUT_OF_STORAGE;
588 pthread_mutex_lock(&(hcamcorder->task_thread_lock));
589 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
590 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
591 /* Play record start sound */
592 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_START_SND, FALSE);
594 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
596 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
598 if (info->video_width == 0 || info->video_height == 0) {
599 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
600 info->video_width, info->video_height, info->preview_width, info->preview_height);
601 info->video_width = info->preview_width;
602 info->video_height = info->preview_height;
605 if (info->support_dual_stream) {
606 _mmcam_dbg_warn("DUAL STREAM MODE");
608 info->record_dual_stream = TRUE;
610 /* No need to restart preview */
611 info->restart_preview = FALSE;
613 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
614 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
615 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
616 info->preview_width == info->video_width &&
617 info->preview_height == info->video_height) {
618 _mmcam_dbg_log("H264 preview mode and same resolution");
620 /* No need to restart preview */
621 info->restart_preview = FALSE;
623 /* always need to restart preview */
624 info->restart_preview = TRUE;
627 /* set recording hint */
628 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
630 if (info->restart_preview) {
631 /* stop preview and set new size */
632 _mmcam_dbg_log("restart preview");
634 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
635 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
637 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
639 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
640 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
642 if (ret != MM_ERROR_NONE) {
643 goto _ERR_CAMCORDER_VIDEO_COMMAND;
646 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
647 ret = MM_ERROR_CAMCORDER_INTERNAL;
648 goto _ERR_CAMCORDER_VIDEO_COMMAND;
651 /* Start preview again with new setting */
652 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
653 if (ret != MM_ERROR_NONE) {
654 goto _ERR_CAMCORDER_VIDEO_COMMAND;
657 if (motion_rate < 1.0) {
658 _mmcam_dbg_warn("wait for stabilization of frame");
662 _mmcam_dbg_log("no need to restart preview");
665 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
666 CONFIGURE_CATEGORY_MAIN_RECORD,
670 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
671 CONFIGURE_CATEGORY_MAIN_RECORD,
672 "PassFirstVideoFrame",
673 &(sc->pass_first_vframe));
675 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
676 sc->drop_vframe, sc->pass_first_vframe);
678 info->record_drop_count = (guint)motion_rate;
679 info->record_motion_rate = motion_rate;
680 if (sc->is_modified_rate) {
681 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
683 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
686 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
687 fps, info->record_motion_rate, info->record_timestamp_ratio);
689 /* set push buffer flag */
690 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
691 info->base_video_ts = 0;
693 /* connect video stream cb signal */
694 /*130826 Connect video stream cb for handling fast record frame cb*/
695 if (info->record_dual_stream) {
696 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE) {
697 goto _ERR_CAMCORDER_VIDEO_COMMAND;
701 /* start video stream */
702 if (info->record_dual_stream) {
703 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
705 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
707 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
708 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
710 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
712 _mmcam_dbg_err("could not get camera control");
716 /* check pre-created encode pipeline */
717 pthread_mutex_lock(&(hcamcorder->task_thread_lock));
718 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
719 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
720 /* create encoding pipeline */
721 ret =_mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
722 if (ret != MM_ERROR_NONE) {
723 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
724 goto _ERR_CAMCORDER_VIDEO_COMMAND;
727 pthread_mutex_unlock(&(hcamcorder->task_thread_lock));
729 /* check recording start sound */
730 _mmcamcorder_sound_solo_play_wait(handle);
732 /**< To fix video recording hanging
733 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
734 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
735 basetime wouldn't change if you set (GstClockTime)0.
736 3. Move set start time position below PAUSED of pipeline.
738 //gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
739 //gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
741 info->video_frame_count = 0;
742 info->is_firstframe = TRUE;
743 info->audio_frame_count = 0;
745 sc->ferror_send = FALSE;
746 sc->ferror_count = 0;
747 hcamcorder->error_occurs = FALSE;
748 sc->bget_eos = FALSE;
750 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
751 if (ret != MM_ERROR_NONE) {
752 /* stop video stream */
753 if (info->record_dual_stream) {
754 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
756 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
758 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
759 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
761 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
763 _mmcam_dbg_err("failed to get camera control");
767 /* Remove recorder pipeline and recording file which size maybe zero */
768 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
769 if (info->filename) {
770 _mmcam_dbg_log("file delete(%s)", info->filename);
771 unlink(info->filename);
773 goto _ERR_CAMCORDER_VIDEO_COMMAND;
776 /*set the camera control to create the GOP so that video record will get a new key frame*/
777 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
778 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
779 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
780 controls = gst_camera_control_list_channels(CameraControl);
781 if (controls != NULL) {
782 for (item = controls ; item && item->data ; item = item->next) {
783 CameraControlChannel = item->data;
784 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
785 if (!strcmp(CameraControlChannel->label, "new-gop")) {
786 //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
792 _mmcam_dbg_warn("failed to find new-gop control channel");
796 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
797 sc->info_image->preview_format);
802 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
803 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
804 /* generate and I-frame on resuming */
805 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
806 controls = gst_camera_control_list_channels(CameraControl);
807 if (controls != NULL) {
808 for (item = controls ; item && item->data ; item = item->next) {
809 CameraControlChannel = item->data;
810 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
811 if (!strcmp(CameraControlChannel->label, "new-gop")) {
812 //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
818 _mmcam_dbg_warn("failed to find new-gop control channel");
823 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
825 _mmcam_dbg_log("Object property settings done");
829 case _MMCamcorder_CMD_PAUSE:
833 if (info->b_commiting) {
834 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
835 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
838 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
839 if (sc->audio_disable) {
840 /* check only video frame */
841 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
843 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
844 _mmcam_dbg_err("Pause fail, frame count %" G_GUINT64_FORMAT "",
845 info->video_frame_count);
846 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
848 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %" G_GUINT64_FORMAT "",
849 count, info->video_frame_count);
852 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
854 /* check both of video and audio frame */
855 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
857 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
858 _mmcam_dbg_err("Pause fail, frame count VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
859 info->video_frame_count, info->audio_frame_count);
860 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
862 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
863 count, info->video_frame_count, info->audio_frame_count);
866 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
870 /* block encodebin */
871 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
874 case _MMCamcorder_CMD_CANCEL:
876 if (info->b_commiting) {
877 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
878 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
881 /* block push buffer */
882 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
884 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
885 if (ret != MM_ERROR_NONE) {
886 goto _ERR_CAMCORDER_VIDEO_COMMAND;
889 /* set recording hint */
890 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
892 /* stop video stream */
893 if (info->record_dual_stream) {
894 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
896 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
898 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
899 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
901 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
903 _mmcam_dbg_err("failed to get camera control");
907 if (info->restart_preview) {
908 /* restart preview */
909 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
910 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
912 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
914 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
915 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
916 if (ret != MM_ERROR_NONE) {
917 goto _ERR_CAMCORDER_VIDEO_COMMAND;
920 /* reset restart_preview for inset window layout */
921 info->restart_preview = FALSE;
923 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
924 ret = MM_ERROR_CAMCORDER_INTERNAL;
925 goto _ERR_CAMCORDER_VIDEO_COMMAND;
928 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
929 if (ret != MM_ERROR_NONE) {
930 goto _ERR_CAMCORDER_VIDEO_COMMAND;
934 /* remove target file */
935 if (info->filename) {
936 _mmcam_dbg_log("file delete(%s)", info->filename);
937 unlink(info->filename);
940 sc->isMaxsizePausing = FALSE;
941 sc->isMaxtimePausing = FALSE;
943 sc->display_interval = 0;
944 sc->previous_slot_time = 0;
945 info->video_frame_count = 0;
946 info->audio_frame_count = 0;
950 case _MMCamcorder_CMD_COMMIT:
954 if (info->b_commiting) {
955 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
956 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
958 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
959 info->b_commiting = TRUE;
960 sc->bget_eos = FALSE;
963 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
964 if (sc->audio_disable) {
965 /* check only video frame */
966 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
968 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
969 _mmcam_dbg_err("Commit fail, frame count is %" G_GUINT64_FORMAT "",
970 info->video_frame_count);
971 info->b_commiting = FALSE;
972 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
974 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %" G_GUINT64_FORMAT "",
975 count, info->video_frame_count);
978 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
980 /* check both of video and audio frame */
981 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
983 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
984 _mmcam_dbg_err("Commit fail, VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
985 info->video_frame_count, info->audio_frame_count);
987 info->b_commiting = FALSE;
988 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
990 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]",
991 count, info->video_frame_count, info->audio_frame_count);
994 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
998 /* block push buffer */
999 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1000 _mmcam_dbg_log("block push buffer to appsrc");
1002 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1003 ret = gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos());
1004 _mmcam_dbg_warn("send eos to appsrc result : %d", ret);
1007 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1008 ret = gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
1009 _mmcam_dbg_warn("send eos to audiosrc result : %d", ret);
1013 sc->display_interval = 0;
1014 sc->previous_slot_time = 0;
1017 _mmcam_dbg_log("Start to wait EOS");
1018 ret =_mmcamcorder_get_eos_message(handle);
1019 if (ret != MM_ERROR_NONE) {
1020 info->b_commiting = FALSE;
1021 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1026 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1027 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1030 return MM_ERROR_NONE;
1032 _ERR_CAMCORDER_VIDEO_COMMAND:
1033 if (command == _MMCamcorder_CMD_RECORD) {
1034 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1041 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1043 int ret = MM_ERROR_NONE;
1045 guint64 file_size = 0;
1047 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1048 _MMCamcorderSubContext *sc = NULL;
1049 _MMCamcorderVideoInfo *info = NULL;
1050 _MMCamcorderMsgItem msg;
1051 MMCamRecordingReport *report = NULL;
1053 mmf_return_val_if_fail(hcamcorder, FALSE);
1055 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1056 mmf_return_val_if_fail(sc, FALSE);
1057 mmf_return_val_if_fail(sc->info_video, FALSE);
1059 info = sc->info_video;
1063 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1064 /* Play record stop sound */
1065 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND, FALSE);
1067 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1069 #ifdef _MMCAMCORDER_UPLOAD_SAMPLE
1070 _mmcamcorder_sound_init(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND);
1071 #else /* _MMCAMCORDER_UPLOAD_SAMPLE */
1072 _mmcamcorder_sound_init(handle);
1073 #endif /* _MMCAMCORDER_UPLOAD_SAMPLE */
1075 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1077 _mmcamcorder_sound_finalize(handle);
1080 /* remove blocking part */
1081 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1083 mm_camcorder_get_attributes(handle, NULL,
1084 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1087 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1088 if (ret != MM_ERROR_NONE) {
1089 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1092 /* set recording hint */
1093 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1095 /* stop video stream */
1096 if (info->record_dual_stream) {
1097 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1099 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1101 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1102 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1104 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1106 _mmcam_dbg_err("failed to get camera control");
1110 if (enabletag && !(sc->ferror_send)) {
1111 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1113 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1115 _mmcam_dbg_err("Writing location information FAILED !!");
1119 /* Check file size */
1120 if (info->max_size > 0) {
1121 _mmcamcorder_get_file_size(info->filename, &file_size);
1122 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1123 info->max_size, file_size);
1125 if (file_size > info->max_size) {
1126 _MMCamcorderMsgItem message;
1127 _mmcam_dbg_err("File size is greater than max size !!");
1128 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1129 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1130 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1134 if (info->restart_preview) {
1136 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1137 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1139 _mmcam_dbg_log("Set state of pipeline as READY");
1140 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1143 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1144 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1145 if (ret != MM_ERROR_NONE) {
1146 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1147 msg.param.code = ret;
1148 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1149 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1152 /* reset restart_preview for inset window layout */
1153 info->restart_preview = FALSE;
1155 /* recover preview size */
1156 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1158 ret =_mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1159 /* Do not return when error is occurred.
1160 Recording file was created successfully, but starting pipeline failed */
1161 if (ret != MM_ERROR_NONE) {
1162 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1163 msg.param.code = ret;
1164 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1165 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1168 _mmcam_dbg_log("No need to restart preview");
1171 /* Send recording report to application */
1172 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1173 report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport));
1175 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1177 report->recording_filename = strdup(info->filename);
1178 msg.param.data= report;
1180 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1184 sc->pipeline_time = 0;
1186 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1187 sc->isMaxtimePausing = FALSE;
1188 hcamcorder->error_occurs = FALSE;
1190 info->video_frame_count = 0;
1191 info->audio_frame_count = 0;
1193 info->b_commiting = FALSE;
1195 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1196 /* check recording stop sound */
1197 _mmcamcorder_sound_solo_play_wait(handle);
1200 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1207 * This function is record video data probing function.
1208 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1209 * this function will be called when data stream pass through the pad.
1211 * @param[in] pad probing pad which calls this function.
1212 * @param[in] buffer buffer which contains stream data.
1213 * @param[in] u_data user data.
1214 * @return This function returns true on success, or false value with error
1218 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data){
1219 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1220 switch (GST_EVENT_TYPE(event)) {
1221 case GST_EVENT_UNKNOWN:
1222 /* upstream events */
1224 case GST_EVENT_SEEK:
1225 case GST_EVENT_NAVIGATION:
1226 case GST_EVENT_LATENCY:
1227 /* downstream serialized events */
1228 case GST_EVENT_SEGMENT :
1230 case GST_EVENT_BUFFERSIZE:
1231 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1234 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1236 /* bidirectional events */
1237 case GST_EVENT_FLUSH_START:
1238 case GST_EVENT_FLUSH_STOP:
1239 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1242 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1246 return GST_PAD_PROBE_OK;
1250 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1252 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1253 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1255 _MMCamcorderSubContext *sc = NULL;
1256 _MMCamcorderVideoInfo *videoinfo = NULL;
1257 _MMCamcorderMsgItem msg;
1258 guint64 buffer_size = 0;
1259 guint64 trailer_size = 0;
1261 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1262 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1263 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1265 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1266 videoinfo = sc->info_video;
1268 /* get buffer size */
1269 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1270 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1271 return GST_PAD_PROBE_OK;
1274 buffer_size = mapinfo.size;
1275 gst_buffer_unmap(buffer, &mapinfo);
1277 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1279 pthread_mutex_lock(&(videoinfo->size_check_lock));
1281 if (videoinfo->audio_frame_count == 0) {
1282 videoinfo->filesize += buffer_size;
1283 videoinfo->audio_frame_count++;
1284 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1285 return GST_PAD_PROBE_OK;
1288 if (sc->ferror_send || sc->isMaxsizePausing) {
1289 _mmcam_dbg_warn("Recording is paused, drop frames");
1290 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1291 return GST_PAD_PROBE_DROP;
1294 /* get trailer size */
1295 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1296 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1301 /* check max size of recorded file */
1302 if (videoinfo->max_size > 0 &&
1303 videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1304 GstState pipeline_state = GST_STATE_VOID_PENDING;
1305 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1306 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1307 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1308 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1309 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1311 if (!sc->isMaxsizePausing) {
1312 sc->isMaxsizePausing = TRUE;
1313 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1314 if (pipeline_state == GST_STATE_PLAYING) {
1315 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1318 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1319 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1322 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1327 videoinfo->filesize += buffer_size;
1328 videoinfo->audio_frame_count++;
1330 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1332 return GST_PAD_PROBE_OK;
1336 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1341 guint64 free_space = 0;
1342 guint64 buffer_size = 0;
1343 guint64 trailer_size = 0;
1344 guint64 queued_buffer = 0;
1345 char *dir_name = NULL;
1346 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1349 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1350 _MMCamcorderMsgItem msg;
1351 _MMCamcorderSubContext *sc = NULL;
1352 _MMCamcorderVideoInfo *videoinfo = NULL;
1354 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1355 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1357 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1358 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1359 videoinfo = sc->info_video;
1361 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1362 if (sc->ferror_send) {
1363 _mmcam_dbg_warn("file write error, drop frames");
1364 return GST_PAD_PROBE_DROP;
1367 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1368 buffer_size = mapinfo.size;
1369 gst_buffer_unmap(buffer, &mapinfo);
1371 videoinfo->video_frame_count++;
1372 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1373 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1374 info->video_frame_count); */
1375 pthread_mutex_lock(&(videoinfo->size_check_lock));
1376 videoinfo->filesize += buffer_size;
1377 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1378 return GST_PAD_PROBE_OK;
1381 /* get trailer size */
1382 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1383 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1388 dir_name = g_path_get_dirname(videoinfo->filename);
1390 ret = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
1394 _mmcam_dbg_err("failed to get dir name from [%s]", videoinfo->filename);
1398 /*_mmcam_dbg_log("check free space for recording");*/
1401 case -2: /* file not exist */
1402 case -1: /* failed to get free space */
1403 _mmcam_dbg_err("Error occured. [%d]", ret);
1404 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1405 sc->ferror_send = TRUE;
1406 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1408 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1410 msg.param.code = MM_ERROR_FILE_READ;
1412 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1417 return GST_PAD_PROBE_DROP; /* skip this buffer */
1419 default: /* succeeded to get free space */
1420 /* check free space for recording */
1421 /* get queued buffer size */
1422 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1423 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1425 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1426 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1429 queued_buffer = aq_size + vq_size;
1431 /* check free space */
1432 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1433 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1434 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1435 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1436 free_space, trailer_size, buffer_size, queued_buffer);
1438 if (!sc->isMaxsizePausing) {
1439 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1440 sc->isMaxsizePausing = TRUE;
1442 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1443 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1446 return GST_PAD_PROBE_DROP;
1451 pthread_mutex_lock(&(videoinfo->size_check_lock));
1453 /* check max size of recorded file */
1454 if (videoinfo->max_size > 0 &&
1455 videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1456 GstState pipeline_state = GST_STATE_VOID_PENDING;
1457 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1458 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1459 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1460 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1461 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1463 if (!sc->isMaxsizePausing) {
1464 sc->isMaxsizePausing = TRUE;
1465 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1466 if (pipeline_state == GST_STATE_PLAYING) {
1467 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1470 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1471 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1474 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1476 return GST_PAD_PROBE_DROP;
1479 videoinfo->filesize += (guint64)buffer_size;
1482 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1485 pthread_mutex_unlock(&(videoinfo->size_check_lock));
1487 return GST_PAD_PROBE_OK;
1491 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1493 guint64 trailer_size = 0;
1494 guint64 rec_pipe_time = 0;
1495 unsigned int remained_time = 0;
1497 GstClockTime b_time;
1499 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1500 _MMCamcorderMsgItem msg;
1501 _MMCamcorderSubContext *sc = NULL;
1502 _MMCamcorderVideoInfo *videoinfo = NULL;
1504 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1506 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1507 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1509 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1510 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1511 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1513 videoinfo = sc->info_video;
1515 b_time = GST_BUFFER_PTS(buffer);
1517 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1519 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1520 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1525 /* check max time */
1526 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1527 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1528 rec_pipe_time, videoinfo->max_time);
1530 if (!sc->isMaxtimePausing) {
1531 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1533 sc->isMaxtimePausing = TRUE;
1535 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1536 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1537 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1538 msg.param.recording_status.remained_time = 0;
1539 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1541 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1542 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1545 return GST_PAD_PROBE_DROP;
1548 /* calculate remained time can be recorded */
1549 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1550 remained_time = videoinfo->max_time - rec_pipe_time;
1551 } else if (videoinfo->max_size > 0) {
1552 long double max_size = (long double)videoinfo->max_size;
1553 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1555 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1558 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1559 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1560 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1561 msg.param.recording_status.remained_time = remained_time;
1562 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1565 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1566 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1569 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1570 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1573 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1574 record_motion_rate, videoinfo->record_drop_count);
1577 /* drop some frame if fast motion */
1578 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1579 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1581 _mmcam_dbg_warn("drop frame");
1583 return GST_PAD_PROBE_DROP;
1586 videoinfo->record_drop_count = 1;
1588 _mmcam_dbg_warn("pass frame");
1592 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1595 return GST_PAD_PROBE_OK;
1599 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1601 _MMCamcorderMsgItem msg;
1602 guint64 trailer_size = 0;
1603 guint64 rec_pipe_time = 0;
1604 _MMCamcorderSubContext *sc = NULL;
1605 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1606 _MMCamcorderVideoInfo *videoinfo = NULL;
1607 unsigned int remained_time = 0;
1608 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1610 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1611 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1612 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1614 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1615 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1616 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1618 videoinfo = sc->info_video;
1620 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1621 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1622 return GST_PAD_PROBE_OK;
1625 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1627 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1628 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1633 /* calculate remained time can be recorded */
1634 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1635 remained_time = videoinfo->max_time - rec_pipe_time;
1636 } else if (videoinfo->max_size > 0) {
1637 long double max_size = (long double)videoinfo->max_size;
1638 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1640 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1643 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1644 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1645 rec_pipe_time, videoinfo->max_time);
1647 if (!sc->isMaxtimePausing) {
1648 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1650 sc->isMaxtimePausing = TRUE;
1652 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1653 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1654 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1655 msg.param.recording_status.remained_time = 0;
1656 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1658 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1659 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1662 return GST_PAD_PROBE_DROP;
1665 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1666 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1667 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1668 msg.param.recording_status.remained_time = remained_time;
1669 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1672 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1673 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1676 return GST_PAD_PROBE_OK;
1680 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1682 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1683 double volume = 0.0;
1686 int err = MM_ERROR_UNKNOWN;
1687 char *err_name = NULL;
1688 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1691 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1692 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1694 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1695 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1696 MMCAM_AUDIO_VOLUME, &volume,
1697 MMCAM_AUDIO_FORMAT, &format,
1698 MMCAM_AUDIO_CHANNEL, &channel,
1700 if (err != MM_ERROR_NONE) {
1701 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1702 SAFE_FREE(err_name);
1706 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1708 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1710 /* Set audio stream NULL */
1711 if (volume == 0.0) {
1712 memset(mapinfo.data, 0, mapinfo.size);
1715 /* CALL audio stream callback */
1716 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1717 MMCamcorderAudioStreamDataType stream;
1719 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1720 _mmcam_dbg_warn("Not ready for stream callback");
1721 gst_buffer_unmap(buffer, &mapinfo);
1722 return GST_PAD_PROBE_OK;
1725 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1726 GST_BUFFER_DATA(buffer), width, height, format);*/
1728 stream.data = (void *)mapinfo.data;
1729 stream.format = format;
1730 stream.channel = channel;
1731 stream.length = mapinfo.size;
1732 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1734 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1736 if (hcamcorder->astream_cb) {
1737 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1740 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1743 gst_buffer_unmap(buffer, &mapinfo);
1744 return GST_PAD_PROBE_OK;
1748 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1750 gboolean bret = FALSE;
1752 switch (fileformat) {
1753 case MM_FILE_FORMAT_3GP:
1754 case MM_FILE_FORMAT_MP4:
1755 bret = __mmcamcorder_add_metadata_mp4(handle);
1758 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1766 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1770 guint64 udta_size = 0;
1771 gint64 current_pos = 0;
1772 gint64 moov_pos = 0;
1773 gint64 udta_pos = 0;
1774 gdouble longitude = 0;
1775 gdouble latitude = 0;
1776 gdouble altitude = 0;
1778 int orientation = 0;
1780 char *err_name = NULL;
1781 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1782 _MMCamcorderLocationInfo location_info = {0,0,0};
1783 _MMCamcorderLocationInfo geo_info = {0,0,0};
1785 _MMCamcorderVideoInfo *info = NULL;
1786 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1787 _MMCamcorderSubContext *sc = NULL;
1789 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1790 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1792 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1793 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1797 info = sc->info_video;
1799 f = fopen64(info->filename, "rb+");
1801 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1802 _mmcam_dbg_err("file open failed [%s]", err_msg);
1806 mm_camcorder_get_attributes(handle, &err_name,
1807 MMCAM_TAG_LATITUDE, &latitude,
1808 MMCAM_TAG_LONGITUDE, &longitude,
1809 MMCAM_TAG_ALTITUDE, &altitude,
1810 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1811 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1814 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1815 SAFE_FREE (err_name);
1818 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1819 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1820 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1821 geo_info.longitude = longitude *10000;
1822 geo_info.latitude = latitude *10000;
1823 geo_info.altitude = altitude *10000;
1824 /* find udta container.
1825 if, there are udta container, write loci box after that
1826 else, make udta container and write loci box. */
1827 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) {
1830 _mmcam_dbg_log("find udta container");
1833 if (fseek(f, -8L, SEEK_CUR) != 0) {
1837 udta_pos = ftello(f);
1842 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1844 _mmcam_dbg_log("recorded file fread %d", nread);
1846 udta_size = _mmcamcorder_get_container_size(buf);
1848 /* goto end of udta and write 'loci' box */
1849 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1854 if (!_mmcamcorder_write_loci(f, location_info)) {
1855 _mmcam_dbg_err("failed to write loci");
1859 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1860 _mmcam_dbg_err("failed to write geodata");
1865 current_pos = ftello(f);
1866 if (current_pos < 0) {
1870 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1874 _mmcam_dbg_log("No udta container");
1875 if (fseek(f, 0, SEEK_END) != 0) {
1879 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1880 _mmcam_dbg_err("failed to write udta");
1885 /* find moov container.
1886 update moov container size. */
1887 if((current_pos = ftello(f))<0)
1890 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) {
1891 gint64 internal_pos = ftello(f);
1893 _mmcam_dbg_log("found moov container");
1894 if (fseek(f, -8L, SEEK_CUR) !=0) {
1898 moov_pos = ftello(f);
1903 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1907 /* add orientation info */
1908 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1909 _mmcam_dbg_err("fseek failed : errno %d", errno);
1913 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','r','a','k'), FALSE)) {
1914 _mmcam_dbg_err("failed to find [trak] tag");
1918 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','k','h','d'), FALSE)) {
1919 _mmcam_dbg_err("failed to find [tkhd] tag");
1923 _mmcam_dbg_log("found [tkhd] tag");
1925 /* seek to start position of composition matrix */
1926 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
1928 /* update composition matrix for orientation */
1929 _mmcamcorder_update_composition_matrix(f, orientation);
1931 _mmcam_dbg_err("No 'moov' container");
1943 _mmcam_dbg_err("ftell() returns negative value.");
1949 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
1951 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1952 _MMCamcorderSubContext *sc = NULL;
1954 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1956 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1957 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1959 /* check video source element */
1960 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
1961 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
1962 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
1963 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
1964 G_CALLBACK(__mmcamcorder_video_stream_cb),
1966 return MM_ERROR_NONE;
1968 _mmcam_dbg_err("videosrc element is not created yet");
1969 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
1974 int _mmcamcorder_video_prepare_record(MMHandleType handle)
1976 int ret = MM_ERROR_NONE;
1978 _MMCamcorderVideoInfo *info = NULL;
1979 _MMCamcorderSubContext *sc = NULL;
1980 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1982 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1984 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1985 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1986 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1988 info = sc->info_video;
1990 _mmcam_dbg_warn("start");
1992 /* create encoding pipeline */
1993 ret =_mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
1994 if (ret != MM_ERROR_NONE) {
1995 goto _ERR_PREPARE_RECORD;
1998 if (info->filename == NULL) {
1999 char *temp_filename = NULL;
2002 mm_camcorder_get_attributes(handle, NULL,
2003 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2005 if (temp_filename) {
2006 info->filename = strdup(temp_filename);
2009 if (!info->filename) {
2010 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2011 goto _ERR_PREPARE_RECORD;
2015 _mmcam_dbg_log("Record file name [%s]", info->filename);
2017 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2018 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2020 /* Adjust display FPS */
2021 sc->display_interval = 0;
2022 sc->previous_slot_time = 0;
2024 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2025 if (ret != MM_ERROR_NONE) {
2026 goto _ERR_PREPARE_RECORD;
2029 _mmcam_dbg_warn("done");
2033 _ERR_PREPARE_RECORD:
2034 /* Remove recorder pipeline and recording file which size maybe zero */
2035 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2036 if (info && info->filename) {
2037 _mmcam_dbg_log("file delete(%s)", info->filename);
2038 unlink(info->filename);