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 && ret != GST_FLOW_FLUSHING) {
111 _mmcam_dbg_err("gst_app_src_push_buffer failed [0x%x]", ret);
112 gst_buffer_unref(buffer);
116 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
118 _mmcam_dbg_warn("unref video buffer immediately - push encoding buffer %d",
119 sc->info_video->push_encoding_buffer);
121 gst_buffer_unref(buffer);
129 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
132 int err = MM_ERROR_NONE;
133 int audio_disable = FALSE;
134 const char* gst_element_rsink_name = NULL;
137 GstPad *srcpad = NULL;
138 GstPad *sinkpad = NULL;
140 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
141 _MMCamcorderSubContext *sc = NULL;
143 type_element *RecordsinkElement = NULL;
145 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
147 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
148 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
149 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
151 _mmcam_dbg_warn("start");
153 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
154 if (err != MM_ERROR_NONE)
158 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
159 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
160 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
161 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
164 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
166 /* get audio disable */
167 mm_camcorder_get_attributes(handle, NULL,
168 MMCAM_AUDIO_DISABLE, &audio_disable,
171 if (sc->is_modified_rate || audio_disable)
172 sc->audio_disable = TRUE;
174 sc->audio_disable = FALSE;
176 _mmcam_dbg_log("AUDIO DISABLE : %d (is_modified_rate %d, audio_disable %d)",
177 sc->audio_disable, sc->is_modified_rate, audio_disable);
179 if (sc->audio_disable == FALSE) {
180 /* create audiosrc bin */
181 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
182 if (err != MM_ERROR_NONE)
186 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
187 if (err != MM_ERROR_NONE)
190 if (sc->audio_disable == FALSE) {
191 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
192 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
195 /* add element and encodesink bin to encode main pipeline */
196 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
197 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
198 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
199 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
202 /* Link each element : appsrc - capsfilter - encodesink bin */
203 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
204 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
205 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
207 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
208 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
209 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
211 if (sc->audio_disable == FALSE) {
212 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
213 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
214 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
217 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
218 CONFIGURE_CATEGORY_MAIN_RECORD,
221 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
223 /* set data probe function */
225 /* register message cb */
227 /* set data probe function for audio */
229 if (sc->audio_disable == FALSE) {
230 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
231 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
232 __mmcamcorder_audioque_dataprobe, hcamcorder);
233 gst_object_unref(sinkpad);
237 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
238 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
239 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
240 gst_object_unref(srcpad);
243 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
244 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
245 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
246 __mmcamcorder_eventprobe_monitor, hcamcorder);
247 gst_object_unref(srcpad);
252 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
253 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
254 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
255 __mmcamcorder_eventprobe_monitor, hcamcorder);
256 gst_object_unref(srcpad);
260 if (sc->audio_disable) {
261 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
262 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
263 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
264 gst_object_unref(sinkpad);
268 if (!strcmp(gst_element_rsink_name, "filesink")) {
269 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
270 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
271 __mmcamcorder_video_dataprobe_record, hcamcorder);
272 gst_object_unref(srcpad);
275 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
276 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
277 __mmcamcorder_audio_dataprobe_check, hcamcorder);
278 gst_object_unref(srcpad);
282 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
284 /* register pipeline message callback */
285 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
287 /* set sync handler */
288 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
290 gst_object_unref(bus);
293 return MM_ERROR_NONE;
295 pipeline_creation_error:
296 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
297 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
299 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
304 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
306 GstPad *srcpad = NULL;
307 GstPad *sinkpad = NULL;
308 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
309 _MMCamcorderSubContext *sc = NULL;
311 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
313 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
314 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
315 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
319 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
320 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
321 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
322 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
324 /* release audiosrc bin */
325 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
326 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
329 To avoid conflicting between old elements and newly created elements,
330 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
331 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
332 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
333 It's because the pipeline of audio recording destroys at the same time,
334 and '_mmcamcorder_element_release_noti' will perfom removing handle.
336 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
338 _mmcam_dbg_log("Audio pipeline removed");
341 return MM_ERROR_NONE;
345 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
347 GstPad *reqpad = NULL;
348 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
349 _MMCamcorderSubContext *sc = NULL;
351 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
353 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
354 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
355 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
359 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
360 /* release request pad */
361 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
363 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
364 gst_object_unref(reqpad);
368 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
370 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
371 gst_object_unref(reqpad);
375 /* release encode main pipeline */
376 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
379 To avoid conflicting between old elements and newly created elements,
380 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
381 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
382 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
383 It's because the pipeline of audio recording destroys at the same time,
384 and '_mmcamcorder_element_release_noti' will perfom removing handle.
386 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
387 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
389 _mmcam_dbg_log("Encoder pipeline removed");
392 return MM_ERROR_NONE;
396 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
398 int ret = MM_ERROR_NONE;
399 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
400 _MMCamcorderSubContext *sc = NULL;
404 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
405 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
406 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
408 _mmcam_dbg_log("start");
410 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
411 _mmcam_dbg_warn("pipeline is not existed.");
412 return MM_ERROR_NONE;
415 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
417 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
418 if (ret != MM_ERROR_NONE) {
419 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
423 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
425 /* remove audio pipeline first */
426 ret = _mmcamcorder_remove_audio_pipeline(handle);
427 if (ret != MM_ERROR_NONE) {
428 _mmcam_dbg_err("Fail to remove audio pipeline");
432 ret = _mmcamcorder_remove_encode_pipeline(handle);
433 if (ret != MM_ERROR_NONE) {
434 _mmcam_dbg_err("Fail to remove encoder pipeline");
438 /* Remove pipeline message callback */
439 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
440 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
441 hcamcorder->encode_pipeline_cb_event_id = 0;
444 /* Remove remained message */
446 GstMessage *gst_msg = NULL;
447 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
448 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
449 gst_message_unref(gst_msg);
452 gst_object_unref(bus);
456 _mmcam_dbg_log("done");
462 int _mmcamcorder_video_command(MMHandleType handle, int command)
467 int ret = MM_ERROR_NONE;
468 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
469 char *err_name = NULL;
470 char *temp_filename = NULL;
471 GstCameraControl *CameraControl = NULL;
472 GstCameraControlChannel *CameraControlChannel = NULL;
473 const GList *controls = NULL;
474 const GList *item = NULL;
477 GstElement *pipeline = NULL;
479 _MMCamcorderVideoInfo *info = NULL;
480 _MMCamcorderSubContext *sc = NULL;
481 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
483 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
485 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
486 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
487 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
488 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
490 info = sc->info_video;
492 _mmcam_dbg_log("Command(%d)", command);
494 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
497 case _MMCamcorder_CMD_RECORD:
499 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
505 int ret_free_space = 0;
506 char *dir_name = NULL;
507 guint64 free_space = 0;
508 int file_system_type = 0;
509 int root_directory_length = 0;
512 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
514 /* init record_dual_stream */
515 info->record_dual_stream = FALSE;
517 ret = mm_camcorder_get_attributes(handle, &err_name,
518 MMCAM_CAMERA_FPS, &fps,
519 MMCAM_CAMERA_WIDTH, &(info->preview_width),
520 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
521 MMCAM_VIDEO_WIDTH, &(info->video_width),
522 MMCAM_VIDEO_HEIGHT, &(info->video_height),
523 MMCAM_FILE_FORMAT, &fileformat,
524 MMCAM_TARGET_FILENAME, &temp_filename, &size,
525 MMCAM_TARGET_MAX_SIZE, &imax_size,
526 MMCAM_TARGET_TIME_LIMIT, &imax_time,
527 MMCAM_FILE_FORMAT, &(info->fileformat),
528 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
529 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
531 if (ret != MM_ERROR_NONE) {
532 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
534 goto _ERR_CAMCORDER_VIDEO_COMMAND;
537 if (temp_filename == NULL) {
538 _mmcam_dbg_err("filename is not set");
539 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
540 goto _ERR_CAMCORDER_VIDEO_COMMAND;
545 info->max_size = 0; /* do not check */
547 info->max_size = ((guint64)imax_size) << 10; /* to byte */
551 info->max_time = 0; /* do not check */
553 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
555 dir_name = g_path_get_dirname(temp_filename);
557 ret = _mmcamcorder_get_storage_info(dir_name, hcamcorder->root_directory, &hcamcorder->storage_info);
559 _mmcam_dbg_err("get storage info failed");
560 return MM_ERROR_OUT_OF_STORAGE;
563 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
565 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
567 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
568 /* MSDOS_SUPER_MAGIC : 0x4d44 */
569 if (file_system_type == MSDOS_SUPER_MAGIC &&
570 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
571 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
572 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
573 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
575 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
576 file_system_type, info->max_size);
579 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
585 _mmcam_dbg_err("failed to get directory name");
589 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
590 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
591 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
592 return MM_ERROR_OUT_OF_STORAGE;
595 g_mutex_lock(&hcamcorder->task_thread_lock);
596 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
597 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
598 /* Play record start sound */
599 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
601 g_mutex_unlock(&hcamcorder->task_thread_lock);
603 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
605 if (info->video_width == 0 || info->video_height == 0) {
606 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
607 info->video_width, info->video_height, info->preview_width, info->preview_height);
608 info->video_width = info->preview_width;
609 info->video_height = info->preview_height;
612 if (info->support_dual_stream) {
613 _mmcam_dbg_warn("DUAL STREAM MODE");
615 info->record_dual_stream = TRUE;
617 /* No need to restart preview */
618 info->restart_preview = FALSE;
620 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
621 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
622 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
623 info->preview_width == info->video_width &&
624 info->preview_height == info->video_height) {
625 _mmcam_dbg_log("H264 preview mode and same resolution");
627 /* No need to restart preview */
628 info->restart_preview = FALSE;
630 /* always need to restart preview */
631 info->restart_preview = TRUE;
634 /* set recording hint */
635 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
637 if (info->restart_preview) {
638 /* stop preview and set new size */
639 _mmcam_dbg_log("restart preview");
641 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
642 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
644 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
646 /* check decoder recreation */
647 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
648 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
649 ret = MM_ERROR_CAMCORDER_INTERNAL;
650 goto _ERR_CAMCORDER_VIDEO_COMMAND;
653 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
654 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
656 if (ret != MM_ERROR_NONE)
657 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;
669 if (motion_rate < 1.0) {
670 _mmcam_dbg_warn("wait for stabilization of frame");
674 _mmcam_dbg_log("no need to restart preview");
677 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
678 CONFIGURE_CATEGORY_MAIN_RECORD,
682 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
683 CONFIGURE_CATEGORY_MAIN_RECORD,
684 "PassFirstVideoFrame",
685 &(sc->pass_first_vframe));
687 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
688 sc->drop_vframe, sc->pass_first_vframe);
690 info->record_drop_count = (guint)motion_rate;
691 info->record_motion_rate = motion_rate;
692 if (sc->is_modified_rate)
693 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
695 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
697 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
698 fps, info->record_motion_rate, info->record_timestamp_ratio);
700 /* set push buffer flag */
701 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
702 info->base_video_ts = 0;
704 /* connect video stream cb signal */
705 /*130826 Connect video stream cb for handling fast record frame cb*/
706 if (info->record_dual_stream) {
707 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
708 goto _ERR_CAMCORDER_VIDEO_COMMAND;
711 /* start video stream */
712 if (info->record_dual_stream) {
713 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
715 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
717 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
718 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
720 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
722 _mmcam_dbg_err("could not get camera control");
726 /* check pre-created encode pipeline */
727 g_mutex_lock(&hcamcorder->task_thread_lock);
728 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
729 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
730 /* create encoding pipeline */
731 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
732 if (ret != MM_ERROR_NONE) {
733 g_mutex_unlock(&hcamcorder->task_thread_lock);
734 goto _ERR_CAMCORDER_VIDEO_COMMAND;
737 g_mutex_unlock(&hcamcorder->task_thread_lock);
739 /* check recording start sound */
740 _mmcamcorder_sound_solo_play_wait(handle);
742 /**< To fix video recording hanging
743 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
744 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
745 basetime wouldn't change if you set (GstClockTime)0.
746 3. Move set start time position below PAUSED of pipeline.
749 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
750 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
753 info->video_frame_count = 0;
754 info->is_firstframe = TRUE;
755 info->audio_frame_count = 0;
757 sc->ferror_send = FALSE;
758 sc->ferror_count = 0;
759 hcamcorder->error_occurs = FALSE;
760 sc->bget_eos = FALSE;
762 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
763 if (ret != MM_ERROR_NONE) {
764 /* stop video stream */
765 if (info->record_dual_stream) {
766 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
768 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
770 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
771 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
773 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
775 _mmcam_dbg_err("failed to get camera control");
779 /* Remove recorder pipeline and recording file which size maybe zero */
780 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
781 if (info->filename) {
782 _mmcam_dbg_log("file delete(%s)", info->filename);
783 unlink(info->filename);
785 goto _ERR_CAMCORDER_VIDEO_COMMAND;
788 /*set the camera control to create the GOP so that video record will get a new key frame*/
789 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
790 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
791 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
792 controls = gst_camera_control_list_channels(CameraControl);
793 if (controls != NULL) {
794 for (item = controls ; item && item->data ; item = item->next) {
795 CameraControlChannel = item->data;
796 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
797 if (!strcmp(CameraControlChannel->label, "new-gop")) {
798 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
804 _mmcam_dbg_warn("failed to find new-gop control channel");
807 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
808 sc->info_image->preview_format);
813 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
814 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
815 /* generate and I-frame on resuming */
816 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
817 controls = gst_camera_control_list_channels(CameraControl);
818 if (controls != NULL) {
819 for (item = controls ; item && item->data ; item = item->next) {
820 CameraControlChannel = item->data;
821 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
822 if (!strcmp(CameraControlChannel->label, "new-gop")) {
823 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
829 _mmcam_dbg_warn("failed to find new-gop control channel");
833 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
835 _mmcam_dbg_log("Object property settings done");
839 case _MMCamcorder_CMD_PAUSE:
841 if (info->b_commiting) {
842 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
843 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
846 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
847 if (sc->audio_disable) {
848 /* check only video frame */
849 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
851 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
852 _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
853 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
855 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", count, info->video_frame_count);
858 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
860 /* check both of video and audio frame */
861 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
863 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
864 _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
865 info->video_frame_count, info->audio_frame_count);
866 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
868 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
869 count, info->video_frame_count, info->audio_frame_count);
872 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
876 /* block encodebin */
877 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
880 case _MMCamcorder_CMD_CANCEL:
882 if (info->b_commiting) {
883 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
884 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
887 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
889 if (hcamcorder->capture_in_recording == FALSE) {
891 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
892 _mmcam_dbg_err("Failed to Wait capture data");
893 hcamcorder->capture_in_recording = FALSE;
896 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
899 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
902 /* block push buffer */
903 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
905 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
906 if (ret != MM_ERROR_NONE)
907 goto _ERR_CAMCORDER_VIDEO_COMMAND;
909 /* set recording hint */
910 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
912 /* stop video stream */
913 if (info->record_dual_stream) {
914 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
916 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
918 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
919 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
921 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
923 _mmcam_dbg_err("failed to get camera control");
927 if (info->restart_preview) {
928 /* restart preview */
929 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
930 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
932 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
934 /* check decoder recreation */
935 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
936 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
937 ret = MM_ERROR_CAMCORDER_INTERNAL;
940 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
941 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
943 if (ret != MM_ERROR_NONE)
944 goto _ERR_CAMCORDER_VIDEO_COMMAND;
946 /* reset restart_preview for inset window layout */
947 info->restart_preview = FALSE;
949 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
950 ret = MM_ERROR_CAMCORDER_INTERNAL;
951 goto _ERR_CAMCORDER_VIDEO_COMMAND;
954 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
955 if (ret != MM_ERROR_NONE)
956 goto _ERR_CAMCORDER_VIDEO_COMMAND;
959 /* remove target file */
960 if (info->filename) {
961 _mmcam_dbg_log("file delete(%s)", info->filename);
962 unlink(info->filename);
965 sc->isMaxsizePausing = FALSE;
966 sc->isMaxtimePausing = FALSE;
968 sc->display_interval = 0;
969 sc->previous_slot_time = 0;
970 info->video_frame_count = 0;
971 info->audio_frame_count = 0;
973 hcamcorder->capture_in_recording = FALSE;
976 case _MMCamcorder_CMD_COMMIT:
978 if (info->b_commiting) {
979 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
980 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
982 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
983 info->b_commiting = TRUE;
984 sc->bget_eos = FALSE;
987 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
988 if (sc->audio_disable) {
989 /* check only video frame */
990 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
991 hcamcorder->capture_in_recording == FALSE) {
993 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
994 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
995 info->video_frame_count, hcamcorder->capture_in_recording);
997 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
998 _mmcam_dbg_warn("video frames are enough. keep going...");
1000 info->b_commiting = FALSE;
1001 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1004 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1005 count, info->video_frame_count, hcamcorder->capture_in_recording);
1008 /* check both of video and audio frame */
1009 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1010 info->audio_frame_count &&
1011 hcamcorder->capture_in_recording == FALSE) {
1013 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1014 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1015 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1017 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1018 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1020 info->b_commiting = FALSE;
1021 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1024 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1026 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1027 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1031 if (hcamcorder->capture_in_recording) {
1032 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1033 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1034 _mmcam_dbg_warn("signal received");
1036 _mmcam_dbg_warn("timeout");
1039 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1043 /* block push buffer */
1044 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1045 _mmcam_dbg_log("block push buffer to appsrc");
1047 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1048 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1049 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1051 _mmcam_dbg_err("VIDEO: send EOS failed");
1052 info->b_commiting = FALSE;
1053 ret = MM_ERROR_CAMCORDER_INTERNAL;
1054 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1057 _mmcam_dbg_err("No video stream source");
1058 info->b_commiting = FALSE;
1059 ret = MM_ERROR_CAMCORDER_INTERNAL;
1060 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1063 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1064 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1065 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1067 _mmcam_dbg_err("AUDIO: send EOS failed");
1068 info->b_commiting = FALSE;
1069 ret = MM_ERROR_CAMCORDER_INTERNAL;
1070 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1073 _mmcam_dbg_log("No audio stream");
1077 sc->display_interval = 0;
1078 sc->previous_slot_time = 0;
1081 _mmcam_dbg_log("Start to wait EOS");
1082 ret = _mmcamcorder_get_eos_message(handle);
1083 if (ret != MM_ERROR_NONE) {
1084 info->b_commiting = FALSE;
1085 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1089 hcamcorder->capture_in_recording = FALSE;
1093 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1094 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1097 return MM_ERROR_NONE;
1099 _ERR_CAMCORDER_VIDEO_COMMAND:
1100 if (command == _MMCamcorder_CMD_RECORD)
1101 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1107 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1109 int ret = MM_ERROR_NONE;
1111 guint64 file_size = 0;
1113 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1114 _MMCamcorderSubContext *sc = NULL;
1115 _MMCamcorderVideoInfo *info = NULL;
1116 _MMCamcorderMsgItem msg;
1117 MMCamRecordingReport *report = NULL;
1119 mmf_return_val_if_fail(hcamcorder, FALSE);
1121 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1122 mmf_return_val_if_fail(sc, FALSE);
1123 mmf_return_val_if_fail(sc->info_video, FALSE);
1125 info = sc->info_video;
1129 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1130 /* Play record stop sound */
1131 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1133 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1135 _mmcamcorder_sound_init(handle);
1137 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1139 _mmcamcorder_sound_finalize(handle);
1142 /* remove blocking part */
1143 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1145 mm_camcorder_get_attributes(handle, NULL,
1146 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1149 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1150 if (ret != MM_ERROR_NONE)
1151 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1153 /* set recording hint */
1154 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1156 /* stop video stream */
1157 if (info->record_dual_stream) {
1158 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1160 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1162 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1163 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1165 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1167 _mmcam_dbg_err("failed to get camera control");
1171 if (enabletag && !(sc->ferror_send)) {
1172 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1174 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1176 _mmcam_dbg_err("Writing location information FAILED !!");
1180 /* Check file size */
1181 if (info->max_size > 0) {
1182 _mmcamcorder_get_file_size(info->filename, &file_size);
1183 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1184 info->max_size, file_size);
1186 if (file_size > info->max_size) {
1187 _MMCamcorderMsgItem message;
1188 _mmcam_dbg_err("File size is greater than max size !!");
1189 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1190 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1191 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1195 if (info->restart_preview) {
1197 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1198 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1200 _mmcam_dbg_log("Set state of pipeline as READY");
1201 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1203 /* check decoder recreation */
1204 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1205 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1206 ret = MM_ERROR_CAMCORDER_INTERNAL;
1210 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1211 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1212 if (ret != MM_ERROR_NONE) {
1213 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1214 msg.param.code = ret;
1215 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1216 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1219 /* reset restart_preview for inset window layout */
1220 info->restart_preview = FALSE;
1222 /* recover preview size */
1223 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1225 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1226 /* Do not return when error is occurred.
1227 Recording file was created successfully, but starting pipeline failed */
1228 if (ret != MM_ERROR_NONE) {
1229 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1230 msg.param.code = ret;
1231 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1232 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1235 _mmcam_dbg_log("No need to restart preview");
1238 /* Send recording report to application */
1239 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1240 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1242 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1244 report->recording_filename = g_strdup(info->filename);
1245 msg.param.data = report;
1247 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1251 sc->pipeline_time = 0;
1253 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1254 sc->isMaxtimePausing = FALSE;
1255 hcamcorder->error_occurs = FALSE;
1257 info->video_frame_count = 0;
1258 info->audio_frame_count = 0;
1260 info->b_commiting = FALSE;
1262 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1263 /* check recording stop sound */
1264 _mmcamcorder_sound_solo_play_wait(handle);
1267 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1274 * This function is record video data probing function.
1275 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
1276 * this function will be called when data stream pass through the pad.
1278 * @param[in] pad probing pad which calls this function.
1279 * @param[in] buffer buffer which contains stream data.
1280 * @param[in] u_data user data.
1281 * @return This function returns true on success, or false value with error
1285 static GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1287 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
1288 switch (GST_EVENT_TYPE(event)) {
1289 case GST_EVENT_UNKNOWN:
1290 /* upstream events */
1292 case GST_EVENT_SEEK:
1293 case GST_EVENT_NAVIGATION:
1294 case GST_EVENT_LATENCY:
1295 /* downstream serialized events */
1296 case GST_EVENT_SEGMENT:
1298 case GST_EVENT_BUFFERSIZE:
1299 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1302 _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1304 /* bidirectional events */
1305 case GST_EVENT_FLUSH_START:
1306 case GST_EVENT_FLUSH_STOP:
1307 _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1310 _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
1314 return GST_PAD_PROBE_OK;
1318 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1320 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1321 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1323 _MMCamcorderSubContext *sc = NULL;
1324 _MMCamcorderVideoInfo *videoinfo = NULL;
1325 _MMCamcorderMsgItem msg;
1326 guint64 buffer_size = 0;
1327 guint64 trailer_size = 0;
1328 guint64 max_size = 0;
1330 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1331 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1332 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1334 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1335 videoinfo = sc->info_video;
1337 /* get buffer size */
1338 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1339 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1340 return GST_PAD_PROBE_OK;
1343 buffer_size = mapinfo.size;
1344 gst_buffer_unmap(buffer, &mapinfo);
1346 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1348 g_mutex_lock(&videoinfo->size_check_lock);
1350 if (videoinfo->audio_frame_count == 0) {
1351 videoinfo->filesize += buffer_size;
1352 videoinfo->audio_frame_count++;
1353 g_mutex_unlock(&videoinfo->size_check_lock);
1354 return GST_PAD_PROBE_OK;
1357 if (sc->ferror_send || sc->isMaxsizePausing) {
1358 _mmcam_dbg_warn("Recording is paused, drop frames");
1359 g_mutex_unlock(&videoinfo->size_check_lock);
1360 return GST_PAD_PROBE_DROP;
1363 /* get trailer size */
1364 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1365 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1370 /* check max size of recorded file */
1371 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1372 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1373 GstState pipeline_state = GST_STATE_VOID_PENDING;
1374 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1375 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1376 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1377 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1378 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1380 if (!sc->isMaxsizePausing) {
1381 sc->isMaxsizePausing = TRUE;
1382 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1383 if (pipeline_state == GST_STATE_PLAYING)
1384 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1386 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1387 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1390 g_mutex_unlock(&videoinfo->size_check_lock);
1395 videoinfo->filesize += buffer_size;
1396 videoinfo->audio_frame_count++;
1398 g_mutex_unlock(&videoinfo->size_check_lock);
1400 return GST_PAD_PROBE_OK;
1404 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1409 guint64 free_space = 0;
1410 guint64 buffer_size = 0;
1411 guint64 trailer_size = 0;
1412 guint64 queued_buffer = 0;
1413 guint64 max_size = 0;
1414 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1416 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1418 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1419 _MMCamcorderMsgItem msg;
1420 _MMCamcorderSubContext *sc = NULL;
1421 _MMCamcorderVideoInfo *videoinfo = NULL;
1423 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1424 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1426 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1427 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1428 videoinfo = sc->info_video;
1430 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1431 if (sc->ferror_send) {
1432 _mmcam_dbg_warn("file write error, drop frames");
1433 return GST_PAD_PROBE_DROP;
1436 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1437 buffer_size = mapinfo.size;
1438 gst_buffer_unmap(buffer, &mapinfo);
1440 videoinfo->video_frame_count++;
1441 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1442 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1443 info->video_frame_count); */
1444 g_mutex_lock(&videoinfo->size_check_lock);
1445 videoinfo->filesize += buffer_size;
1446 g_mutex_unlock(&videoinfo->size_check_lock);
1447 return GST_PAD_PROBE_OK;
1450 /* get trailer size */
1451 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1452 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1457 /* check free space */
1458 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1460 _mmcam_dbg_err("Error occured. [%d]", ret);
1461 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1462 sc->ferror_send = TRUE;
1464 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1465 msg.param.code = MM_ERROR_FILE_READ;
1467 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1472 return GST_PAD_PROBE_DROP; /* skip this buffer */
1475 if (free_space == 0) {
1476 /* check storage state */
1477 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1479 _mmcam_dbg_warn("storage state %d", storage_state);
1481 if (storage_state == STORAGE_STATE_REMOVED ||
1482 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1483 _mmcam_dbg_err("storage was removed!");
1485 _MMCAMCORDER_LOCK(hcamcorder);
1487 if (sc->ferror_send == FALSE) {
1488 _mmcam_dbg_err("OUT_OF_STORAGE error");
1490 sc->ferror_send = TRUE;
1492 _MMCAMCORDER_UNLOCK(hcamcorder);
1494 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1495 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1497 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1499 _MMCAMCORDER_UNLOCK(hcamcorder);
1500 _mmcam_dbg_warn("error was already sent");
1503 return GST_PAD_PROBE_DROP;
1507 /* get queued buffer size */
1508 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1509 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1512 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1513 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1516 queued_buffer = aq_size + vq_size;
1518 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1519 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1520 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1521 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1522 free_space, trailer_size, buffer_size, queued_buffer);
1524 if (!sc->isMaxsizePausing) {
1525 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1526 sc->isMaxsizePausing = TRUE;
1528 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1529 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1532 return GST_PAD_PROBE_DROP;
1535 g_mutex_lock(&videoinfo->size_check_lock);
1537 /* check max size of recorded file */
1538 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1539 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1540 GstState pipeline_state = GST_STATE_VOID_PENDING;
1541 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1542 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1543 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1544 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1545 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1547 if (!sc->isMaxsizePausing) {
1548 sc->isMaxsizePausing = TRUE;
1549 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1550 if (pipeline_state == GST_STATE_PLAYING)
1551 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1553 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1554 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1557 g_mutex_unlock(&videoinfo->size_check_lock);
1559 return GST_PAD_PROBE_DROP;
1562 videoinfo->filesize += (guint64)buffer_size;
1565 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1568 g_mutex_unlock(&videoinfo->size_check_lock);
1570 return GST_PAD_PROBE_OK;
1574 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1576 guint64 trailer_size = 0;
1577 guint64 rec_pipe_time = 0;
1578 unsigned int remained_time = 0;
1580 GstClockTime b_time;
1582 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1583 _MMCamcorderMsgItem msg;
1584 _MMCamcorderSubContext *sc = NULL;
1585 _MMCamcorderVideoInfo *videoinfo = NULL;
1587 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1589 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1590 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1592 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1593 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1594 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1596 videoinfo = sc->info_video;
1598 b_time = GST_BUFFER_PTS(buffer);
1600 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1602 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1603 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1608 /* check max time */
1609 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1610 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1611 rec_pipe_time, videoinfo->max_time);
1613 if (!sc->isMaxtimePausing) {
1614 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1616 sc->isMaxtimePausing = TRUE;
1618 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1619 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1620 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1621 msg.param.recording_status.remained_time = 0;
1622 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1624 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1625 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1628 return GST_PAD_PROBE_DROP;
1631 /* calculate remained time can be recorded */
1632 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1633 remained_time = videoinfo->max_time - rec_pipe_time;
1634 } else if (videoinfo->max_size > 0) {
1635 long double max_size = (long double)videoinfo->max_size;
1636 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1638 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1641 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1642 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1643 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1644 msg.param.recording_status.remained_time = remained_time;
1645 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1648 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1649 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1652 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1653 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1656 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1657 record_motion_rate, videoinfo->record_drop_count);
1660 /* drop some frame if fast motion */
1661 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1662 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1664 _mmcam_dbg_warn("drop frame");
1666 return GST_PAD_PROBE_DROP;
1669 videoinfo->record_drop_count = 1;
1671 _mmcam_dbg_warn("pass frame");
1675 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1678 return GST_PAD_PROBE_OK;
1682 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1684 _MMCamcorderMsgItem msg;
1685 guint64 trailer_size = 0;
1686 guint64 rec_pipe_time = 0;
1687 _MMCamcorderSubContext *sc = NULL;
1688 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1689 _MMCamcorderVideoInfo *videoinfo = NULL;
1690 unsigned int remained_time = 0;
1691 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1693 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1694 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1695 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1697 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1698 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1699 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1701 videoinfo = sc->info_video;
1703 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1704 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1705 return GST_PAD_PROBE_OK;
1708 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1710 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1711 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1716 /* calculate remained time can be recorded */
1717 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1718 remained_time = videoinfo->max_time - rec_pipe_time;
1719 } else if (videoinfo->max_size > 0) {
1720 long double max_size = (long double)videoinfo->max_size;
1721 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1723 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1726 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1727 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1728 rec_pipe_time, videoinfo->max_time);
1730 if (!sc->isMaxtimePausing) {
1731 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1733 sc->isMaxtimePausing = TRUE;
1735 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1736 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1737 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1738 msg.param.recording_status.remained_time = 0;
1739 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1741 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1742 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1745 return GST_PAD_PROBE_DROP;
1748 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1749 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1750 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1751 msg.param.recording_status.remained_time = remained_time;
1752 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1755 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1756 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1759 return GST_PAD_PROBE_OK;
1763 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1765 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1766 double volume = 0.0;
1769 int err = MM_ERROR_UNKNOWN;
1770 char *err_name = NULL;
1771 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1774 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1775 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1777 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1778 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1779 MMCAM_AUDIO_VOLUME, &volume,
1780 MMCAM_AUDIO_FORMAT, &format,
1781 MMCAM_AUDIO_CHANNEL, &channel,
1783 if (err != MM_ERROR_NONE) {
1784 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1785 SAFE_FREE(err_name);
1789 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1791 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1793 /* Set audio stream NULL */
1795 memset(mapinfo.data, 0, mapinfo.size);
1797 /* CALL audio stream callback */
1798 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1799 MMCamcorderAudioStreamDataType stream;
1801 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1802 _mmcam_dbg_warn("Not ready for stream callback");
1803 gst_buffer_unmap(buffer, &mapinfo);
1804 return GST_PAD_PROBE_OK;
1807 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1808 GST_BUFFER_DATA(buffer), width, height, format);*/
1810 stream.data = (void *)mapinfo.data;
1811 stream.format = format;
1812 stream.channel = channel;
1813 stream.length = mapinfo.size;
1814 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1816 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1818 if (hcamcorder->astream_cb)
1819 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1821 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1824 gst_buffer_unmap(buffer, &mapinfo);
1825 return GST_PAD_PROBE_OK;
1829 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1831 gboolean bret = FALSE;
1833 switch (fileformat) {
1834 case MM_FILE_FORMAT_3GP:
1835 case MM_FILE_FORMAT_MP4:
1836 bret = __mmcamcorder_add_metadata_mp4(handle);
1839 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1847 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1851 guint64 udta_size = 0;
1852 gint64 current_pos = 0;
1853 gint64 moov_pos = 0;
1854 gint64 udta_pos = 0;
1855 gdouble longitude = 0;
1856 gdouble latitude = 0;
1857 gdouble altitude = 0;
1859 int orientation = 0;
1861 char *err_name = NULL;
1862 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1863 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1864 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1866 _MMCamcorderVideoInfo *info = NULL;
1867 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1868 _MMCamcorderSubContext *sc = NULL;
1870 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1871 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1873 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1874 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1878 info = sc->info_video;
1880 f = fopen64(info->filename, "rb+");
1882 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1883 _mmcam_dbg_err("file open failed [%s]", err_msg);
1887 mm_camcorder_get_attributes(handle, &err_name,
1888 MMCAM_TAG_LATITUDE, &latitude,
1889 MMCAM_TAG_LONGITUDE, &longitude,
1890 MMCAM_TAG_ALTITUDE, &altitude,
1891 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1892 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1895 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1896 SAFE_FREE(err_name);
1899 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1900 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1901 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1902 geo_info.longitude = longitude *10000;
1903 geo_info.latitude = latitude *10000;
1904 geo_info.altitude = altitude *10000;
1905 /* find udta container.
1906 if, there are udta container, write loci box after that
1907 else, make udta container and write loci box. */
1908 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1911 _mmcam_dbg_log("find udta container");
1914 if (fseek(f, -8L, SEEK_CUR) != 0)
1917 udta_pos = ftello(f);
1921 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1923 _mmcam_dbg_log("recorded file fread %d", nread);
1925 udta_size = _mmcamcorder_get_container_size(buf);
1927 /* goto end of udta and write 'loci' box */
1928 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1932 if (!_mmcamcorder_write_loci(f, location_info)) {
1933 _mmcam_dbg_err("failed to write loci");
1937 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1938 _mmcam_dbg_err("failed to write geodata");
1943 current_pos = ftello(f);
1944 if (current_pos < 0)
1947 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1950 _mmcam_dbg_log("No udta container");
1951 if (fseek(f, 0, SEEK_END) != 0)
1954 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1955 _mmcam_dbg_err("failed to write udta");
1960 /* find moov container.
1961 update moov container size. */
1962 if ((current_pos = ftello(f)) < 0)
1965 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1966 gint64 internal_pos = ftello(f);
1968 _mmcam_dbg_log("found moov container");
1969 if (fseek(f, -8L, SEEK_CUR) != 0)
1972 moov_pos = ftello(f);
1976 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
1979 /* add orientation info */
1980 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1981 _mmcam_dbg_err("fseek failed : errno %d", errno);
1985 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
1986 _mmcam_dbg_err("failed to find [trak] tag");
1990 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
1991 _mmcam_dbg_err("failed to find [tkhd] tag");
1995 _mmcam_dbg_log("found [tkhd] tag");
1997 /* seek to start position of composition matrix */
1998 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
2000 /* update composition matrix for orientation */
2001 _mmcamcorder_update_composition_matrix(f, orientation);
2003 _mmcam_dbg_err("No 'moov' container");
2015 _mmcam_dbg_err("ftell() returns negative value.");
2021 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2023 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2024 _MMCamcorderSubContext *sc = NULL;
2026 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2028 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2029 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2031 /* check video source element */
2032 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2033 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2034 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2035 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2036 G_CALLBACK(__mmcamcorder_video_stream_cb),
2038 return MM_ERROR_NONE;
2040 _mmcam_dbg_err("videosrc element is not created yet");
2041 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2046 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2048 int ret = MM_ERROR_NONE;
2050 _MMCamcorderVideoInfo *info = NULL;
2051 _MMCamcorderSubContext *sc = NULL;
2052 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2054 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2056 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2057 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2058 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2060 info = sc->info_video;
2062 _mmcam_dbg_warn("start");
2064 /* create encoding pipeline */
2065 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2066 if (ret != MM_ERROR_NONE)
2067 goto _ERR_PREPARE_RECORD;
2069 if (info->filename == NULL) {
2070 char *temp_filename = NULL;
2073 mm_camcorder_get_attributes(handle, NULL,
2074 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2077 info->filename = g_strdup(temp_filename);
2079 if (!info->filename) {
2080 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2081 goto _ERR_PREPARE_RECORD;
2085 _mmcam_dbg_log("Record file name [%s]", info->filename);
2087 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2088 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2090 /* Adjust display FPS */
2091 sc->display_interval = 0;
2092 sc->previous_slot_time = 0;
2094 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2095 if (ret != MM_ERROR_NONE)
2096 goto _ERR_PREPARE_RECORD;
2098 _mmcam_dbg_warn("done");
2102 _ERR_PREPARE_RECORD:
2103 /* Remove recorder pipeline and recording file which size maybe zero */
2104 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2105 if (info && info->filename) {
2106 _mmcam_dbg_log("file delete(%s)", info->filename);
2107 unlink(info->filename);