4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jeongmo Yang <jm80.yang@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 /*=======================================================================================
24 =======================================================================================*/
25 #include <gst/video/cameracontrol.h>
26 #include <gst/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
30 /*---------------------------------------------------------------------------------------
31 | GLOBAL VARIABLE DEFINITIONS for internal |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_LOCATION_INFO // for add gps information
34 #define MAX_ERROR_MESSAGE_LEN 128
36 /*---------------------------------------------------------------------------------------
37 | LOCAL VARIABLE DEFINITIONS for internal |
38 ---------------------------------------------------------------------------------------*/
39 #define _MMCAMCORDER_MINIMUM_FRAME 5
40 #define _MMCAMCORDER_RETRIAL_COUNT 10
41 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* ms */
42 #define _OFFSET_COMPOSITION_MATRIX 40L
43 #define _GOP_GEN_INTERVAL 1000000000 /*nano seconds*/
45 /*---------------------------------------------------------------------------------------
46 | LOCAL FUNCTION PROTOTYPES: |
47 ---------------------------------------------------------------------------------------*/
48 /* STATIC INTERNAL FUNCTION */
49 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
54 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
55 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
56 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
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 gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
67 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
68 _MMCamcorderSubContext *sc = NULL;
70 GstBuffer *buffer = gst_sample_get_buffer(sample);
71 mmf_return_val_if_fail(buffer, FALSE);
72 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
73 mmf_return_val_if_fail(hcamcorder, FALSE);
75 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
76 mmf_return_val_if_fail(sc, FALSE);
79 _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
80 sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
83 /* push buffer in appsrc to encode */
84 if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
85 sc->info_video->record_dual_stream &&
86 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
87 GstFlowReturn ret = 0;
88 GstClock *pipe_clock = NULL;
90 if(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
91 if(sc->info_video->is_firstframe) {
92 sc->info_video->is_firstframe = FALSE;
93 pipe_clock = GST_ELEMENT_CLOCK(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
95 gst_object_ref(pipe_clock);
96 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer) - (gst_clock_get_time(pipe_clock) - GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
97 gst_object_unref(pipe_clock);
101 if(sc->info_video->is_firstframe) {
102 sc->info_video->is_firstframe = FALSE;
103 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer);
107 GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS (buffer) - sc->info_video->base_video_ts;
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 g_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_SAMPLE_SOUND_NAME_REC_START, FALSE);
597 g_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 /* check decoder recreation */
643 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
644 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
645 ret = MM_ERROR_CAMCORDER_INTERNAL;
646 goto _ERR_CAMCORDER_VIDEO_COMMAND;
649 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
650 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
652 if (ret != MM_ERROR_NONE) {
653 goto _ERR_CAMCORDER_VIDEO_COMMAND;
656 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
657 ret = MM_ERROR_CAMCORDER_INTERNAL;
658 goto _ERR_CAMCORDER_VIDEO_COMMAND;
661 /* Start preview again with new setting */
662 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
663 if (ret != MM_ERROR_NONE) {
664 goto _ERR_CAMCORDER_VIDEO_COMMAND;
667 if (motion_rate < 1.0) {
668 _mmcam_dbg_warn("wait for stabilization of frame");
672 _mmcam_dbg_log("no need to restart preview");
675 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
676 CONFIGURE_CATEGORY_MAIN_RECORD,
680 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
681 CONFIGURE_CATEGORY_MAIN_RECORD,
682 "PassFirstVideoFrame",
683 &(sc->pass_first_vframe));
685 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
686 sc->drop_vframe, sc->pass_first_vframe);
688 info->record_drop_count = (guint)motion_rate;
689 info->record_motion_rate = motion_rate;
690 if (sc->is_modified_rate) {
691 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
693 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
696 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
697 fps, info->record_motion_rate, info->record_timestamp_ratio);
699 /* set push buffer flag */
700 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
701 info->base_video_ts = 0;
703 /* connect video stream cb signal */
704 /*130826 Connect video stream cb for handling fast record frame cb*/
705 if (info->record_dual_stream) {
706 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE) {
707 goto _ERR_CAMCORDER_VIDEO_COMMAND;
711 /* start video stream */
712 if (info->record_dual_stream) {
713 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
715 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
717 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
718 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
720 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
722 _mmcam_dbg_err("could not get camera control");
726 /* check pre-created encode pipeline */
727 g_mutex_lock(&hcamcorder->task_thread_lock);
728 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
729 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
730 /* create encoding pipeline */
731 ret =_mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
732 if (ret != MM_ERROR_NONE) {
733 g_mutex_unlock(&hcamcorder->task_thread_lock);
734 goto _ERR_CAMCORDER_VIDEO_COMMAND;
737 g_mutex_unlock(&hcamcorder->task_thread_lock);
739 /* check recording start sound */
740 _mmcamcorder_sound_solo_play_wait(handle);
742 /**< To fix video recording hanging
743 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
744 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
745 basetime wouldn't change if you set (GstClockTime)0.
746 3. Move set start time position below PAUSED of pipeline.
748 //gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
749 //gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
751 info->video_frame_count = 0;
752 info->is_firstframe = TRUE;
753 info->audio_frame_count = 0;
755 sc->ferror_send = FALSE;
756 sc->ferror_count = 0;
757 hcamcorder->error_occurs = FALSE;
758 sc->bget_eos = FALSE;
760 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
761 if (ret != MM_ERROR_NONE) {
762 /* stop video stream */
763 if (info->record_dual_stream) {
764 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
766 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
768 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
769 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
771 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
773 _mmcam_dbg_err("failed to get camera control");
777 /* Remove recorder pipeline and recording file which size maybe zero */
778 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
779 if (info->filename) {
780 _mmcam_dbg_log("file delete(%s)", info->filename);
781 unlink(info->filename);
783 goto _ERR_CAMCORDER_VIDEO_COMMAND;
786 /*set the camera control to create the GOP so that video record will get a new key frame*/
787 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
788 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
789 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
790 controls = gst_camera_control_list_channels(CameraControl);
791 if (controls != NULL) {
792 for (item = controls ; item && item->data ; item = item->next) {
793 CameraControlChannel = item->data;
794 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
795 if (!strcmp(CameraControlChannel->label, "new-gop")) {
796 //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
802 _mmcam_dbg_warn("failed to find new-gop control channel");
806 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
807 sc->info_image->preview_format);
812 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
813 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
814 /* generate and I-frame on resuming */
815 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
816 controls = gst_camera_control_list_channels(CameraControl);
817 if (controls != NULL) {
818 for (item = controls ; item && item->data ; item = item->next) {
819 CameraControlChannel = item->data;
820 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
821 if (!strcmp(CameraControlChannel->label, "new-gop")) {
822 //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
828 _mmcam_dbg_warn("failed to find new-gop control channel");
833 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
835 _mmcam_dbg_log("Object property settings done");
839 case _MMCamcorder_CMD_PAUSE:
841 if (info->b_commiting) {
842 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
843 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
846 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
847 if (sc->audio_disable) {
848 /* check only video frame */
849 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
851 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
852 _mmcam_dbg_err("Pause fail, frame count %llu",
853 info->video_frame_count);
854 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
856 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu",
857 count, info->video_frame_count);
860 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
862 /* check both of video and audio frame */
863 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
865 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
866 _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
867 info->video_frame_count, info->audio_frame_count);
868 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
870 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
871 count, info->video_frame_count, info->audio_frame_count);
874 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
878 /* block encodebin */
879 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
882 case _MMCamcorder_CMD_CANCEL:
884 if (info->b_commiting) {
885 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
886 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
889 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
891 if (hcamcorder->capture_in_recording == FALSE) {
893 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
894 _mmcam_dbg_err("Failed to Wait capture data");
895 hcamcorder->capture_in_recording = FALSE;
898 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
901 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
904 /* block push buffer */
905 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
907 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
908 if (ret != MM_ERROR_NONE) {
909 goto _ERR_CAMCORDER_VIDEO_COMMAND;
912 /* set recording hint */
913 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
915 /* stop video stream */
916 if (info->record_dual_stream) {
917 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
919 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
921 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
922 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
924 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
926 _mmcam_dbg_err("failed to get camera control");
930 if (info->restart_preview) {
931 /* restart preview */
932 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
933 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
935 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
937 /* check decoder recreation */
938 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
939 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
940 ret = MM_ERROR_CAMCORDER_INTERNAL;
943 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
944 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
946 if (ret != MM_ERROR_NONE) {
947 goto _ERR_CAMCORDER_VIDEO_COMMAND;
950 /* reset restart_preview for inset window layout */
951 info->restart_preview = FALSE;
953 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
954 ret = MM_ERROR_CAMCORDER_INTERNAL;
955 goto _ERR_CAMCORDER_VIDEO_COMMAND;
958 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
959 if (ret != MM_ERROR_NONE) {
960 goto _ERR_CAMCORDER_VIDEO_COMMAND;
964 /* remove target file */
965 if (info->filename) {
966 _mmcam_dbg_log("file delete(%s)", info->filename);
967 unlink(info->filename);
970 sc->isMaxsizePausing = FALSE;
971 sc->isMaxtimePausing = FALSE;
973 sc->display_interval = 0;
974 sc->previous_slot_time = 0;
975 info->video_frame_count = 0;
976 info->audio_frame_count = 0;
978 hcamcorder->capture_in_recording = FALSE;
981 case _MMCamcorder_CMD_COMMIT:
983 if (info->b_commiting) {
984 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
985 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
987 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
988 info->b_commiting = TRUE;
989 sc->bget_eos = FALSE;
992 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
993 if (sc->audio_disable) {
994 /* check only video frame */
995 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
996 hcamcorder->capture_in_recording == FALSE) {
998 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
999 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1000 info->video_frame_count, hcamcorder->capture_in_recording);
1002 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1003 _mmcam_dbg_warn("video frames are enough. keep going...");
1005 info->b_commiting = FALSE;
1006 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1009 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1010 count, info->video_frame_count, hcamcorder->capture_in_recording);
1013 /* check both of video and audio frame */
1014 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1015 info->audio_frame_count &&
1016 hcamcorder->capture_in_recording == FALSE) {
1018 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1019 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1020 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1022 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1023 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1025 info->b_commiting = FALSE;
1026 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1029 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1031 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1032 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1036 if (hcamcorder->capture_in_recording) {
1037 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1038 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1039 _mmcam_dbg_warn("signal received");
1041 _mmcam_dbg_warn("timeout");
1044 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1048 /* block push buffer */
1049 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1050 _mmcam_dbg_log("block push buffer to appsrc");
1052 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1053 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1054 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1056 _mmcam_dbg_err("VIDEO: send EOS failed");
1057 info->b_commiting = FALSE;
1058 ret = MM_ERROR_CAMCORDER_INTERNAL;
1059 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1062 _mmcam_dbg_err("No video stream source");
1063 info->b_commiting = FALSE;
1064 ret = MM_ERROR_CAMCORDER_INTERNAL;
1065 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1068 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1069 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1070 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1072 _mmcam_dbg_err("AUDIO: send EOS failed");
1073 info->b_commiting = FALSE;
1074 ret = MM_ERROR_CAMCORDER_INTERNAL;
1075 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1078 _mmcam_dbg_log("No audio stream");
1082 sc->display_interval = 0;
1083 sc->previous_slot_time = 0;
1086 _mmcam_dbg_log("Start to wait EOS");
1087 ret =_mmcamcorder_get_eos_message(handle);
1088 if (ret != MM_ERROR_NONE) {
1089 info->b_commiting = FALSE;
1090 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1094 hcamcorder->capture_in_recording = FALSE;
1098 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1099 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1102 return MM_ERROR_NONE;
1104 _ERR_CAMCORDER_VIDEO_COMMAND:
1105 if (command == _MMCamcorder_CMD_RECORD) {
1106 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1113 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1115 int ret = MM_ERROR_NONE;
1117 guint64 file_size = 0;
1119 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1120 _MMCamcorderSubContext *sc = NULL;
1121 _MMCamcorderVideoInfo *info = NULL;
1122 _MMCamcorderMsgItem msg;
1123 MMCamRecordingReport *report = NULL;
1125 mmf_return_val_if_fail(hcamcorder, FALSE);
1127 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1128 mmf_return_val_if_fail(sc, FALSE);
1129 mmf_return_val_if_fail(sc->info_video, FALSE);
1131 info = sc->info_video;
1135 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1136 /* Play record stop sound */
1137 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1139 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1141 _mmcamcorder_sound_init(handle);
1143 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1145 _mmcamcorder_sound_finalize(handle);
1148 /* remove blocking part */
1149 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1151 mm_camcorder_get_attributes(handle, NULL,
1152 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1155 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1156 if (ret != MM_ERROR_NONE) {
1157 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1160 /* set recording hint */
1161 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1163 /* stop video stream */
1164 if (info->record_dual_stream) {
1165 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1167 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1169 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1170 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1172 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1174 _mmcam_dbg_err("failed to get camera control");
1178 if (enabletag && !(sc->ferror_send)) {
1179 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1181 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1183 _mmcam_dbg_err("Writing location information FAILED !!");
1187 /* Check file size */
1188 if (info->max_size > 0) {
1189 _mmcamcorder_get_file_size(info->filename, &file_size);
1190 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1191 info->max_size, file_size);
1193 if (file_size > info->max_size) {
1194 _MMCamcorderMsgItem message;
1195 _mmcam_dbg_err("File size is greater than max size !!");
1196 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1197 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1198 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1202 if (info->restart_preview) {
1204 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1205 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1207 _mmcam_dbg_log("Set state of pipeline as READY");
1208 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1210 /* check decoder recreation */
1211 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1212 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1213 ret = MM_ERROR_CAMCORDER_INTERNAL;
1217 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1218 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1219 if (ret != MM_ERROR_NONE) {
1220 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1221 msg.param.code = ret;
1222 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1223 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1226 /* reset restart_preview for inset window layout */
1227 info->restart_preview = FALSE;
1229 /* recover preview size */
1230 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1232 ret =_mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1233 /* Do not return when error is occurred.
1234 Recording file was created successfully, but starting pipeline failed */
1235 if (ret != MM_ERROR_NONE) {
1236 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1237 msg.param.code = ret;
1238 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1239 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1242 _mmcam_dbg_log("No need to restart preview");
1245 /* Send recording report to application */
1246 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1247 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1249 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1251 report->recording_filename = g_strdup(info->filename);
1252 msg.param.data= report;
1254 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1258 sc->pipeline_time = 0;
1260 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1261 sc->isMaxtimePausing = FALSE;
1262 hcamcorder->error_occurs = FALSE;
1264 info->video_frame_count = 0;
1265 info->audio_frame_count = 0;
1267 info->b_commiting = FALSE;
1269 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1270 /* check recording stop sound */
1271 _mmcamcorder_sound_solo_play_wait(handle);
1274 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1281 * This function is record video data probing function.
1282 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1283 * this function will be called when data stream pass through the pad.
1285 * @param[in] pad probing pad which calls this function.
1286 * @param[in] buffer buffer which contains stream data.
1287 * @param[in] u_data user data.
1288 * @return This function returns true on success, or false value with error
1292 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data){
1293 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1294 switch (GST_EVENT_TYPE(event)) {
1295 case GST_EVENT_UNKNOWN:
1296 /* upstream events */
1298 case GST_EVENT_SEEK:
1299 case GST_EVENT_NAVIGATION:
1300 case GST_EVENT_LATENCY:
1301 /* downstream serialized events */
1302 case GST_EVENT_SEGMENT :
1304 case GST_EVENT_BUFFERSIZE:
1305 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1308 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1310 /* bidirectional events */
1311 case GST_EVENT_FLUSH_START:
1312 case GST_EVENT_FLUSH_STOP:
1313 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1316 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1320 return GST_PAD_PROBE_OK;
1324 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1326 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1327 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1329 _MMCamcorderSubContext *sc = NULL;
1330 _MMCamcorderVideoInfo *videoinfo = NULL;
1331 _MMCamcorderMsgItem msg;
1332 guint64 buffer_size = 0;
1333 guint64 trailer_size = 0;
1335 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1336 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1337 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1339 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1340 videoinfo = sc->info_video;
1342 /* get buffer size */
1343 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1344 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1345 return GST_PAD_PROBE_OK;
1348 buffer_size = mapinfo.size;
1349 gst_buffer_unmap(buffer, &mapinfo);
1351 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1353 g_mutex_lock(&videoinfo->size_check_lock);
1355 if (videoinfo->audio_frame_count == 0) {
1356 videoinfo->filesize += buffer_size;
1357 videoinfo->audio_frame_count++;
1358 g_mutex_unlock(&videoinfo->size_check_lock);
1359 return GST_PAD_PROBE_OK;
1362 if (sc->ferror_send || sc->isMaxsizePausing) {
1363 _mmcam_dbg_warn("Recording is paused, drop frames");
1364 g_mutex_unlock(&videoinfo->size_check_lock);
1365 return GST_PAD_PROBE_DROP;
1368 /* get trailer size */
1369 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1370 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1375 /* check max size of recorded file */
1376 if (videoinfo->max_size > 0 &&
1377 videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1378 GstState pipeline_state = GST_STATE_VOID_PENDING;
1379 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1380 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1381 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1382 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1383 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1385 if (!sc->isMaxsizePausing) {
1386 sc->isMaxsizePausing = TRUE;
1387 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1388 if (pipeline_state == GST_STATE_PLAYING) {
1389 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1392 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1393 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1396 g_mutex_unlock(&videoinfo->size_check_lock);
1401 videoinfo->filesize += buffer_size;
1402 videoinfo->audio_frame_count++;
1404 g_mutex_unlock(&videoinfo->size_check_lock);
1406 return GST_PAD_PROBE_OK;
1410 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1415 guint64 free_space = 0;
1416 guint64 buffer_size = 0;
1417 guint64 trailer_size = 0;
1418 guint64 queued_buffer = 0;
1419 char *dir_name = NULL;
1420 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1423 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1424 _MMCamcorderMsgItem msg;
1425 _MMCamcorderSubContext *sc = NULL;
1426 _MMCamcorderVideoInfo *videoinfo = NULL;
1428 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1429 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1431 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1432 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1433 videoinfo = sc->info_video;
1435 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1436 if (sc->ferror_send) {
1437 _mmcam_dbg_warn("file write error, drop frames");
1438 return GST_PAD_PROBE_DROP;
1441 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1442 buffer_size = mapinfo.size;
1443 gst_buffer_unmap(buffer, &mapinfo);
1445 videoinfo->video_frame_count++;
1446 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1447 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1448 info->video_frame_count); */
1449 g_mutex_lock(&videoinfo->size_check_lock);
1450 videoinfo->filesize += buffer_size;
1451 g_mutex_unlock(&videoinfo->size_check_lock);
1452 return GST_PAD_PROBE_OK;
1455 /* get trailer size */
1456 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1457 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1462 dir_name = g_path_get_dirname(videoinfo->filename);
1464 ret = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
1468 _mmcam_dbg_err("failed to get dir name from [%s]", videoinfo->filename);
1472 /*_mmcam_dbg_log("check free space for recording");*/
1475 case -2: /* file not exist */
1476 case -1: /* failed to get free space */
1477 _mmcam_dbg_err("Error occured. [%d]", ret);
1478 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1479 sc->ferror_send = TRUE;
1480 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1482 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1484 msg.param.code = MM_ERROR_FILE_READ;
1486 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1491 return GST_PAD_PROBE_DROP; /* skip this buffer */
1493 default: /* succeeded to get free space */
1494 /* check free space for recording */
1495 /* get queued buffer size */
1496 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1497 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1499 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1500 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1503 queued_buffer = aq_size + vq_size;
1505 /* check free space */
1506 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1507 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1508 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1509 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1510 free_space, trailer_size, buffer_size, queued_buffer);
1512 if (!sc->isMaxsizePausing) {
1513 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1514 sc->isMaxsizePausing = TRUE;
1516 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1517 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1520 return GST_PAD_PROBE_DROP;
1525 g_mutex_lock(&videoinfo->size_check_lock);
1527 /* check max size of recorded file */
1528 if (videoinfo->max_size > 0 &&
1529 videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1530 GstState pipeline_state = GST_STATE_VOID_PENDING;
1531 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1532 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1533 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1534 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1535 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1537 if (!sc->isMaxsizePausing) {
1538 sc->isMaxsizePausing = TRUE;
1539 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1540 if (pipeline_state == GST_STATE_PLAYING) {
1541 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1544 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1545 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1548 g_mutex_unlock(&videoinfo->size_check_lock);
1550 return GST_PAD_PROBE_DROP;
1553 videoinfo->filesize += (guint64)buffer_size;
1556 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1559 g_mutex_unlock(&videoinfo->size_check_lock);
1561 return GST_PAD_PROBE_OK;
1565 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1567 guint64 trailer_size = 0;
1568 guint64 rec_pipe_time = 0;
1569 unsigned int remained_time = 0;
1571 GstClockTime b_time;
1573 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1574 _MMCamcorderMsgItem msg;
1575 _MMCamcorderSubContext *sc = NULL;
1576 _MMCamcorderVideoInfo *videoinfo = NULL;
1578 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1580 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1581 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1583 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1584 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1585 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1587 videoinfo = sc->info_video;
1589 b_time = GST_BUFFER_PTS(buffer);
1591 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1593 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1594 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1599 /* check max time */
1600 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1601 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1602 rec_pipe_time, videoinfo->max_time);
1604 if (!sc->isMaxtimePausing) {
1605 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1607 sc->isMaxtimePausing = TRUE;
1609 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1610 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1611 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1612 msg.param.recording_status.remained_time = 0;
1613 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1615 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1616 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1619 return GST_PAD_PROBE_DROP;
1622 /* calculate remained time can be recorded */
1623 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1624 remained_time = videoinfo->max_time - rec_pipe_time;
1625 } else if (videoinfo->max_size > 0) {
1626 long double max_size = (long double)videoinfo->max_size;
1627 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1629 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1632 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1633 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1634 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1635 msg.param.recording_status.remained_time = remained_time;
1636 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1639 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1640 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1643 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1644 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1647 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1648 record_motion_rate, videoinfo->record_drop_count);
1651 /* drop some frame if fast motion */
1652 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1653 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1655 _mmcam_dbg_warn("drop frame");
1657 return GST_PAD_PROBE_DROP;
1660 videoinfo->record_drop_count = 1;
1662 _mmcam_dbg_warn("pass frame");
1666 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1669 return GST_PAD_PROBE_OK;
1673 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1675 _MMCamcorderMsgItem msg;
1676 guint64 trailer_size = 0;
1677 guint64 rec_pipe_time = 0;
1678 _MMCamcorderSubContext *sc = NULL;
1679 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1680 _MMCamcorderVideoInfo *videoinfo = NULL;
1681 unsigned int remained_time = 0;
1682 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1684 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1685 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1686 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1688 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1689 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1690 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1692 videoinfo = sc->info_video;
1694 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1695 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1696 return GST_PAD_PROBE_OK;
1699 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1701 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1702 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1707 /* calculate remained time can be recorded */
1708 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1709 remained_time = videoinfo->max_time - rec_pipe_time;
1710 } else if (videoinfo->max_size > 0) {
1711 long double max_size = (long double)videoinfo->max_size;
1712 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1714 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1717 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1718 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1719 rec_pipe_time, videoinfo->max_time);
1721 if (!sc->isMaxtimePausing) {
1722 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1724 sc->isMaxtimePausing = TRUE;
1726 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1727 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1728 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1729 msg.param.recording_status.remained_time = 0;
1730 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1732 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1733 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1736 return GST_PAD_PROBE_DROP;
1739 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1740 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1741 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1742 msg.param.recording_status.remained_time = remained_time;
1743 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1746 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1747 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1750 return GST_PAD_PROBE_OK;
1754 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1756 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1757 double volume = 0.0;
1760 int err = MM_ERROR_UNKNOWN;
1761 char *err_name = NULL;
1762 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1765 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1766 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1768 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1769 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1770 MMCAM_AUDIO_VOLUME, &volume,
1771 MMCAM_AUDIO_FORMAT, &format,
1772 MMCAM_AUDIO_CHANNEL, &channel,
1774 if (err != MM_ERROR_NONE) {
1775 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1776 SAFE_FREE(err_name);
1780 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1782 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1784 /* Set audio stream NULL */
1785 if (volume == 0.0) {
1786 memset(mapinfo.data, 0, mapinfo.size);
1789 /* CALL audio stream callback */
1790 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1791 MMCamcorderAudioStreamDataType stream;
1793 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1794 _mmcam_dbg_warn("Not ready for stream callback");
1795 gst_buffer_unmap(buffer, &mapinfo);
1796 return GST_PAD_PROBE_OK;
1799 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1800 GST_BUFFER_DATA(buffer), width, height, format);*/
1802 stream.data = (void *)mapinfo.data;
1803 stream.format = format;
1804 stream.channel = channel;
1805 stream.length = mapinfo.size;
1806 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1808 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1810 if (hcamcorder->astream_cb) {
1811 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1814 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1817 gst_buffer_unmap(buffer, &mapinfo);
1818 return GST_PAD_PROBE_OK;
1822 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1824 gboolean bret = FALSE;
1826 switch (fileformat) {
1827 case MM_FILE_FORMAT_3GP:
1828 case MM_FILE_FORMAT_MP4:
1829 bret = __mmcamcorder_add_metadata_mp4(handle);
1832 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1840 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1844 guint64 udta_size = 0;
1845 gint64 current_pos = 0;
1846 gint64 moov_pos = 0;
1847 gint64 udta_pos = 0;
1848 gdouble longitude = 0;
1849 gdouble latitude = 0;
1850 gdouble altitude = 0;
1852 int orientation = 0;
1854 char *err_name = NULL;
1855 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1856 _MMCamcorderLocationInfo location_info = {0,0,0};
1857 _MMCamcorderLocationInfo geo_info = {0,0,0};
1859 _MMCamcorderVideoInfo *info = NULL;
1860 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1861 _MMCamcorderSubContext *sc = NULL;
1863 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1864 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1866 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1867 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1871 info = sc->info_video;
1873 f = fopen64(info->filename, "rb+");
1875 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1876 _mmcam_dbg_err("file open failed [%s]", err_msg);
1880 mm_camcorder_get_attributes(handle, &err_name,
1881 MMCAM_TAG_LATITUDE, &latitude,
1882 MMCAM_TAG_LONGITUDE, &longitude,
1883 MMCAM_TAG_ALTITUDE, &altitude,
1884 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1885 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1888 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1889 SAFE_FREE (err_name);
1892 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1893 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1894 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1895 geo_info.longitude = longitude *10000;
1896 geo_info.latitude = latitude *10000;
1897 geo_info.altitude = altitude *10000;
1898 /* find udta container.
1899 if, there are udta container, write loci box after that
1900 else, make udta container and write loci box. */
1901 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) {
1904 _mmcam_dbg_log("find udta container");
1907 if (fseek(f, -8L, SEEK_CUR) != 0) {
1911 udta_pos = ftello(f);
1916 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1918 _mmcam_dbg_log("recorded file fread %d", nread);
1920 udta_size = _mmcamcorder_get_container_size(buf);
1922 /* goto end of udta and write 'loci' box */
1923 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1928 if (!_mmcamcorder_write_loci(f, location_info)) {
1929 _mmcam_dbg_err("failed to write loci");
1933 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1934 _mmcam_dbg_err("failed to write geodata");
1939 current_pos = ftello(f);
1940 if (current_pos < 0) {
1944 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1948 _mmcam_dbg_log("No udta container");
1949 if (fseek(f, 0, SEEK_END) != 0) {
1953 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1954 _mmcam_dbg_err("failed to write udta");
1959 /* find moov container.
1960 update moov container size. */
1961 if((current_pos = ftello(f))<0)
1964 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) {
1965 gint64 internal_pos = ftello(f);
1967 _mmcam_dbg_log("found moov container");
1968 if (fseek(f, -8L, SEEK_CUR) !=0) {
1972 moov_pos = ftello(f);
1977 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1981 /* add orientation info */
1982 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1983 _mmcam_dbg_err("fseek failed : errno %d", errno);
1987 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','r','a','k'), FALSE)) {
1988 _mmcam_dbg_err("failed to find [trak] tag");
1992 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','k','h','d'), FALSE)) {
1993 _mmcam_dbg_err("failed to find [tkhd] tag");
1997 _mmcam_dbg_log("found [tkhd] tag");
1999 /* seek to start position of composition matrix */
2000 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
2002 /* update composition matrix for orientation */
2003 _mmcamcorder_update_composition_matrix(f, orientation);
2005 _mmcam_dbg_err("No 'moov' container");
2017 _mmcam_dbg_err("ftell() returns negative value.");
2023 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2025 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2026 _MMCamcorderSubContext *sc = NULL;
2028 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2030 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2031 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2033 /* check video source element */
2034 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2035 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2036 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2037 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2038 G_CALLBACK(__mmcamcorder_video_stream_cb),
2040 return MM_ERROR_NONE;
2042 _mmcam_dbg_err("videosrc element is not created yet");
2043 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2048 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2050 int ret = MM_ERROR_NONE;
2052 _MMCamcorderVideoInfo *info = NULL;
2053 _MMCamcorderSubContext *sc = NULL;
2054 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2056 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2058 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2059 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2060 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2062 info = sc->info_video;
2064 _mmcam_dbg_warn("start");
2066 /* create encoding pipeline */
2067 ret =_mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2068 if (ret != MM_ERROR_NONE) {
2069 goto _ERR_PREPARE_RECORD;
2072 if (info->filename == NULL) {
2073 char *temp_filename = NULL;
2076 mm_camcorder_get_attributes(handle, NULL,
2077 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2079 if (temp_filename) {
2080 info->filename = g_strdup(temp_filename);
2083 if (!info->filename) {
2084 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2085 goto _ERR_PREPARE_RECORD;
2089 _mmcam_dbg_log("Record file name [%s]", info->filename);
2091 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2092 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2094 /* Adjust display FPS */
2095 sc->display_interval = 0;
2096 sc->previous_slot_time = 0;
2098 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2099 if (ret != MM_ERROR_NONE) {
2100 goto _ERR_PREPARE_RECORD;
2103 _mmcam_dbg_warn("done");
2107 _ERR_PREPARE_RECORD:
2108 /* Remove recorder pipeline and recording file which size maybe zero */
2109 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2110 if (info && info->filename) {
2111 _mmcam_dbg_log("file delete(%s)", info->filename);
2112 unlink(info->filename);