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 /* set sync handler */
292 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
294 gst_object_unref(bus);
297 return MM_ERROR_NONE;
299 pipeline_creation_error:
300 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++) {
301 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
303 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
308 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
310 GstPad *srcpad = NULL;
311 GstPad *sinkpad = NULL;
312 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
313 _MMCamcorderSubContext *sc = NULL;
315 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
317 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
318 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
319 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
323 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
324 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
325 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
326 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
328 /* release audiosrc bin */
329 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
330 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
333 To avoid conflicting between old elements and newly created elements,
334 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
335 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
336 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
337 It's because the pipeline of audio recording destroys at the same time,
338 and '_mmcamcorder_element_release_noti' will perfom removing handle.
340 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
342 _mmcam_dbg_log("Audio pipeline removed");
345 return MM_ERROR_NONE;
349 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
351 GstPad *reqpad = NULL;
352 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
353 _MMCamcorderSubContext *sc = NULL;
355 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
357 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
358 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
359 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
363 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
364 /* release request pad */
365 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
367 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
368 gst_object_unref(reqpad);
372 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
374 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
375 gst_object_unref(reqpad);
379 /* release encode main pipeline */
380 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
383 To avoid conflicting between old elements and newly created elements,
384 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
385 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
386 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
387 It's because the pipeline of audio recording destroys at the same time,
388 and '_mmcamcorder_element_release_noti' will perfom removing handle.
390 //_mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK);
392 _mmcam_dbg_log("Encoder pipeline removed");
395 return MM_ERROR_NONE;
399 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
401 int ret = MM_ERROR_NONE;
402 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
403 _MMCamcorderSubContext *sc = NULL;
407 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
408 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
409 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
411 _mmcam_dbg_log("start");
413 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
414 _mmcam_dbg_warn("pipeline is not existed.");
415 return MM_ERROR_NONE;
418 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
420 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
421 if (ret != MM_ERROR_NONE) {
422 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
426 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
428 /* remove audio pipeline first */
429 ret = _mmcamcorder_remove_audio_pipeline(handle);
430 if (ret != MM_ERROR_NONE) {
431 _mmcam_dbg_err("Fail to remove audio pipeline");
435 ret = _mmcamcorder_remove_encode_pipeline(handle);
436 if (ret != MM_ERROR_NONE) {
437 _mmcam_dbg_err("Fail to remove encoder pipeline");
441 /* Remove pipeline message callback */
442 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
443 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
444 hcamcorder->encode_pipeline_cb_event_id = 0;
447 /* Remove remained message */
449 GstMessage *gst_msg = NULL;
450 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
451 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
452 gst_message_unref(gst_msg);
455 gst_object_unref(bus);
459 _mmcam_dbg_log("done");
465 int _mmcamcorder_video_command(MMHandleType handle, int command)
470 int ret = MM_ERROR_NONE;
471 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
472 char *err_name = NULL;
473 char *temp_filename = NULL;
474 GstCameraControl *CameraControl = NULL;
475 GstCameraControlChannel *CameraControlChannel = NULL;
476 const GList *controls = NULL;
477 const GList *item = NULL;
480 GstElement *pipeline = NULL;
482 _MMCamcorderVideoInfo *info = NULL;
483 _MMCamcorderSubContext *sc = NULL;
484 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
486 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
488 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
489 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
490 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
491 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
493 info = sc->info_video;
495 _mmcam_dbg_log("Command(%d)", command);
497 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
500 case _MMCamcorder_CMD_RECORD:
502 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
508 int ret_free_space = 0;
509 char *dir_name = NULL;
510 guint64 free_space = 0;
511 int file_system_type = 0;
512 int root_directory_length = 0;
515 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
517 /* init record_dual_stream */
518 info->record_dual_stream = FALSE;
520 ret = mm_camcorder_get_attributes(handle, &err_name,
521 MMCAM_CAMERA_FPS, &fps,
522 MMCAM_CAMERA_WIDTH, &(info->preview_width),
523 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
524 MMCAM_VIDEO_WIDTH, &(info->video_width),
525 MMCAM_VIDEO_HEIGHT, &(info->video_height),
526 MMCAM_FILE_FORMAT, &fileformat,
527 MMCAM_TARGET_FILENAME, &temp_filename, &size,
528 MMCAM_TARGET_MAX_SIZE, &imax_size,
529 MMCAM_TARGET_TIME_LIMIT, &imax_time,
530 MMCAM_FILE_FORMAT, &(info->fileformat),
531 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
532 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
534 if (ret != MM_ERROR_NONE) {
535 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
536 SAFE_FREE (err_name);
537 goto _ERR_CAMCORDER_VIDEO_COMMAND;
540 if (temp_filename == NULL) {
541 _mmcam_dbg_err("filename is not set");
542 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
543 goto _ERR_CAMCORDER_VIDEO_COMMAND;
547 if (imax_size <= 0) {
548 info->max_size = 0; /* do not check */
550 info->max_size = ((guint64)imax_size) << 10; /* to byte */
554 if (imax_time <= 0) {
555 info->max_time = 0; /* do not check */
557 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
560 dir_name = g_path_get_dirname(temp_filename);
562 ret_free_space = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
564 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
566 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
567 /* MSDOS_SUPER_MAGIC : 0x4d44 */
568 if (file_system_type == MSDOS_SUPER_MAGIC &&
569 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
570 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
571 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
572 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
574 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
575 file_system_type, info->max_size);
578 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
584 _mmcam_dbg_err("failed to get directory name");
588 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
589 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
590 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
591 return MM_ERROR_OUT_OF_STORAGE;
594 g_mutex_lock(&hcamcorder->task_thread_lock);
595 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
596 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
597 /* Play record start sound */
598 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
600 g_mutex_unlock(&hcamcorder->task_thread_lock);
602 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
604 if (info->video_width == 0 || info->video_height == 0) {
605 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
606 info->video_width, info->video_height, info->preview_width, info->preview_height);
607 info->video_width = info->preview_width;
608 info->video_height = info->preview_height;
611 if (info->support_dual_stream) {
612 _mmcam_dbg_warn("DUAL STREAM MODE");
614 info->record_dual_stream = TRUE;
616 /* No need to restart preview */
617 info->restart_preview = FALSE;
619 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
620 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
621 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
622 info->preview_width == info->video_width &&
623 info->preview_height == info->video_height) {
624 _mmcam_dbg_log("H264 preview mode and same resolution");
626 /* No need to restart preview */
627 info->restart_preview = FALSE;
629 /* always need to restart preview */
630 info->restart_preview = TRUE;
633 /* set recording hint */
634 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
636 if (info->restart_preview) {
637 /* stop preview and set new size */
638 _mmcam_dbg_log("restart preview");
640 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
641 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
643 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
645 /* check decoder recreation */
646 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
647 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
648 ret = MM_ERROR_CAMCORDER_INTERNAL;
649 goto _ERR_CAMCORDER_VIDEO_COMMAND;
652 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
653 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
655 if (ret != MM_ERROR_NONE) {
656 goto _ERR_CAMCORDER_VIDEO_COMMAND;
659 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
660 ret = MM_ERROR_CAMCORDER_INTERNAL;
661 goto _ERR_CAMCORDER_VIDEO_COMMAND;
664 /* Start preview again with new setting */
665 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
666 if (ret != MM_ERROR_NONE) {
667 goto _ERR_CAMCORDER_VIDEO_COMMAND;
670 if (motion_rate < 1.0) {
671 _mmcam_dbg_warn("wait for stabilization of frame");
675 _mmcam_dbg_log("no need to restart preview");
678 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
679 CONFIGURE_CATEGORY_MAIN_RECORD,
683 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
684 CONFIGURE_CATEGORY_MAIN_RECORD,
685 "PassFirstVideoFrame",
686 &(sc->pass_first_vframe));
688 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
689 sc->drop_vframe, sc->pass_first_vframe);
691 info->record_drop_count = (guint)motion_rate;
692 info->record_motion_rate = motion_rate;
693 if (sc->is_modified_rate) {
694 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
696 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
699 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
700 fps, info->record_motion_rate, info->record_timestamp_ratio);
702 /* set push buffer flag */
703 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
704 info->base_video_ts = 0;
706 /* connect video stream cb signal */
707 /*130826 Connect video stream cb for handling fast record frame cb*/
708 if (info->record_dual_stream) {
709 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE) {
710 goto _ERR_CAMCORDER_VIDEO_COMMAND;
714 /* start video stream */
715 if (info->record_dual_stream) {
716 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
718 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
720 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
721 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
723 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
725 _mmcam_dbg_err("could not get camera control");
729 /* check pre-created encode pipeline */
730 g_mutex_lock(&hcamcorder->task_thread_lock);
731 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
732 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
733 /* create encoding pipeline */
734 ret =_mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
735 if (ret != MM_ERROR_NONE) {
736 g_mutex_unlock(&hcamcorder->task_thread_lock);
737 goto _ERR_CAMCORDER_VIDEO_COMMAND;
740 g_mutex_unlock(&hcamcorder->task_thread_lock);
742 /* check recording start sound */
743 _mmcamcorder_sound_solo_play_wait(handle);
745 /**< To fix video recording hanging
746 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
747 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
748 basetime wouldn't change if you set (GstClockTime)0.
749 3. Move set start time position below PAUSED of pipeline.
751 //gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
752 //gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
754 info->video_frame_count = 0;
755 info->is_firstframe = TRUE;
756 info->audio_frame_count = 0;
758 sc->ferror_send = FALSE;
759 sc->ferror_count = 0;
760 hcamcorder->error_occurs = FALSE;
761 sc->bget_eos = FALSE;
763 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
764 if (ret != MM_ERROR_NONE) {
765 /* stop video stream */
766 if (info->record_dual_stream) {
767 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
769 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
771 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
772 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
774 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
776 _mmcam_dbg_err("failed to get camera control");
780 /* Remove recorder pipeline and recording file which size maybe zero */
781 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
782 if (info->filename) {
783 _mmcam_dbg_log("file delete(%s)", info->filename);
784 unlink(info->filename);
786 goto _ERR_CAMCORDER_VIDEO_COMMAND;
789 /*set the camera control to create the GOP so that video record will get a new key frame*/
790 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
791 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
792 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
793 controls = gst_camera_control_list_channels(CameraControl);
794 if (controls != NULL) {
795 for (item = controls ; item && item->data ; item = item->next) {
796 CameraControlChannel = item->data;
797 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
798 if (!strcmp(CameraControlChannel->label, "new-gop")) {
799 //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
805 _mmcam_dbg_warn("failed to find new-gop control channel");
809 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
810 sc->info_image->preview_format);
815 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
816 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
817 /* generate and I-frame on resuming */
818 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
819 controls = gst_camera_control_list_channels(CameraControl);
820 if (controls != NULL) {
821 for (item = controls ; item && item->data ; item = item->next) {
822 CameraControlChannel = item->data;
823 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
824 if (!strcmp(CameraControlChannel->label, "new-gop")) {
825 //gst_camera_control_set_value(CameraControl, CameraControlChannel, 1);
831 _mmcam_dbg_warn("failed to find new-gop control channel");
836 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
838 _mmcam_dbg_log("Object property settings done");
842 case _MMCamcorder_CMD_PAUSE:
844 if (info->b_commiting) {
845 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
846 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
849 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
850 if (sc->audio_disable) {
851 /* check only video frame */
852 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
854 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
855 _mmcam_dbg_err("Pause fail, frame count %llu",
856 info->video_frame_count);
857 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
859 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu",
860 count, info->video_frame_count);
863 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
865 /* check both of video and audio frame */
866 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
868 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
869 _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
870 info->video_frame_count, info->audio_frame_count);
871 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
873 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
874 count, info->video_frame_count, info->audio_frame_count);
877 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
881 /* block encodebin */
882 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
885 case _MMCamcorder_CMD_CANCEL:
887 if (info->b_commiting) {
888 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
889 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
892 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
894 if (hcamcorder->capture_in_recording == FALSE) {
896 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
897 _mmcam_dbg_err("Failed to Wait capture data");
898 hcamcorder->capture_in_recording = FALSE;
901 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
904 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
907 /* block push buffer */
908 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
910 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
911 if (ret != MM_ERROR_NONE) {
912 goto _ERR_CAMCORDER_VIDEO_COMMAND;
915 /* set recording hint */
916 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
918 /* stop video stream */
919 if (info->record_dual_stream) {
920 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
922 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
924 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
925 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
927 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
929 _mmcam_dbg_err("failed to get camera control");
933 if (info->restart_preview) {
934 /* restart preview */
935 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
936 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
938 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
940 /* check decoder recreation */
941 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
942 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
943 ret = MM_ERROR_CAMCORDER_INTERNAL;
946 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
947 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
949 if (ret != MM_ERROR_NONE) {
950 goto _ERR_CAMCORDER_VIDEO_COMMAND;
953 /* reset restart_preview for inset window layout */
954 info->restart_preview = FALSE;
956 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
957 ret = MM_ERROR_CAMCORDER_INTERNAL;
958 goto _ERR_CAMCORDER_VIDEO_COMMAND;
961 ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
962 if (ret != MM_ERROR_NONE) {
963 goto _ERR_CAMCORDER_VIDEO_COMMAND;
967 /* remove target file */
968 if (info->filename) {
969 _mmcam_dbg_log("file delete(%s)", info->filename);
970 unlink(info->filename);
973 sc->isMaxsizePausing = FALSE;
974 sc->isMaxtimePausing = FALSE;
976 sc->display_interval = 0;
977 sc->previous_slot_time = 0;
978 info->video_frame_count = 0;
979 info->audio_frame_count = 0;
981 hcamcorder->capture_in_recording = FALSE;
984 case _MMCamcorder_CMD_COMMIT:
986 if (info->b_commiting) {
987 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
988 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
990 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
991 info->b_commiting = TRUE;
992 sc->bget_eos = FALSE;
995 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
996 if (sc->audio_disable) {
997 /* check only video frame */
998 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
999 hcamcorder->capture_in_recording == FALSE) {
1001 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1002 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1003 info->video_frame_count, hcamcorder->capture_in_recording);
1005 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1006 _mmcam_dbg_warn("video frames are enough. keep going...");
1008 info->b_commiting = FALSE;
1009 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1012 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1013 count, info->video_frame_count, hcamcorder->capture_in_recording);
1016 /* check both of video and audio frame */
1017 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1018 info->audio_frame_count &&
1019 hcamcorder->capture_in_recording == FALSE) {
1021 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1022 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1023 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1025 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1026 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1028 info->b_commiting = FALSE;
1029 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1032 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1034 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1035 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1039 if (hcamcorder->capture_in_recording) {
1040 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1041 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1042 _mmcam_dbg_warn("signal received");
1044 _mmcam_dbg_warn("timeout");
1047 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1051 /* block push buffer */
1052 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1053 _mmcam_dbg_log("block push buffer to appsrc");
1055 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1056 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1057 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1059 _mmcam_dbg_err("VIDEO: send EOS failed");
1060 info->b_commiting = FALSE;
1061 ret = MM_ERROR_CAMCORDER_INTERNAL;
1062 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1065 _mmcam_dbg_err("No video stream source");
1066 info->b_commiting = FALSE;
1067 ret = MM_ERROR_CAMCORDER_INTERNAL;
1068 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1071 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1072 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1073 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1075 _mmcam_dbg_err("AUDIO: send EOS failed");
1076 info->b_commiting = FALSE;
1077 ret = MM_ERROR_CAMCORDER_INTERNAL;
1078 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1081 _mmcam_dbg_log("No audio stream");
1085 sc->display_interval = 0;
1086 sc->previous_slot_time = 0;
1089 _mmcam_dbg_log("Start to wait EOS");
1090 ret =_mmcamcorder_get_eos_message(handle);
1091 if (ret != MM_ERROR_NONE) {
1092 info->b_commiting = FALSE;
1093 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1097 hcamcorder->capture_in_recording = FALSE;
1101 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1102 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1105 return MM_ERROR_NONE;
1107 _ERR_CAMCORDER_VIDEO_COMMAND:
1108 if (command == _MMCamcorder_CMD_RECORD) {
1109 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1116 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1118 int ret = MM_ERROR_NONE;
1120 guint64 file_size = 0;
1122 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1123 _MMCamcorderSubContext *sc = NULL;
1124 _MMCamcorderVideoInfo *info = NULL;
1125 _MMCamcorderMsgItem msg;
1126 MMCamRecordingReport *report = NULL;
1128 mmf_return_val_if_fail(hcamcorder, FALSE);
1130 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1131 mmf_return_val_if_fail(sc, FALSE);
1132 mmf_return_val_if_fail(sc->info_video, FALSE);
1134 info = sc->info_video;
1138 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1139 /* Play record stop sound */
1140 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1142 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1144 _mmcamcorder_sound_init(handle);
1146 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1148 _mmcamcorder_sound_finalize(handle);
1151 /* remove blocking part */
1152 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1154 mm_camcorder_get_attributes(handle, NULL,
1155 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1158 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1159 if (ret != MM_ERROR_NONE) {
1160 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1163 /* set recording hint */
1164 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1166 /* stop video stream */
1167 if (info->record_dual_stream) {
1168 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1170 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1172 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1173 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1175 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1177 _mmcam_dbg_err("failed to get camera control");
1181 if (enabletag && !(sc->ferror_send)) {
1182 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1184 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1186 _mmcam_dbg_err("Writing location information FAILED !!");
1190 /* Check file size */
1191 if (info->max_size > 0) {
1192 _mmcamcorder_get_file_size(info->filename, &file_size);
1193 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1194 info->max_size, file_size);
1196 if (file_size > info->max_size) {
1197 _MMCamcorderMsgItem message;
1198 _mmcam_dbg_err("File size is greater than max size !!");
1199 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1200 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1201 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1205 if (info->restart_preview) {
1207 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1208 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1210 _mmcam_dbg_log("Set state of pipeline as READY");
1211 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1213 /* check decoder recreation */
1214 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1215 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1216 ret = MM_ERROR_CAMCORDER_INTERNAL;
1220 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1221 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1222 if (ret != MM_ERROR_NONE) {
1223 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1224 msg.param.code = ret;
1225 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1226 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1229 /* reset restart_preview for inset window layout */
1230 info->restart_preview = FALSE;
1232 /* recover preview size */
1233 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1235 ret =_mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1236 /* Do not return when error is occurred.
1237 Recording file was created successfully, but starting pipeline failed */
1238 if (ret != MM_ERROR_NONE) {
1239 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1240 msg.param.code = ret;
1241 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1242 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1245 _mmcam_dbg_log("No need to restart preview");
1248 /* Send recording report to application */
1249 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1250 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1252 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1254 report->recording_filename = g_strdup(info->filename);
1255 msg.param.data= report;
1257 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1261 sc->pipeline_time = 0;
1263 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1264 sc->isMaxtimePausing = FALSE;
1265 hcamcorder->error_occurs = FALSE;
1267 info->video_frame_count = 0;
1268 info->audio_frame_count = 0;
1270 info->b_commiting = FALSE;
1272 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) {
1273 /* check recording stop sound */
1274 _mmcamcorder_sound_solo_play_wait(handle);
1277 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1284 * This function is record video data probing function.
1285 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1286 * this function will be called when data stream pass through the pad.
1288 * @param[in] pad probing pad which calls this function.
1289 * @param[in] buffer buffer which contains stream data.
1290 * @param[in] u_data user data.
1291 * @return This function returns true on success, or false value with error
1295 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data){
1296 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1297 switch (GST_EVENT_TYPE(event)) {
1298 case GST_EVENT_UNKNOWN:
1299 /* upstream events */
1301 case GST_EVENT_SEEK:
1302 case GST_EVENT_NAVIGATION:
1303 case GST_EVENT_LATENCY:
1304 /* downstream serialized events */
1305 case GST_EVENT_SEGMENT :
1307 case GST_EVENT_BUFFERSIZE:
1308 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1311 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1313 /* bidirectional events */
1314 case GST_EVENT_FLUSH_START:
1315 case GST_EVENT_FLUSH_STOP:
1316 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1319 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1323 return GST_PAD_PROBE_OK;
1327 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1329 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1330 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1332 _MMCamcorderSubContext *sc = NULL;
1333 _MMCamcorderVideoInfo *videoinfo = NULL;
1334 _MMCamcorderMsgItem msg;
1335 guint64 buffer_size = 0;
1336 guint64 trailer_size = 0;
1338 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1339 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1340 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1342 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1343 videoinfo = sc->info_video;
1345 /* get buffer size */
1346 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1347 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1348 return GST_PAD_PROBE_OK;
1351 buffer_size = mapinfo.size;
1352 gst_buffer_unmap(buffer, &mapinfo);
1354 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1356 g_mutex_lock(&videoinfo->size_check_lock);
1358 if (videoinfo->audio_frame_count == 0) {
1359 videoinfo->filesize += buffer_size;
1360 videoinfo->audio_frame_count++;
1361 g_mutex_unlock(&videoinfo->size_check_lock);
1362 return GST_PAD_PROBE_OK;
1365 if (sc->ferror_send || sc->isMaxsizePausing) {
1366 _mmcam_dbg_warn("Recording is paused, drop frames");
1367 g_mutex_unlock(&videoinfo->size_check_lock);
1368 return GST_PAD_PROBE_DROP;
1371 /* get trailer size */
1372 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1373 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1378 /* check max size of recorded file */
1379 if (videoinfo->max_size > 0 &&
1380 videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1381 GstState pipeline_state = GST_STATE_VOID_PENDING;
1382 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1383 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1384 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1385 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1386 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1388 if (!sc->isMaxsizePausing) {
1389 sc->isMaxsizePausing = TRUE;
1390 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1391 if (pipeline_state == GST_STATE_PLAYING) {
1392 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1395 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1396 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1399 g_mutex_unlock(&videoinfo->size_check_lock);
1404 videoinfo->filesize += buffer_size;
1405 videoinfo->audio_frame_count++;
1407 g_mutex_unlock(&videoinfo->size_check_lock);
1409 return GST_PAD_PROBE_OK;
1413 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1418 guint64 free_space = 0;
1419 guint64 buffer_size = 0;
1420 guint64 trailer_size = 0;
1421 guint64 queued_buffer = 0;
1422 char *dir_name = NULL;
1423 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1426 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1427 _MMCamcorderMsgItem msg;
1428 _MMCamcorderSubContext *sc = NULL;
1429 _MMCamcorderVideoInfo *videoinfo = NULL;
1431 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1432 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1434 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1435 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1436 videoinfo = sc->info_video;
1438 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1439 if (sc->ferror_send) {
1440 _mmcam_dbg_warn("file write error, drop frames");
1441 return GST_PAD_PROBE_DROP;
1444 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1445 buffer_size = mapinfo.size;
1446 gst_buffer_unmap(buffer, &mapinfo);
1448 videoinfo->video_frame_count++;
1449 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1450 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1451 info->video_frame_count); */
1452 g_mutex_lock(&videoinfo->size_check_lock);
1453 videoinfo->filesize += buffer_size;
1454 g_mutex_unlock(&videoinfo->size_check_lock);
1455 return GST_PAD_PROBE_OK;
1458 /* get trailer size */
1459 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1460 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1465 dir_name = g_path_get_dirname(videoinfo->filename);
1467 ret = _mmcamcorder_get_freespace(dir_name, hcamcorder->root_directory, &free_space);
1471 _mmcam_dbg_err("failed to get dir name from [%s]", videoinfo->filename);
1475 /*_mmcam_dbg_log("check free space for recording");*/
1478 case -2: /* file not exist */
1479 case -1: /* failed to get free space */
1480 _mmcam_dbg_err("Error occured. [%d]", ret);
1481 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1482 sc->ferror_send = TRUE;
1483 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1485 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1487 msg.param.code = MM_ERROR_FILE_READ;
1489 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1494 return GST_PAD_PROBE_DROP; /* skip this buffer */
1496 default: /* succeeded to get free space */
1497 /* check free space for recording */
1498 /* get queued buffer size */
1499 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1500 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1502 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1503 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1506 queued_buffer = aq_size + vq_size;
1508 /* check free space */
1509 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1510 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1511 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1512 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1513 free_space, trailer_size, buffer_size, queued_buffer);
1515 if (!sc->isMaxsizePausing) {
1516 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1517 sc->isMaxsizePausing = TRUE;
1519 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1520 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1523 return GST_PAD_PROBE_DROP;
1528 g_mutex_lock(&videoinfo->size_check_lock);
1530 /* check max size of recorded file */
1531 if (videoinfo->max_size > 0 &&
1532 videoinfo->max_size < videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) {
1533 GstState pipeline_state = GST_STATE_VOID_PENDING;
1534 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1535 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1536 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1537 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1538 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1540 if (!sc->isMaxsizePausing) {
1541 sc->isMaxsizePausing = TRUE;
1542 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1543 if (pipeline_state == GST_STATE_PLAYING) {
1544 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1547 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1548 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1551 g_mutex_unlock(&videoinfo->size_check_lock);
1553 return GST_PAD_PROBE_DROP;
1556 videoinfo->filesize += (guint64)buffer_size;
1559 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1562 g_mutex_unlock(&videoinfo->size_check_lock);
1564 return GST_PAD_PROBE_OK;
1568 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1570 guint64 trailer_size = 0;
1571 guint64 rec_pipe_time = 0;
1572 unsigned int remained_time = 0;
1574 GstClockTime b_time;
1576 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1577 _MMCamcorderMsgItem msg;
1578 _MMCamcorderSubContext *sc = NULL;
1579 _MMCamcorderVideoInfo *videoinfo = NULL;
1581 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1583 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1584 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1586 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1587 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1588 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1590 videoinfo = sc->info_video;
1592 b_time = GST_BUFFER_PTS(buffer);
1594 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1596 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1597 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1602 /* check max time */
1603 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1604 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1605 rec_pipe_time, videoinfo->max_time);
1607 if (!sc->isMaxtimePausing) {
1608 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1610 sc->isMaxtimePausing = TRUE;
1612 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1613 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1614 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1615 msg.param.recording_status.remained_time = 0;
1616 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1618 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1619 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1622 return GST_PAD_PROBE_DROP;
1625 /* calculate remained time can be recorded */
1626 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1627 remained_time = videoinfo->max_time - rec_pipe_time;
1628 } else if (videoinfo->max_size > 0) {
1629 long double max_size = (long double)videoinfo->max_size;
1630 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1632 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1635 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1636 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1637 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1638 msg.param.recording_status.remained_time = remained_time;
1639 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1642 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1643 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1646 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1647 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1650 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1651 record_motion_rate, videoinfo->record_drop_count);
1654 /* drop some frame if fast motion */
1655 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1656 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1658 _mmcam_dbg_warn("drop frame");
1660 return GST_PAD_PROBE_DROP;
1663 videoinfo->record_drop_count = 1;
1665 _mmcam_dbg_warn("pass frame");
1669 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1672 return GST_PAD_PROBE_OK;
1676 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1678 _MMCamcorderMsgItem msg;
1679 guint64 trailer_size = 0;
1680 guint64 rec_pipe_time = 0;
1681 _MMCamcorderSubContext *sc = NULL;
1682 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1683 _MMCamcorderVideoInfo *videoinfo = NULL;
1684 unsigned int remained_time = 0;
1685 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1687 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1688 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1689 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1691 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1692 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1693 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1695 videoinfo = sc->info_video;
1697 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1698 _mmcam_dbg_err( "Buffer timestamp is invalid, check it");
1699 return GST_PAD_PROBE_OK;
1702 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1704 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1705 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1710 /* calculate remained time can be recorded */
1711 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1712 remained_time = videoinfo->max_time - rec_pipe_time;
1713 } else if (videoinfo->max_size > 0) {
1714 long double max_size = (long double)videoinfo->max_size;
1715 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1717 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1720 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1721 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1722 rec_pipe_time, videoinfo->max_time);
1724 if (!sc->isMaxtimePausing) {
1725 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1727 sc->isMaxtimePausing = TRUE;
1729 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1730 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1731 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1732 msg.param.recording_status.remained_time = 0;
1733 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1735 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1736 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1739 return GST_PAD_PROBE_DROP;
1742 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1743 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1744 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1745 msg.param.recording_status.remained_time = remained_time;
1746 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1749 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1750 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1753 return GST_PAD_PROBE_OK;
1757 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1759 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1760 double volume = 0.0;
1763 int err = MM_ERROR_UNKNOWN;
1764 char *err_name = NULL;
1765 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1768 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1769 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1771 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1772 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1773 MMCAM_AUDIO_VOLUME, &volume,
1774 MMCAM_AUDIO_FORMAT, &format,
1775 MMCAM_AUDIO_CHANNEL, &channel,
1777 if (err != MM_ERROR_NONE) {
1778 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1779 SAFE_FREE(err_name);
1783 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1785 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1787 /* Set audio stream NULL */
1788 if (volume == 0.0) {
1789 memset(mapinfo.data, 0, mapinfo.size);
1792 /* CALL audio stream callback */
1793 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1794 MMCamcorderAudioStreamDataType stream;
1796 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1797 _mmcam_dbg_warn("Not ready for stream callback");
1798 gst_buffer_unmap(buffer, &mapinfo);
1799 return GST_PAD_PROBE_OK;
1802 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1803 GST_BUFFER_DATA(buffer), width, height, format);*/
1805 stream.data = (void *)mapinfo.data;
1806 stream.format = format;
1807 stream.channel = channel;
1808 stream.length = mapinfo.size;
1809 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1811 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1813 if (hcamcorder->astream_cb) {
1814 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1817 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1820 gst_buffer_unmap(buffer, &mapinfo);
1821 return GST_PAD_PROBE_OK;
1825 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1827 gboolean bret = FALSE;
1829 switch (fileformat) {
1830 case MM_FILE_FORMAT_3GP:
1831 case MM_FILE_FORMAT_MP4:
1832 bret = __mmcamcorder_add_metadata_mp4(handle);
1835 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1843 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1847 guint64 udta_size = 0;
1848 gint64 current_pos = 0;
1849 gint64 moov_pos = 0;
1850 gint64 udta_pos = 0;
1851 gdouble longitude = 0;
1852 gdouble latitude = 0;
1853 gdouble altitude = 0;
1855 int orientation = 0;
1857 char *err_name = NULL;
1858 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1859 _MMCamcorderLocationInfo location_info = {0,0,0};
1860 _MMCamcorderLocationInfo geo_info = {0,0,0};
1862 _MMCamcorderVideoInfo *info = NULL;
1863 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1864 _MMCamcorderSubContext *sc = NULL;
1866 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1867 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1869 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1870 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1874 info = sc->info_video;
1876 f = fopen64(info->filename, "rb+");
1878 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1879 _mmcam_dbg_err("file open failed [%s]", err_msg);
1883 mm_camcorder_get_attributes(handle, &err_name,
1884 MMCAM_TAG_LATITUDE, &latitude,
1885 MMCAM_TAG_LONGITUDE, &longitude,
1886 MMCAM_TAG_ALTITUDE, &altitude,
1887 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1888 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1891 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1892 SAFE_FREE (err_name);
1895 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1896 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1897 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1898 geo_info.longitude = longitude *10000;
1899 geo_info.latitude = latitude *10000;
1900 geo_info.altitude = altitude *10000;
1901 /* find udta container.
1902 if, there are udta container, write loci box after that
1903 else, make udta container and write loci box. */
1904 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) {
1907 _mmcam_dbg_log("find udta container");
1910 if (fseek(f, -8L, SEEK_CUR) != 0) {
1914 udta_pos = ftello(f);
1919 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1921 _mmcam_dbg_log("recorded file fread %d", nread);
1923 udta_size = _mmcamcorder_get_container_size(buf);
1925 /* goto end of udta and write 'loci' box */
1926 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) {
1931 if (!_mmcamcorder_write_loci(f, location_info)) {
1932 _mmcam_dbg_err("failed to write loci");
1936 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1937 _mmcam_dbg_err("failed to write geodata");
1942 current_pos = ftello(f);
1943 if (current_pos < 0) {
1947 if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) {
1951 _mmcam_dbg_log("No udta container");
1952 if (fseek(f, 0, SEEK_END) != 0) {
1956 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1957 _mmcam_dbg_err("failed to write udta");
1962 /* find moov container.
1963 update moov container size. */
1964 if((current_pos = ftello(f))<0)
1967 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) {
1968 gint64 internal_pos = ftello(f);
1970 _mmcam_dbg_log("found moov container");
1971 if (fseek(f, -8L, SEEK_CUR) !=0) {
1975 moov_pos = ftello(f);
1980 if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) {
1984 /* add orientation info */
1985 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1986 _mmcam_dbg_err("fseek failed : errno %d", errno);
1990 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','r','a','k'), FALSE)) {
1991 _mmcam_dbg_err("failed to find [trak] tag");
1995 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','k','h','d'), FALSE)) {
1996 _mmcam_dbg_err("failed to find [tkhd] tag");
2000 _mmcam_dbg_log("found [tkhd] tag");
2002 /* seek to start position of composition matrix */
2003 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
2005 /* update composition matrix for orientation */
2006 _mmcamcorder_update_composition_matrix(f, orientation);
2008 _mmcam_dbg_err("No 'moov' container");
2020 _mmcam_dbg_err("ftell() returns negative value.");
2026 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2028 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2029 _MMCamcorderSubContext *sc = NULL;
2031 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2033 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2034 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2036 /* check video source element */
2037 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2038 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2039 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2040 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2041 G_CALLBACK(__mmcamcorder_video_stream_cb),
2043 return MM_ERROR_NONE;
2045 _mmcam_dbg_err("videosrc element is not created yet");
2046 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2051 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2053 int ret = MM_ERROR_NONE;
2055 _MMCamcorderVideoInfo *info = NULL;
2056 _MMCamcorderSubContext *sc = NULL;
2057 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2059 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2061 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2062 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2063 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2065 info = sc->info_video;
2067 _mmcam_dbg_warn("start");
2069 /* create encoding pipeline */
2070 ret =_mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2071 if (ret != MM_ERROR_NONE) {
2072 goto _ERR_PREPARE_RECORD;
2075 if (info->filename == NULL) {
2076 char *temp_filename = NULL;
2079 mm_camcorder_get_attributes(handle, NULL,
2080 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2082 if (temp_filename) {
2083 info->filename = g_strdup(temp_filename);
2086 if (!info->filename) {
2087 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2088 goto _ERR_PREPARE_RECORD;
2092 _mmcam_dbg_log("Record file name [%s]", info->filename);
2094 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2095 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2097 /* Adjust display FPS */
2098 sc->display_interval = 0;
2099 sc->previous_slot_time = 0;
2101 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2102 if (ret != MM_ERROR_NONE) {
2103 goto _ERR_PREPARE_RECORD;
2106 _mmcam_dbg_warn("done");
2110 _ERR_PREPARE_RECORD:
2111 /* Remove recorder pipeline and recording file which size maybe zero */
2112 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2113 if (info && info->filename) {
2114 _mmcam_dbg_log("file delete(%s)", info->filename);
2115 unlink(info->filename);