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;
108 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
110 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
111 if (ret != GST_FLOW_OK && 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)
159 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
160 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
161 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
162 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
165 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
167 /* get audio disable */
168 mm_camcorder_get_attributes(handle, NULL,
169 MMCAM_AUDIO_DISABLE, &audio_disable,
172 if (sc->is_modified_rate || audio_disable)
173 sc->audio_disable = TRUE;
175 sc->audio_disable = FALSE;
177 _mmcam_dbg_log("AUDIO DISABLE : %d (is_modified_rate %d, audio_disable %d)",
178 sc->audio_disable, sc->is_modified_rate, audio_disable);
180 if (sc->audio_disable == FALSE) {
181 /* create audiosrc bin */
182 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
183 if (err != MM_ERROR_NONE)
187 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
188 if (err != MM_ERROR_NONE)
191 if (sc->audio_disable == FALSE) {
192 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
193 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
196 /* add element and encodesink bin to encode main pipeline */
197 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
198 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
199 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
200 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
203 /* Link each element : appsrc - capsfilter - encodesink bin */
204 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
205 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
206 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
208 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
209 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
210 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
212 if (sc->audio_disable == FALSE) {
213 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
214 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
215 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
218 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
219 CONFIGURE_CATEGORY_MAIN_RECORD,
222 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
224 /* set data probe function */
226 /* register message cb */
228 /* set data probe function for audio */
230 if (sc->audio_disable == FALSE) {
231 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
232 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
233 __mmcamcorder_audioque_dataprobe, hcamcorder);
234 gst_object_unref(sinkpad);
238 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
239 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
240 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
241 gst_object_unref(srcpad);
244 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
245 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
246 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
247 __mmcamcorder_eventprobe_monitor, hcamcorder);
248 gst_object_unref(srcpad);
253 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
254 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
255 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
256 __mmcamcorder_eventprobe_monitor, hcamcorder);
257 gst_object_unref(srcpad);
261 if (sc->audio_disable) {
262 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
263 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
264 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
265 gst_object_unref(sinkpad);
269 if (!strcmp(gst_element_rsink_name, "filesink")) {
270 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
271 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
272 __mmcamcorder_video_dataprobe_record, hcamcorder);
273 gst_object_unref(srcpad);
276 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
277 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
278 __mmcamcorder_audio_dataprobe_check, hcamcorder);
279 gst_object_unref(srcpad);
283 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
285 /* register pipeline message callback */
286 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
288 /* set sync handler */
289 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
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,
388 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
390 _mmcam_dbg_log("Encoder pipeline removed");
393 return MM_ERROR_NONE;
397 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
399 int ret = MM_ERROR_NONE;
400 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
401 _MMCamcorderSubContext *sc = NULL;
405 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
406 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
407 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
409 _mmcam_dbg_log("start");
411 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
412 _mmcam_dbg_warn("pipeline is not existed.");
413 return MM_ERROR_NONE;
416 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
418 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
419 if (ret != MM_ERROR_NONE) {
420 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
424 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
426 /* remove audio pipeline first */
427 ret = _mmcamcorder_remove_audio_pipeline(handle);
428 if (ret != MM_ERROR_NONE) {
429 _mmcam_dbg_err("Fail to remove audio pipeline");
433 ret = _mmcamcorder_remove_encode_pipeline(handle);
434 if (ret != MM_ERROR_NONE) {
435 _mmcam_dbg_err("Fail to remove encoder pipeline");
439 /* Remove pipeline message callback */
440 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
441 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
442 hcamcorder->encode_pipeline_cb_event_id = 0;
445 /* Remove remained message */
447 GstMessage *gst_msg = NULL;
448 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
449 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
450 gst_message_unref(gst_msg);
453 gst_object_unref(bus);
457 _mmcam_dbg_log("done");
463 int _mmcamcorder_video_command(MMHandleType handle, int command)
468 int ret = MM_ERROR_NONE;
469 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
470 char *err_name = NULL;
471 char *temp_filename = NULL;
472 GstCameraControl *CameraControl = NULL;
473 GstCameraControlChannel *CameraControlChannel = NULL;
474 const GList *controls = NULL;
475 const GList *item = NULL;
478 GstElement *pipeline = NULL;
480 _MMCamcorderVideoInfo *info = NULL;
481 _MMCamcorderSubContext *sc = NULL;
482 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
484 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
486 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
487 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
488 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
489 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
491 info = sc->info_video;
493 _mmcam_dbg_log("Command(%d)", command);
495 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
498 case _MMCamcorder_CMD_RECORD:
500 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
506 int ret_free_space = 0;
507 char *dir_name = NULL;
508 guint64 free_space = 0;
509 int file_system_type = 0;
510 int root_directory_length = 0;
513 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
515 /* init record_dual_stream */
516 info->record_dual_stream = FALSE;
518 ret = mm_camcorder_get_attributes(handle, &err_name,
519 MMCAM_CAMERA_FPS, &fps,
520 MMCAM_CAMERA_WIDTH, &(info->preview_width),
521 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
522 MMCAM_VIDEO_WIDTH, &(info->video_width),
523 MMCAM_VIDEO_HEIGHT, &(info->video_height),
524 MMCAM_FILE_FORMAT, &fileformat,
525 MMCAM_TARGET_FILENAME, &temp_filename, &size,
526 MMCAM_TARGET_MAX_SIZE, &imax_size,
527 MMCAM_TARGET_TIME_LIMIT, &imax_time,
528 MMCAM_FILE_FORMAT, &(info->fileformat),
529 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
530 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
532 if (ret != MM_ERROR_NONE) {
533 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
535 goto _ERR_CAMCORDER_VIDEO_COMMAND;
538 if (temp_filename == NULL) {
539 _mmcam_dbg_err("filename is not set");
540 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
541 goto _ERR_CAMCORDER_VIDEO_COMMAND;
546 info->max_size = 0; /* do not check */
548 info->max_size = ((guint64)imax_size) << 10; /* to byte */
552 info->max_time = 0; /* do not check */
554 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
556 dir_name = g_path_get_dirname(temp_filename);
558 ret = _mmcamcorder_get_storage_info(dir_name, hcamcorder->root_directory, &hcamcorder->storage_info);
560 _mmcam_dbg_err("get storage info failed");
563 return MM_ERROR_OUT_OF_STORAGE;
566 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
568 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
570 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
571 /* MSDOS_SUPER_MAGIC : 0x4d44 */
572 if (file_system_type == MSDOS_SUPER_MAGIC &&
573 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
574 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
575 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
576 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
578 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
579 file_system_type, info->max_size);
582 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
588 _mmcam_dbg_err("failed to get directory name");
592 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
593 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
594 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
595 return MM_ERROR_OUT_OF_STORAGE;
598 g_mutex_lock(&hcamcorder->task_thread_lock);
599 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
600 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
601 /* Play record start sound */
602 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
604 g_mutex_unlock(&hcamcorder->task_thread_lock);
606 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
608 if (info->video_width == 0 || info->video_height == 0) {
609 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
610 info->video_width, info->video_height, info->preview_width, info->preview_height);
611 info->video_width = info->preview_width;
612 info->video_height = info->preview_height;
615 if (info->support_dual_stream) {
616 _mmcam_dbg_warn("DUAL STREAM MODE");
618 info->record_dual_stream = TRUE;
620 /* No need to restart preview */
621 info->restart_preview = FALSE;
623 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
624 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
625 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
626 info->preview_width == info->video_width &&
627 info->preview_height == info->video_height) {
628 _mmcam_dbg_log("H264 preview mode and same resolution");
630 /* No need to restart preview */
631 info->restart_preview = FALSE;
633 /* always need to restart preview */
634 info->restart_preview = TRUE;
637 /* set recording hint */
638 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
640 if (info->restart_preview) {
641 /* stop preview and set new size */
642 _mmcam_dbg_log("restart preview");
644 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
645 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
646 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
648 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
650 /* check decoder recreation */
651 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
652 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
653 ret = MM_ERROR_CAMCORDER_INTERNAL;
654 goto _ERR_CAMCORDER_VIDEO_COMMAND;
657 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
658 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
659 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
661 if (ret != MM_ERROR_NONE)
662 goto _ERR_CAMCORDER_VIDEO_COMMAND;
664 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
665 ret = MM_ERROR_CAMCORDER_INTERNAL;
666 goto _ERR_CAMCORDER_VIDEO_COMMAND;
669 /* Start preview again with new setting */
670 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
671 if (ret != MM_ERROR_NONE)
672 goto _ERR_CAMCORDER_VIDEO_COMMAND;
674 if (motion_rate < 1.0) {
675 _mmcam_dbg_warn("wait for stabilization of frame");
679 _mmcam_dbg_log("no need to restart preview");
682 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
683 CONFIGURE_CATEGORY_MAIN_RECORD,
687 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
688 CONFIGURE_CATEGORY_MAIN_RECORD,
689 "PassFirstVideoFrame",
690 &(sc->pass_first_vframe));
692 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
693 sc->drop_vframe, sc->pass_first_vframe);
695 info->record_drop_count = (guint)motion_rate;
696 info->record_motion_rate = motion_rate;
697 if (sc->is_modified_rate)
698 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
700 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
702 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
703 fps, info->record_motion_rate, info->record_timestamp_ratio);
705 /* set push buffer flag */
706 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
707 info->base_video_ts = 0;
709 /* connect video stream cb signal */
710 /*130826 Connect video stream cb for handling fast record frame cb*/
711 if (info->record_dual_stream) {
712 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
713 goto _ERR_CAMCORDER_VIDEO_COMMAND;
716 /* start video stream */
717 if (info->record_dual_stream) {
718 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
720 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
722 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
723 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
725 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
727 _mmcam_dbg_err("could not get camera control");
731 /* check pre-created encode pipeline */
732 g_mutex_lock(&hcamcorder->task_thread_lock);
733 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
734 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
735 /* create encoding pipeline */
736 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
737 if (ret != MM_ERROR_NONE) {
738 g_mutex_unlock(&hcamcorder->task_thread_lock);
739 goto _ERR_CAMCORDER_VIDEO_COMMAND;
742 g_mutex_unlock(&hcamcorder->task_thread_lock);
744 /* check recording start sound */
745 _mmcamcorder_sound_solo_play_wait(handle);
747 /**< To fix video recording hanging
748 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
749 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
750 basetime wouldn't change if you set (GstClockTime)0.
751 3. Move set start time position below PAUSED of pipeline.
754 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
755 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
758 info->video_frame_count = 0;
759 info->is_firstframe = TRUE;
760 info->audio_frame_count = 0;
762 sc->ferror_send = FALSE;
763 sc->ferror_count = 0;
764 hcamcorder->error_occurs = FALSE;
765 sc->bget_eos = FALSE;
767 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
768 if (ret != MM_ERROR_NONE) {
769 /* stop video stream */
770 if (info->record_dual_stream) {
771 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
773 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
775 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
776 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
778 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
780 _mmcam_dbg_err("failed to get camera control");
784 /* Remove recorder pipeline and recording file which size maybe zero */
785 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
786 if (info->filename) {
787 _mmcam_dbg_log("file delete(%s)", info->filename);
788 unlink(info->filename);
790 goto _ERR_CAMCORDER_VIDEO_COMMAND;
793 /*set the camera control to create the GOP so that video record will get a new key frame*/
794 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
795 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
796 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
797 controls = gst_camera_control_list_channels(CameraControl);
798 if (controls != NULL) {
799 for (item = controls ; item && item->data ; item = item->next) {
800 CameraControlChannel = item->data;
801 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
802 if (!strcmp(CameraControlChannel->label, "new-gop")) {
803 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
809 _mmcam_dbg_warn("failed to find new-gop control channel");
812 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
813 sc->info_image->preview_format);
818 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
819 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
820 /* generate and I-frame on resuming */
821 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
822 controls = gst_camera_control_list_channels(CameraControl);
823 if (controls != NULL) {
824 for (item = controls ; item && item->data ; item = item->next) {
825 CameraControlChannel = item->data;
826 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
827 if (!strcmp(CameraControlChannel->label, "new-gop")) {
828 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
834 _mmcam_dbg_warn("failed to find new-gop control channel");
838 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
840 _mmcam_dbg_log("Object property settings done");
844 case _MMCamcorder_CMD_PAUSE:
846 if (info->b_commiting) {
847 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
848 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
851 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
852 if (sc->audio_disable) {
853 /* check only video frame */
854 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
856 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
857 _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
858 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
860 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", 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;
914 /* set recording hint */
915 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
917 /* stop video stream */
918 if (info->record_dual_stream) {
919 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
921 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
923 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
924 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
926 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
928 _mmcam_dbg_err("failed to get camera control");
932 if (info->restart_preview) {
933 /* restart preview */
934 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
935 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
936 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", 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);
948 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
950 if (ret != MM_ERROR_NONE)
951 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;
966 /* remove target file */
967 if (info->filename) {
968 _mmcam_dbg_log("file delete(%s)", info->filename);
969 unlink(info->filename);
972 sc->isMaxsizePausing = FALSE;
973 sc->isMaxtimePausing = FALSE;
975 sc->display_interval = 0;
976 sc->previous_slot_time = 0;
977 info->video_frame_count = 0;
978 info->audio_frame_count = 0;
980 hcamcorder->capture_in_recording = FALSE;
983 case _MMCamcorder_CMD_COMMIT:
985 if (info->b_commiting) {
986 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
987 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
989 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
990 info->b_commiting = TRUE;
991 sc->bget_eos = FALSE;
994 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
995 if (sc->audio_disable) {
996 /* check only video frame */
997 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
998 hcamcorder->capture_in_recording == FALSE) {
1000 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1001 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1002 info->video_frame_count, hcamcorder->capture_in_recording);
1004 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1005 _mmcam_dbg_warn("video frames are enough. keep going...");
1007 info->b_commiting = FALSE;
1008 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1011 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1012 count, info->video_frame_count, hcamcorder->capture_in_recording);
1015 /* check both of video and audio frame */
1016 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1017 info->audio_frame_count &&
1018 hcamcorder->capture_in_recording == FALSE) {
1020 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1021 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1022 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1024 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1025 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1027 info->b_commiting = FALSE;
1028 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1031 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1033 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1034 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1038 if (hcamcorder->capture_in_recording) {
1039 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1040 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1041 _mmcam_dbg_warn("signal received");
1043 _mmcam_dbg_warn("timeout");
1046 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1050 /* block push buffer */
1051 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1052 _mmcam_dbg_log("block push buffer to appsrc");
1054 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1055 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1056 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1058 _mmcam_dbg_err("VIDEO: send EOS failed");
1059 info->b_commiting = FALSE;
1060 ret = MM_ERROR_CAMCORDER_INTERNAL;
1061 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1064 _mmcam_dbg_err("No video stream source");
1065 info->b_commiting = FALSE;
1066 ret = MM_ERROR_CAMCORDER_INTERNAL;
1067 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1070 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1071 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1072 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1074 _mmcam_dbg_err("AUDIO: send EOS failed");
1075 info->b_commiting = FALSE;
1076 ret = MM_ERROR_CAMCORDER_INTERNAL;
1077 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1080 _mmcam_dbg_log("No audio stream");
1084 sc->display_interval = 0;
1085 sc->previous_slot_time = 0;
1088 _mmcam_dbg_log("Start to wait EOS");
1089 ret = _mmcamcorder_get_eos_message(handle);
1090 if (ret != MM_ERROR_NONE) {
1091 info->b_commiting = FALSE;
1092 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1096 hcamcorder->capture_in_recording = FALSE;
1100 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1101 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1104 return MM_ERROR_NONE;
1106 _ERR_CAMCORDER_VIDEO_COMMAND:
1107 if (command == _MMCamcorder_CMD_RECORD)
1108 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1114 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1116 int ret = MM_ERROR_NONE;
1118 guint64 file_size = 0;
1120 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1121 _MMCamcorderSubContext *sc = NULL;
1122 _MMCamcorderVideoInfo *info = NULL;
1123 _MMCamcorderMsgItem msg;
1124 MMCamRecordingReport *report = NULL;
1126 mmf_return_val_if_fail(hcamcorder, FALSE);
1128 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1129 mmf_return_val_if_fail(sc, FALSE);
1130 mmf_return_val_if_fail(sc->info_video, FALSE);
1132 info = sc->info_video;
1136 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1137 /* Play record stop sound */
1138 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1140 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1142 _mmcamcorder_sound_init(handle);
1144 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1146 _mmcamcorder_sound_finalize(handle);
1149 /* remove blocking part */
1150 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1152 mm_camcorder_get_attributes(handle, NULL,
1153 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1156 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1157 if (ret != MM_ERROR_NONE)
1158 _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);
1206 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1208 _mmcam_dbg_log("Set state of pipeline as READY");
1209 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1211 /* check decoder recreation */
1212 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1213 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1214 ret = MM_ERROR_CAMCORDER_INTERNAL;
1218 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1219 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1220 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", 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_FOCUS) {
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)
1297 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1298 switch (GST_EVENT_TYPE(event)) {
1299 case GST_EVENT_UNKNOWN:
1300 /* upstream events */
1302 case GST_EVENT_SEEK:
1303 case GST_EVENT_NAVIGATION:
1304 case GST_EVENT_LATENCY:
1305 /* downstream serialized events */
1306 case GST_EVENT_SEGMENT:
1308 case GST_EVENT_BUFFERSIZE:
1309 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1312 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1314 /* bidirectional events */
1315 case GST_EVENT_FLUSH_START:
1316 case GST_EVENT_FLUSH_STOP:
1317 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1320 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1324 return GST_PAD_PROBE_OK;
1328 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1330 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1331 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1333 _MMCamcorderSubContext *sc = NULL;
1334 _MMCamcorderVideoInfo *videoinfo = NULL;
1335 _MMCamcorderMsgItem msg;
1336 guint64 buffer_size = 0;
1337 guint64 trailer_size = 0;
1338 guint64 max_size = 0;
1340 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1341 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1342 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1344 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1345 videoinfo = sc->info_video;
1347 /* get buffer size */
1348 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1349 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1350 return GST_PAD_PROBE_OK;
1353 buffer_size = mapinfo.size;
1354 gst_buffer_unmap(buffer, &mapinfo);
1356 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1358 g_mutex_lock(&videoinfo->size_check_lock);
1360 if (videoinfo->audio_frame_count == 0) {
1361 videoinfo->filesize += buffer_size;
1362 videoinfo->audio_frame_count++;
1363 g_mutex_unlock(&videoinfo->size_check_lock);
1364 return GST_PAD_PROBE_OK;
1367 if (sc->ferror_send || sc->isMaxsizePausing) {
1368 _mmcam_dbg_warn("Recording is paused, drop frames");
1369 g_mutex_unlock(&videoinfo->size_check_lock);
1370 return GST_PAD_PROBE_DROP;
1373 /* get trailer size */
1374 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1375 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1380 /* check max size of recorded file */
1381 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1382 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1383 GstState pipeline_state = GST_STATE_VOID_PENDING;
1384 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1385 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1386 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1387 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1388 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1390 if (!sc->isMaxsizePausing) {
1391 sc->isMaxsizePausing = TRUE;
1392 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1393 if (pipeline_state == GST_STATE_PLAYING)
1394 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1396 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1397 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1400 g_mutex_unlock(&videoinfo->size_check_lock);
1405 videoinfo->filesize += buffer_size;
1406 videoinfo->audio_frame_count++;
1408 g_mutex_unlock(&videoinfo->size_check_lock);
1410 return GST_PAD_PROBE_OK;
1414 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1419 guint64 free_space = 0;
1420 guint64 buffer_size = 0;
1421 guint64 trailer_size = 0;
1422 guint64 queued_buffer = 0;
1423 guint64 max_size = 0;
1424 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1426 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1428 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1429 _MMCamcorderMsgItem msg;
1430 _MMCamcorderSubContext *sc = NULL;
1431 _MMCamcorderVideoInfo *videoinfo = NULL;
1433 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1434 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1436 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1437 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1438 videoinfo = sc->info_video;
1440 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1441 if (sc->ferror_send) {
1442 _mmcam_dbg_warn("file write error, drop frames");
1443 return GST_PAD_PROBE_DROP;
1446 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1447 buffer_size = mapinfo.size;
1448 gst_buffer_unmap(buffer, &mapinfo);
1450 videoinfo->video_frame_count++;
1451 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1452 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1453 info->video_frame_count); */
1454 g_mutex_lock(&videoinfo->size_check_lock);
1455 videoinfo->filesize += buffer_size;
1456 g_mutex_unlock(&videoinfo->size_check_lock);
1457 return GST_PAD_PROBE_OK;
1460 /* get trailer size */
1461 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1462 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1467 /* check free space */
1468 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1470 _mmcam_dbg_err("Error occured. [%d]", ret);
1471 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1472 sc->ferror_send = TRUE;
1474 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1475 msg.param.code = MM_ERROR_FILE_READ;
1477 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1482 return GST_PAD_PROBE_DROP; /* skip this buffer */
1485 if (free_space == 0) {
1486 /* check storage state */
1487 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1489 _mmcam_dbg_warn("storage state %d", storage_state);
1491 if (storage_state == STORAGE_STATE_REMOVED ||
1492 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1493 _mmcam_dbg_err("storage was removed!");
1495 _MMCAMCORDER_LOCK(hcamcorder);
1497 if (sc->ferror_send == FALSE) {
1498 _mmcam_dbg_err("OUT_OF_STORAGE error");
1500 sc->ferror_send = TRUE;
1502 _MMCAMCORDER_UNLOCK(hcamcorder);
1504 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1505 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1507 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1509 _MMCAMCORDER_UNLOCK(hcamcorder);
1510 _mmcam_dbg_warn("error was already sent");
1513 return GST_PAD_PROBE_DROP;
1517 /* get queued buffer size */
1518 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1519 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1522 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1523 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1526 queued_buffer = aq_size + vq_size;
1528 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1529 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1530 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1531 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1532 free_space, trailer_size, buffer_size, queued_buffer);
1534 if (!sc->isMaxsizePausing) {
1535 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1536 sc->isMaxsizePausing = TRUE;
1538 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1539 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1542 return GST_PAD_PROBE_DROP;
1545 g_mutex_lock(&videoinfo->size_check_lock);
1547 /* check max size of recorded file */
1548 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1549 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1550 GstState pipeline_state = GST_STATE_VOID_PENDING;
1551 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1552 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1553 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1554 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1555 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1557 if (!sc->isMaxsizePausing) {
1558 sc->isMaxsizePausing = TRUE;
1559 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1560 if (pipeline_state == GST_STATE_PLAYING)
1561 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1563 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1564 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1567 g_mutex_unlock(&videoinfo->size_check_lock);
1569 return GST_PAD_PROBE_DROP;
1572 videoinfo->filesize += (guint64)buffer_size;
1575 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1578 g_mutex_unlock(&videoinfo->size_check_lock);
1580 return GST_PAD_PROBE_OK;
1584 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1586 guint64 trailer_size = 0;
1587 guint64 rec_pipe_time = 0;
1588 unsigned int remained_time = 0;
1590 GstClockTime b_time;
1592 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1593 _MMCamcorderMsgItem msg;
1594 _MMCamcorderSubContext *sc = NULL;
1595 _MMCamcorderVideoInfo *videoinfo = NULL;
1597 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1599 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1600 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1602 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1603 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1604 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1606 videoinfo = sc->info_video;
1608 b_time = GST_BUFFER_PTS(buffer);
1610 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1612 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1613 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1618 /* check max time */
1619 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1620 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1621 rec_pipe_time, videoinfo->max_time);
1623 if (!sc->isMaxtimePausing) {
1624 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1626 sc->isMaxtimePausing = TRUE;
1628 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1629 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1630 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1631 msg.param.recording_status.remained_time = 0;
1632 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1634 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1635 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1638 return GST_PAD_PROBE_DROP;
1641 /* calculate remained time can be recorded */
1642 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1643 remained_time = videoinfo->max_time - rec_pipe_time;
1644 } else if (videoinfo->max_size > 0) {
1645 long double max_size = (long double)videoinfo->max_size;
1646 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1648 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1651 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1652 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1653 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1654 msg.param.recording_status.remained_time = remained_time;
1655 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1658 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1659 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1662 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1663 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1666 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1667 record_motion_rate, videoinfo->record_drop_count);
1670 /* drop some frame if fast motion */
1671 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1672 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1674 _mmcam_dbg_warn("drop frame");
1676 return GST_PAD_PROBE_DROP;
1679 videoinfo->record_drop_count = 1;
1681 _mmcam_dbg_warn("pass frame");
1685 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1686 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1689 return GST_PAD_PROBE_OK;
1693 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1695 _MMCamcorderMsgItem msg;
1696 guint64 trailer_size = 0;
1697 guint64 rec_pipe_time = 0;
1698 _MMCamcorderSubContext *sc = NULL;
1699 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1700 _MMCamcorderVideoInfo *videoinfo = NULL;
1701 unsigned int remained_time = 0;
1702 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1704 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1705 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1706 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1708 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1709 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1710 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1712 videoinfo = sc->info_video;
1714 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1715 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1716 return GST_PAD_PROBE_OK;
1719 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1721 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1722 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1727 /* calculate remained time can be recorded */
1728 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1729 remained_time = videoinfo->max_time - rec_pipe_time;
1730 } else if (videoinfo->max_size > 0) {
1731 long double max_size = (long double)videoinfo->max_size;
1732 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1734 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1737 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1738 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1739 rec_pipe_time, videoinfo->max_time);
1741 if (!sc->isMaxtimePausing) {
1742 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1744 sc->isMaxtimePausing = TRUE;
1746 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1747 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1748 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1749 msg.param.recording_status.remained_time = 0;
1750 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1752 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1753 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1756 return GST_PAD_PROBE_DROP;
1759 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1760 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1761 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1762 msg.param.recording_status.remained_time = remained_time;
1763 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1766 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1767 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1770 return GST_PAD_PROBE_OK;
1774 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1776 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1777 double volume = 0.0;
1780 int err = MM_ERROR_UNKNOWN;
1781 char *err_name = NULL;
1782 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1785 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1786 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1788 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1789 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1790 MMCAM_AUDIO_VOLUME, &volume,
1791 MMCAM_AUDIO_FORMAT, &format,
1792 MMCAM_AUDIO_CHANNEL, &channel,
1794 if (err != MM_ERROR_NONE) {
1795 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1796 SAFE_FREE(err_name);
1800 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1802 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1804 /* Set audio stream NULL */
1806 memset(mapinfo.data, 0, mapinfo.size);
1808 /* CALL audio stream callback */
1809 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1810 MMCamcorderAudioStreamDataType stream;
1812 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1813 _mmcam_dbg_warn("Not ready for stream callback");
1814 gst_buffer_unmap(buffer, &mapinfo);
1815 return GST_PAD_PROBE_OK;
1818 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1819 GST_BUFFER_DATA(buffer), width, height, format);*/
1821 stream.data = (void *)mapinfo.data;
1822 stream.format = format;
1823 stream.channel = channel;
1824 stream.length = mapinfo.size;
1825 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1827 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1829 if (hcamcorder->astream_cb)
1830 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1832 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1835 gst_buffer_unmap(buffer, &mapinfo);
1836 return GST_PAD_PROBE_OK;
1840 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1842 gboolean bret = FALSE;
1844 switch (fileformat) {
1845 case MM_FILE_FORMAT_3GP:
1846 case MM_FILE_FORMAT_MP4:
1847 bret = __mmcamcorder_add_metadata_mp4(handle);
1850 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1858 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1862 guint64 udta_size = 0;
1863 gint64 current_pos = 0;
1864 gint64 moov_pos = 0;
1865 gint64 udta_pos = 0;
1866 gdouble longitude = 0;
1867 gdouble latitude = 0;
1868 gdouble altitude = 0;
1870 int orientation = 0;
1872 char *err_name = NULL;
1873 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1874 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1875 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1877 _MMCamcorderVideoInfo *info = NULL;
1878 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1879 _MMCamcorderSubContext *sc = NULL;
1881 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1882 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1884 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1885 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1889 info = sc->info_video;
1891 f = fopen64(info->filename, "rb+");
1893 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1894 _mmcam_dbg_err("file open failed [%s]", err_msg);
1898 mm_camcorder_get_attributes(handle, &err_name,
1899 MMCAM_TAG_LATITUDE, &latitude,
1900 MMCAM_TAG_LONGITUDE, &longitude,
1901 MMCAM_TAG_ALTITUDE, &altitude,
1902 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1903 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1906 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1907 SAFE_FREE(err_name);
1910 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1911 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1912 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1913 geo_info.longitude = longitude *10000;
1914 geo_info.latitude = latitude *10000;
1915 geo_info.altitude = altitude *10000;
1916 /* find udta container.
1917 if, there are udta container, write loci box after that
1918 else, make udta container and write loci box. */
1919 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1922 _mmcam_dbg_log("find udta container");
1925 if (fseek(f, -8L, SEEK_CUR) != 0)
1928 udta_pos = ftello(f);
1932 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1934 _mmcam_dbg_log("recorded file fread %d", nread);
1936 udta_size = _mmcamcorder_get_container_size(buf);
1938 /* goto end of udta and write 'loci' box */
1939 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1943 if (!_mmcamcorder_write_loci(f, location_info)) {
1944 _mmcam_dbg_err("failed to write loci");
1948 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1949 _mmcam_dbg_err("failed to write geodata");
1954 current_pos = ftello(f);
1955 if (current_pos < 0)
1958 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1961 _mmcam_dbg_log("No udta container");
1962 if (fseek(f, 0, SEEK_END) != 0)
1965 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1966 _mmcam_dbg_err("failed to write udta");
1971 /* find moov container.
1972 update moov container size. */
1973 if ((current_pos = ftello(f)) < 0)
1976 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1977 gint64 internal_pos = ftello(f);
1979 _mmcam_dbg_log("found moov container");
1980 if (fseek(f, -8L, SEEK_CUR) != 0)
1983 moov_pos = ftello(f);
1987 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
1990 /* add orientation info */
1991 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1992 _mmcam_dbg_err("fseek failed : errno %d", errno);
1996 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
1997 _mmcam_dbg_err("failed to find [trak] tag");
2001 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2002 _mmcam_dbg_err("failed to find [tkhd] tag");
2006 _mmcam_dbg_log("found [tkhd] tag");
2008 /* seek to start position of composition matrix */
2009 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
2011 /* update composition matrix for orientation */
2012 _mmcamcorder_update_composition_matrix(f, orientation);
2014 _mmcam_dbg_err("No 'moov' container");
2026 _mmcam_dbg_err("ftell() returns negative value.");
2032 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2034 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2035 _MMCamcorderSubContext *sc = NULL;
2037 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2039 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2040 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2042 /* check video source element */
2043 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2044 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2045 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2046 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2047 G_CALLBACK(__mmcamcorder_video_stream_cb),
2049 return MM_ERROR_NONE;
2051 _mmcam_dbg_err("videosrc element is not created yet");
2052 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2057 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2059 int ret = MM_ERROR_NONE;
2061 _MMCamcorderVideoInfo *info = NULL;
2062 _MMCamcorderSubContext *sc = NULL;
2063 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2065 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2067 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2068 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2069 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2071 info = sc->info_video;
2073 _mmcam_dbg_warn("start");
2075 /* create encoding pipeline */
2076 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2077 if (ret != MM_ERROR_NONE)
2078 goto _ERR_PREPARE_RECORD;
2080 if (info->filename == NULL) {
2081 char *temp_filename = NULL;
2084 mm_camcorder_get_attributes(handle, NULL,
2085 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2088 info->filename = g_strdup(temp_filename);
2090 if (!info->filename) {
2091 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2092 goto _ERR_PREPARE_RECORD;
2096 _mmcam_dbg_log("Record file name [%s]", info->filename);
2098 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2099 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2101 /* Adjust display FPS */
2102 sc->display_interval = 0;
2103 sc->previous_slot_time = 0;
2105 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2106 if (ret != MM_ERROR_NONE)
2107 goto _ERR_PREPARE_RECORD;
2109 _mmcam_dbg_warn("done");
2113 _ERR_PREPARE_RECORD:
2114 /* Remove recorder pipeline and recording file which size maybe zero */
2115 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2116 if (info && info->filename) {
2117 _mmcam_dbg_log("file delete(%s)", info->filename);
2118 unlink(info->filename);