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);
58 /*=======================================================================================
59 | FUNCTION DEFINITIONS |
60 =======================================================================================*/
61 /*---------------------------------------------------------------------------------------
62 | GLOBAL FUNCTION DEFINITIONS: |
63 ---------------------------------------------------------------------------------------*/
64 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
66 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
67 _MMCamcorderSubContext *sc = NULL;
69 GstBuffer *buffer = gst_sample_get_buffer(sample);
70 mmf_return_val_if_fail(buffer, FALSE);
71 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
72 mmf_return_val_if_fail(hcamcorder, FALSE);
74 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
75 mmf_return_val_if_fail(sc, FALSE);
78 _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
79 sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
82 /* push buffer in appsrc to encode */
83 if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
84 sc->info_video->record_dual_stream &&
85 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
86 GstFlowReturn ret = 0;
87 GstClock *pipe_clock = NULL;
89 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
90 if (sc->info_video->is_firstframe) {
91 sc->info_video->is_firstframe = FALSE;
92 pipe_clock = GST_ELEMENT_CLOCK(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
94 gst_object_ref(pipe_clock);
95 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);
96 gst_object_unref(pipe_clock);
100 if (sc->info_video->is_firstframe) {
101 sc->info_video->is_firstframe = FALSE;
102 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer);
106 GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS(buffer) - sc->info_video->base_video_ts;
107 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
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 functions */
228 if (sc->audio_disable == FALSE) {
229 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
230 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
231 __mmcamcorder_audioque_dataprobe, hcamcorder);
232 gst_object_unref(sinkpad);
236 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
237 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
238 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
239 gst_object_unref(srcpad);
242 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
243 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
244 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
245 __mmcamcorder_eventprobe_monitor, hcamcorder);
246 gst_object_unref(srcpad);
251 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
252 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
253 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
254 __mmcamcorder_eventprobe_monitor, hcamcorder);
255 gst_object_unref(srcpad);
259 if (sc->audio_disable) {
260 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
261 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
262 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
263 gst_object_unref(sinkpad);
267 if (!strcmp(gst_element_rsink_name, "filesink")) {
268 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
269 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
270 __mmcamcorder_video_dataprobe_record, hcamcorder);
271 gst_object_unref(srcpad);
274 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
275 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
276 __mmcamcorder_audio_dataprobe_check, hcamcorder);
277 gst_object_unref(srcpad);
281 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
282 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
283 __mmcamcorder_muxed_dataprobe, hcamcorder);
284 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
285 __mmcamcorder_eventprobe_monitor, hcamcorder);
286 gst_object_unref(sinkpad);
289 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
291 /* register pipeline message callback */
292 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
294 /* set sync handler */
295 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
297 gst_object_unref(bus);
300 return MM_ERROR_NONE;
302 pipeline_creation_error:
303 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
304 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
306 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
311 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
313 GstPad *srcpad = NULL;
314 GstPad *sinkpad = NULL;
315 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
316 _MMCamcorderSubContext *sc = NULL;
318 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
320 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
321 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
322 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
326 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
327 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
328 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
329 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
331 /* release audiosrc bin */
332 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
333 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
336 To avoid conflicting between old elements and newly created elements,
337 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
338 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
339 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
340 It's because the pipeline of audio recording destroys at the same time,
341 and '_mmcamcorder_element_release_noti' will perfom removing handle.
343 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
345 _mmcam_dbg_log("Audio pipeline removed");
348 return MM_ERROR_NONE;
352 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
354 GstPad *reqpad = NULL;
355 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
356 _MMCamcorderSubContext *sc = NULL;
358 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
360 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
361 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
362 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
366 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
367 /* release request pad */
368 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
370 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
371 gst_object_unref(reqpad);
375 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
377 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
378 gst_object_unref(reqpad);
382 /* release encode main pipeline */
383 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
386 To avoid conflicting between old elements and newly created elements,
387 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
388 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
389 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
390 It's because the pipeline of audio recording destroys at the same time,
391 and '_mmcamcorder_element_release_noti' will perfom removing handle.
393 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
394 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
396 _mmcam_dbg_log("Encoder pipeline removed");
399 return MM_ERROR_NONE;
403 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
405 int ret = MM_ERROR_NONE;
406 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
407 _MMCamcorderSubContext *sc = NULL;
411 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
412 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
413 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
415 _mmcam_dbg_log("start");
417 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
418 _mmcam_dbg_warn("pipeline is not existed.");
419 return MM_ERROR_NONE;
422 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
424 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
425 if (ret != MM_ERROR_NONE) {
426 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
430 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
432 /* remove audio pipeline first */
433 ret = _mmcamcorder_remove_audio_pipeline(handle);
434 if (ret != MM_ERROR_NONE) {
435 _mmcam_dbg_err("Fail to remove audio pipeline");
439 ret = _mmcamcorder_remove_encode_pipeline(handle);
440 if (ret != MM_ERROR_NONE) {
441 _mmcam_dbg_err("Fail to remove encoder pipeline");
445 /* Remove pipeline message callback */
446 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
447 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
448 hcamcorder->encode_pipeline_cb_event_id = 0;
451 /* Remove remained message */
453 GstMessage *gst_msg = NULL;
454 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
455 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
456 gst_message_unref(gst_msg);
459 gst_object_unref(bus);
463 _mmcam_dbg_log("done");
469 int _mmcamcorder_video_command(MMHandleType handle, int command)
474 int ret = MM_ERROR_NONE;
475 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
476 char *err_name = NULL;
477 char *temp_filename = NULL;
478 GstCameraControl *CameraControl = NULL;
479 GstCameraControlChannel *CameraControlChannel = NULL;
480 const GList *controls = NULL;
481 const GList *item = NULL;
484 GstElement *pipeline = NULL;
486 _MMCamcorderVideoInfo *info = NULL;
487 _MMCamcorderSubContext *sc = NULL;
488 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
490 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
492 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
493 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
494 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
495 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
497 info = sc->info_video;
499 _mmcam_dbg_log("Command(%d)", command);
501 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
504 case _MMCamcorder_CMD_RECORD:
506 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
512 int ret_free_space = 0;
513 char *dir_name = NULL;
514 guint64 free_space = 0;
515 int file_system_type = 0;
516 int root_directory_length = 0;
519 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
521 /* init record_dual_stream */
522 info->record_dual_stream = FALSE;
524 ret = mm_camcorder_get_attributes(handle, &err_name,
525 MMCAM_CAMERA_FPS, &fps,
526 MMCAM_CAMERA_WIDTH, &(info->preview_width),
527 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
528 MMCAM_VIDEO_WIDTH, &(info->video_width),
529 MMCAM_VIDEO_HEIGHT, &(info->video_height),
530 MMCAM_FILE_FORMAT, &fileformat,
531 MMCAM_TARGET_FILENAME, &temp_filename, &size,
532 MMCAM_TARGET_MAX_SIZE, &imax_size,
533 MMCAM_TARGET_TIME_LIMIT, &imax_time,
534 MMCAM_FILE_FORMAT, &(info->fileformat),
535 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
536 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
538 if (ret != MM_ERROR_NONE) {
539 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
541 goto _ERR_CAMCORDER_VIDEO_COMMAND;
544 if (temp_filename == NULL) {
545 _mmcam_dbg_err("filename is not set");
546 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
547 goto _ERR_CAMCORDER_VIDEO_COMMAND;
552 info->max_size = 0; /* do not check */
554 info->max_size = ((guint64)imax_size) << 10; /* to byte */
558 info->max_time = 0; /* do not check */
560 info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */
562 dir_name = g_path_get_dirname(temp_filename);
564 ret = _mmcamcorder_get_storage_info(dir_name, hcamcorder->root_directory, &hcamcorder->storage_info);
566 _mmcam_dbg_err("get storage info failed");
569 return MM_ERROR_OUT_OF_STORAGE;
572 ret_free_space = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
574 _mmcam_dbg_warn("current space - %s [%" G_GUINT64_FORMAT "]", dir_name, free_space);
576 if (_mmcamcorder_get_file_system_type(dir_name, &file_system_type) == 0) {
577 /* MSDOS_SUPER_MAGIC : 0x4d44 */
578 if (file_system_type == MSDOS_SUPER_MAGIC &&
579 (info->max_size == 0 || info->max_size > FAT32_FILE_SYSTEM_MAX_SIZE)) {
580 _mmcam_dbg_warn("FAT32 and too large max[%"G_GUINT64_FORMAT"], set max as %"G_GUINT64_FORMAT,
581 info->max_size, FAT32_FILE_SYSTEM_MAX_SIZE);
582 info->max_size = FAT32_FILE_SYSTEM_MAX_SIZE;
584 _mmcam_dbg_warn("file system 0x%x, max size %"G_GUINT64_FORMAT,
585 file_system_type, info->max_size);
588 _mmcam_dbg_warn("_mmcamcorder_get_file_system_type failed");
594 _mmcam_dbg_err("failed to get directory name");
598 if ((ret_free_space == -1) || free_space <= (_MMCAMCORDER_MINIMUM_SPACE<<1)) {
599 _mmcam_dbg_err("OUT of STORAGE [ret_free_space:%d or free space [%" G_GUINT64_FORMAT "] is smaller than [%d]",
600 ret_free_space, free_space, (_MMCAMCORDER_MINIMUM_SPACE<<1));
601 return MM_ERROR_OUT_OF_STORAGE;
604 g_mutex_lock(&hcamcorder->task_thread_lock);
605 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
606 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
607 /* Play record start sound */
608 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
610 g_mutex_unlock(&hcamcorder->task_thread_lock);
612 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
614 if (info->video_width == 0 || info->video_height == 0) {
615 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
616 info->video_width, info->video_height, info->preview_width, info->preview_height);
617 info->video_width = info->preview_width;
618 info->video_height = info->preview_height;
621 if (info->support_dual_stream) {
622 _mmcam_dbg_warn("DUAL STREAM MODE");
624 info->record_dual_stream = TRUE;
626 /* No need to restart preview */
627 info->restart_preview = FALSE;
629 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
630 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
631 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
632 info->preview_width == info->video_width &&
633 info->preview_height == info->video_height) {
634 _mmcam_dbg_log("H264 preview mode and same resolution");
636 /* No need to restart preview */
637 info->restart_preview = FALSE;
639 /* always need to restart preview */
640 info->restart_preview = TRUE;
643 /* set recording hint */
644 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
646 if (info->restart_preview) {
647 /* stop preview and set new size */
648 _mmcam_dbg_log("restart preview");
650 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
651 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
652 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
654 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
656 /* check decoder recreation */
657 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
658 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
659 ret = MM_ERROR_CAMCORDER_INTERNAL;
660 goto _ERR_CAMCORDER_VIDEO_COMMAND;
663 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
664 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
665 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
667 if (ret != MM_ERROR_NONE)
668 goto _ERR_CAMCORDER_VIDEO_COMMAND;
670 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
671 ret = MM_ERROR_CAMCORDER_INTERNAL;
672 goto _ERR_CAMCORDER_VIDEO_COMMAND;
675 /* Start preview again with new setting */
676 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
677 if (ret != MM_ERROR_NONE)
678 goto _ERR_CAMCORDER_VIDEO_COMMAND;
680 if (motion_rate < 1.0) {
681 _mmcam_dbg_warn("wait for stabilization of frame");
685 _mmcam_dbg_log("no need to restart preview");
688 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
689 CONFIGURE_CATEGORY_MAIN_RECORD,
693 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
694 CONFIGURE_CATEGORY_MAIN_RECORD,
695 "PassFirstVideoFrame",
696 &(sc->pass_first_vframe));
698 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
699 sc->drop_vframe, sc->pass_first_vframe);
701 info->record_drop_count = (guint)motion_rate;
702 info->record_motion_rate = motion_rate;
703 if (sc->is_modified_rate)
704 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
706 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
708 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
709 fps, info->record_motion_rate, info->record_timestamp_ratio);
711 /* set push buffer flag */
712 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
713 info->base_video_ts = 0;
715 /* connect video stream cb signal */
716 /*130826 Connect video stream cb for handling fast record frame cb*/
717 if (info->record_dual_stream) {
718 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
719 goto _ERR_CAMCORDER_VIDEO_COMMAND;
722 /* start video stream */
723 if (info->record_dual_stream) {
724 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
726 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
728 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
729 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
731 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
733 _mmcam_dbg_err("could not get camera control");
737 /* check pre-created encode pipeline */
738 g_mutex_lock(&hcamcorder->task_thread_lock);
739 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
740 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
741 /* create encoding pipeline */
742 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
743 if (ret != MM_ERROR_NONE) {
744 g_mutex_unlock(&hcamcorder->task_thread_lock);
745 goto _ERR_CAMCORDER_VIDEO_COMMAND;
748 g_mutex_unlock(&hcamcorder->task_thread_lock);
750 /* check recording start sound */
751 _mmcamcorder_sound_solo_play_wait(handle);
753 /**< To fix video recording hanging
754 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
755 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
756 basetime wouldn't change if you set (GstClockTime)0.
757 3. Move set start time position below PAUSED of pipeline.
760 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
761 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
764 info->video_frame_count = 0;
765 info->is_firstframe = TRUE;
766 info->audio_frame_count = 0;
768 sc->ferror_send = FALSE;
769 sc->ferror_count = 0;
770 hcamcorder->error_occurs = FALSE;
771 sc->bget_eos = FALSE;
772 sc->muxed_stream_offset = 0;
774 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
775 if (ret != MM_ERROR_NONE) {
776 /* stop video stream */
777 if (info->record_dual_stream) {
778 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
780 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
782 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
783 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
785 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
787 _mmcam_dbg_err("failed to get camera control");
791 /* Remove recorder pipeline and recording file which size maybe zero */
792 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
793 if (info->filename) {
794 _mmcam_dbg_log("file delete(%s)", info->filename);
795 unlink(info->filename);
797 goto _ERR_CAMCORDER_VIDEO_COMMAND;
800 /*set the camera control to create the GOP so that video record will get a new key frame*/
801 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
802 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
803 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
804 controls = gst_camera_control_list_channels(CameraControl);
805 if (controls != NULL) {
806 for (item = controls ; item && item->data ; item = item->next) {
807 CameraControlChannel = item->data;
808 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
809 if (!strcmp(CameraControlChannel->label, "new-gop")) {
810 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
816 _mmcam_dbg_warn("failed to find new-gop control channel");
819 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
820 sc->info_image->preview_format);
825 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
826 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
827 /* generate and I-frame on resuming */
828 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
829 controls = gst_camera_control_list_channels(CameraControl);
830 if (controls != NULL) {
831 for (item = controls ; item && item->data ; item = item->next) {
832 CameraControlChannel = item->data;
833 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
834 if (!strcmp(CameraControlChannel->label, "new-gop")) {
835 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
841 _mmcam_dbg_warn("failed to find new-gop control channel");
845 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
847 _mmcam_dbg_log("Object property settings done");
851 case _MMCamcorder_CMD_PAUSE:
853 if (info->b_commiting) {
854 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
855 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
858 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
859 if (sc->audio_disable) {
860 /* check only video frame */
861 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
863 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
864 _mmcam_dbg_err("Pause fail, frame count %llu", info->video_frame_count);
865 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
867 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %llu", count, info->video_frame_count);
870 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
872 /* check both of video and audio frame */
873 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
875 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
876 _mmcam_dbg_err("Pause fail, frame count VIDEO[%llu], AUDIO [%llu]",
877 info->video_frame_count, info->audio_frame_count);
878 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
880 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu]",
881 count, info->video_frame_count, info->audio_frame_count);
884 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
888 /* block encodebin */
889 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
892 case _MMCamcorder_CMD_CANCEL:
894 if (info->b_commiting) {
895 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
896 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
899 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
901 if (hcamcorder->capture_in_recording == FALSE) {
903 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
904 _mmcam_dbg_err("Failed to Wait capture data");
905 hcamcorder->capture_in_recording = FALSE;
908 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
911 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
914 /* block push buffer */
915 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
917 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
918 if (ret != MM_ERROR_NONE)
919 goto _ERR_CAMCORDER_VIDEO_COMMAND;
921 /* set recording hint */
922 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
924 /* stop video stream */
925 if (info->record_dual_stream) {
926 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
928 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
930 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
931 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
933 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
935 _mmcam_dbg_err("failed to get camera control");
939 if (info->restart_preview) {
940 /* restart preview */
941 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
942 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
943 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
945 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
947 /* check decoder recreation */
948 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
949 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
950 ret = MM_ERROR_CAMCORDER_INTERNAL;
953 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
954 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
955 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
957 if (ret != MM_ERROR_NONE)
958 goto _ERR_CAMCORDER_VIDEO_COMMAND;
960 /* reset restart_preview for inset window layout */
961 info->restart_preview = FALSE;
963 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
964 ret = MM_ERROR_CAMCORDER_INTERNAL;
965 goto _ERR_CAMCORDER_VIDEO_COMMAND;
968 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
969 if (ret != MM_ERROR_NONE)
970 goto _ERR_CAMCORDER_VIDEO_COMMAND;
973 /* remove target file */
974 if (info->filename) {
975 _mmcam_dbg_log("file delete(%s)", info->filename);
976 unlink(info->filename);
979 sc->isMaxsizePausing = FALSE;
980 sc->isMaxtimePausing = FALSE;
982 sc->display_interval = 0;
983 sc->previous_slot_time = 0;
984 info->video_frame_count = 0;
985 info->audio_frame_count = 0;
987 hcamcorder->capture_in_recording = FALSE;
990 case _MMCamcorder_CMD_COMMIT:
992 if (info->b_commiting) {
993 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
994 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
996 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
997 info->b_commiting = TRUE;
998 sc->bget_eos = FALSE;
1001 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1002 if (sc->audio_disable) {
1003 /* check only video frame */
1004 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1005 hcamcorder->capture_in_recording == FALSE) {
1007 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1008 _mmcam_dbg_err("Commit fail, frame count is %llu, capturing %d",
1009 info->video_frame_count, hcamcorder->capture_in_recording);
1011 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1012 _mmcam_dbg_warn("video frames are enough. keep going...");
1014 info->b_commiting = FALSE;
1015 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1018 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %llu, capturing %d",
1019 count, info->video_frame_count, hcamcorder->capture_in_recording);
1022 /* check both of video and audio frame */
1023 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1024 info->audio_frame_count &&
1025 hcamcorder->capture_in_recording == FALSE) {
1027 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1028 _mmcam_dbg_err("Commit fail, VIDEO[%llu], AUDIO [%llu], capturing %d",
1029 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1031 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1032 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1034 info->b_commiting = FALSE;
1035 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1038 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1040 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%llu], AUDIO [%llu], capturing %d",
1041 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1045 if (hcamcorder->capture_in_recording) {
1046 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1047 if (_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time)) {
1048 _mmcam_dbg_warn("signal received");
1050 _mmcam_dbg_warn("timeout");
1053 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1057 /* block push buffer */
1058 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1059 _mmcam_dbg_log("block push buffer to appsrc");
1061 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1062 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1063 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1065 _mmcam_dbg_err("VIDEO: send EOS failed");
1066 info->b_commiting = FALSE;
1067 ret = MM_ERROR_CAMCORDER_INTERNAL;
1068 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1071 _mmcam_dbg_err("No video stream source");
1072 info->b_commiting = FALSE;
1073 ret = MM_ERROR_CAMCORDER_INTERNAL;
1074 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1077 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1078 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1079 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1081 _mmcam_dbg_err("AUDIO: send EOS failed");
1082 info->b_commiting = FALSE;
1083 ret = MM_ERROR_CAMCORDER_INTERNAL;
1084 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1087 _mmcam_dbg_log("No audio stream");
1091 sc->display_interval = 0;
1092 sc->previous_slot_time = 0;
1095 _mmcam_dbg_log("Start to wait EOS");
1096 ret = _mmcamcorder_get_eos_message(handle);
1097 if (ret != MM_ERROR_NONE) {
1098 info->b_commiting = FALSE;
1099 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1103 hcamcorder->capture_in_recording = FALSE;
1107 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1108 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1111 return MM_ERROR_NONE;
1113 _ERR_CAMCORDER_VIDEO_COMMAND:
1114 if (command == _MMCamcorder_CMD_RECORD)
1115 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1121 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1123 int ret = MM_ERROR_NONE;
1125 guint64 file_size = 0;
1127 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1128 _MMCamcorderSubContext *sc = NULL;
1129 _MMCamcorderVideoInfo *info = NULL;
1130 _MMCamcorderMsgItem msg;
1131 MMCamRecordingReport *report = NULL;
1133 mmf_return_val_if_fail(hcamcorder, FALSE);
1135 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1136 mmf_return_val_if_fail(sc, FALSE);
1137 mmf_return_val_if_fail(sc->info_video, FALSE);
1139 info = sc->info_video;
1143 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1144 /* Play record stop sound */
1145 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1147 _mmcam_dbg_warn("Play stop sound through pulseaudio");
1149 _mmcamcorder_sound_init(handle);
1151 _mmcamcorder_sound_play((MMHandleType)hcamcorder, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, TRUE);
1153 _mmcamcorder_sound_finalize(handle);
1156 /* remove blocking part */
1157 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1159 mm_camcorder_get_attributes(handle, NULL,
1160 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1163 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1164 if (ret != MM_ERROR_NONE)
1165 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1167 /* set recording hint */
1168 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1170 /* stop video stream */
1171 if (info->record_dual_stream) {
1172 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1174 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1176 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1177 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1179 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1181 _mmcam_dbg_err("failed to get camera control");
1185 if (enabletag && !(sc->ferror_send)) {
1186 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1188 _mmcam_dbg_log("Writing location information SUCCEEDED !!");
1190 _mmcam_dbg_err("Writing location information FAILED !!");
1194 /* Check file size */
1195 if (info->max_size > 0) {
1196 _mmcamcorder_get_file_size(info->filename, &file_size);
1197 _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte",
1198 info->max_size, file_size);
1200 if (file_size > info->max_size) {
1201 _MMCamcorderMsgItem message;
1202 _mmcam_dbg_err("File size is greater than max size !!");
1203 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1204 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1205 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1209 if (info->restart_preview) {
1211 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1212 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1213 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1215 _mmcam_dbg_log("Set state of pipeline as READY");
1216 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1218 /* check decoder recreation */
1219 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1220 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1221 ret = MM_ERROR_CAMCORDER_INTERNAL;
1225 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1226 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1227 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1229 if (ret != MM_ERROR_NONE) {
1230 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1231 msg.param.code = ret;
1232 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1233 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1236 /* reset restart_preview for inset window layout */
1237 info->restart_preview = FALSE;
1239 /* recover preview size */
1240 _mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height);
1242 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1243 /* Do not return when error is occurred.
1244 Recording file was created successfully, but starting pipeline failed */
1245 if (ret != MM_ERROR_NONE) {
1246 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1247 msg.param.code = ret;
1248 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1249 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1252 _mmcam_dbg_log("No need to restart preview");
1255 /* Send recording report to application */
1256 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1257 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1259 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1261 report->recording_filename = g_strdup(info->filename);
1262 msg.param.data = report;
1264 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1268 sc->pipeline_time = 0;
1270 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1271 sc->isMaxtimePausing = FALSE;
1272 hcamcorder->error_occurs = FALSE;
1274 info->video_frame_count = 0;
1275 info->audio_frame_count = 0;
1277 info->b_commiting = FALSE;
1279 if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_FOCUS) {
1280 /* check recording stop sound */
1281 _mmcamcorder_sound_solo_play_wait(handle);
1284 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1290 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1292 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1293 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1295 _MMCamcorderSubContext *sc = NULL;
1296 _MMCamcorderVideoInfo *videoinfo = NULL;
1297 _MMCamcorderMsgItem msg;
1298 guint64 buffer_size = 0;
1299 guint64 trailer_size = 0;
1300 guint64 max_size = 0;
1302 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1303 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1304 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1306 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1307 videoinfo = sc->info_video;
1309 /* get buffer size */
1310 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1311 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1312 return GST_PAD_PROBE_OK;
1315 buffer_size = mapinfo.size;
1316 gst_buffer_unmap(buffer, &mapinfo);
1318 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1320 g_mutex_lock(&videoinfo->size_check_lock);
1322 if (videoinfo->audio_frame_count == 0) {
1323 videoinfo->filesize += buffer_size;
1324 videoinfo->audio_frame_count++;
1325 g_mutex_unlock(&videoinfo->size_check_lock);
1326 return GST_PAD_PROBE_OK;
1329 if (sc->ferror_send || sc->isMaxsizePausing) {
1330 _mmcam_dbg_warn("Recording is paused, drop frames");
1331 g_mutex_unlock(&videoinfo->size_check_lock);
1332 return GST_PAD_PROBE_DROP;
1335 /* get trailer size */
1336 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1337 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1342 /* check max size of recorded file */
1343 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1344 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1345 GstState pipeline_state = GST_STATE_VOID_PENDING;
1346 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1347 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1348 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1349 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1350 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1352 if (!sc->isMaxsizePausing) {
1353 sc->isMaxsizePausing = TRUE;
1354 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1355 if (pipeline_state == GST_STATE_PLAYING)
1356 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1358 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1359 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1362 g_mutex_unlock(&videoinfo->size_check_lock);
1367 videoinfo->filesize += buffer_size;
1368 videoinfo->audio_frame_count++;
1370 g_mutex_unlock(&videoinfo->size_check_lock);
1372 return GST_PAD_PROBE_OK;
1376 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1381 guint64 free_space = 0;
1382 guint64 buffer_size = 0;
1383 guint64 trailer_size = 0;
1384 guint64 queued_buffer = 0;
1385 guint64 max_size = 0;
1386 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1388 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1390 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1391 _MMCamcorderMsgItem msg;
1392 _MMCamcorderSubContext *sc = NULL;
1393 _MMCamcorderVideoInfo *videoinfo = NULL;
1395 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1396 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1398 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1399 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1400 videoinfo = sc->info_video;
1402 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1403 if (sc->ferror_send) {
1404 _mmcam_dbg_warn("file write error, drop frames");
1405 return GST_PAD_PROBE_DROP;
1408 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1409 buffer_size = mapinfo.size;
1410 gst_buffer_unmap(buffer, &mapinfo);
1412 videoinfo->video_frame_count++;
1413 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1414 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1415 info->video_frame_count); */
1416 g_mutex_lock(&videoinfo->size_check_lock);
1417 videoinfo->filesize += buffer_size;
1418 g_mutex_unlock(&videoinfo->size_check_lock);
1419 return GST_PAD_PROBE_OK;
1422 /* get trailer size */
1423 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1424 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1429 /* check free space */
1430 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1432 _mmcam_dbg_err("Error occured. [%d]", ret);
1433 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1434 sc->ferror_send = TRUE;
1436 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1437 msg.param.code = MM_ERROR_FILE_READ;
1439 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1444 return GST_PAD_PROBE_DROP; /* skip this buffer */
1447 if (free_space == 0) {
1448 /* check storage state */
1449 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1451 _mmcam_dbg_warn("storage state %d", storage_state);
1453 if (storage_state == STORAGE_STATE_REMOVED ||
1454 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1455 _mmcam_dbg_err("storage was removed!");
1457 _MMCAMCORDER_LOCK(hcamcorder);
1459 if (sc->ferror_send == FALSE) {
1460 _mmcam_dbg_err("OUT_OF_STORAGE error");
1462 sc->ferror_send = TRUE;
1464 _MMCAMCORDER_UNLOCK(hcamcorder);
1466 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1467 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1469 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1471 _MMCAMCORDER_UNLOCK(hcamcorder);
1472 _mmcam_dbg_warn("error was already sent");
1475 return GST_PAD_PROBE_DROP;
1479 /* get queued buffer size */
1480 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
1481 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1484 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
1485 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1488 queued_buffer = aq_size + vq_size;
1490 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1491 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1492 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1493 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1494 free_space, trailer_size, buffer_size, queued_buffer);
1496 if (!sc->isMaxsizePausing) {
1497 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1498 sc->isMaxsizePausing = TRUE;
1500 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1501 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1504 return GST_PAD_PROBE_DROP;
1507 g_mutex_lock(&videoinfo->size_check_lock);
1509 /* check max size of recorded file */
1510 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1511 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1512 GstState pipeline_state = GST_STATE_VOID_PENDING;
1513 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1514 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1515 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1516 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1517 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1519 if (!sc->isMaxsizePausing) {
1520 sc->isMaxsizePausing = TRUE;
1521 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1522 if (pipeline_state == GST_STATE_PLAYING)
1523 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1525 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1526 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1529 g_mutex_unlock(&videoinfo->size_check_lock);
1531 return GST_PAD_PROBE_DROP;
1534 videoinfo->filesize += (guint64)buffer_size;
1537 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1540 g_mutex_unlock(&videoinfo->size_check_lock);
1542 return GST_PAD_PROBE_OK;
1546 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1548 guint64 trailer_size = 0;
1549 guint64 rec_pipe_time = 0;
1550 unsigned int remained_time = 0;
1552 GstClockTime b_time;
1554 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1555 _MMCamcorderMsgItem msg;
1556 _MMCamcorderSubContext *sc = NULL;
1557 _MMCamcorderVideoInfo *videoinfo = NULL;
1559 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1561 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1562 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1564 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1565 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1566 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1568 videoinfo = sc->info_video;
1570 b_time = GST_BUFFER_PTS(buffer);
1572 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1574 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1575 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1580 /* check max time */
1581 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1582 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1583 rec_pipe_time, videoinfo->max_time);
1585 if (!sc->isMaxtimePausing) {
1586 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1588 sc->isMaxtimePausing = TRUE;
1590 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1591 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1592 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1593 msg.param.recording_status.remained_time = 0;
1594 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1596 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1597 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1600 return GST_PAD_PROBE_DROP;
1603 /* calculate remained time can be recorded */
1604 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1605 remained_time = videoinfo->max_time - rec_pipe_time;
1606 } else if (videoinfo->max_size > 0) {
1607 long double max_size = (long double)videoinfo->max_size;
1608 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1610 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1613 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1614 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1615 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1616 msg.param.recording_status.remained_time = remained_time;
1617 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1620 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1621 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1624 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1625 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1628 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1629 record_motion_rate, videoinfo->record_drop_count);
1632 /* drop some frame if fast motion */
1633 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1634 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1636 _mmcam_dbg_warn("drop frame");
1638 return GST_PAD_PROBE_DROP;
1641 videoinfo->record_drop_count = 1;
1643 _mmcam_dbg_warn("pass frame");
1647 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1648 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1651 return GST_PAD_PROBE_OK;
1655 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1657 _MMCamcorderMsgItem msg;
1658 guint64 trailer_size = 0;
1659 guint64 rec_pipe_time = 0;
1660 _MMCamcorderSubContext *sc = NULL;
1661 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1662 _MMCamcorderVideoInfo *videoinfo = NULL;
1663 unsigned int remained_time = 0;
1664 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1666 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1667 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1668 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1670 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1671 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1672 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1674 videoinfo = sc->info_video;
1676 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1677 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1678 return GST_PAD_PROBE_OK;
1681 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1683 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4) {
1684 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1689 /* calculate remained time can be recorded */
1690 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1691 remained_time = videoinfo->max_time - rec_pipe_time;
1692 } else if (videoinfo->max_size > 0) {
1693 long double max_size = (long double)videoinfo->max_size;
1694 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1696 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1699 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1700 _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \
1701 rec_pipe_time, videoinfo->max_time);
1703 if (!sc->isMaxtimePausing) {
1704 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1706 sc->isMaxtimePausing = TRUE;
1708 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1709 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1710 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1711 msg.param.recording_status.remained_time = 0;
1712 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1714 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1715 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1718 return GST_PAD_PROBE_DROP;
1721 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1722 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1723 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1724 msg.param.recording_status.remained_time = remained_time;
1725 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1728 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1729 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1732 return GST_PAD_PROBE_OK;
1736 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1738 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1739 double volume = 0.0;
1742 int err = MM_ERROR_UNKNOWN;
1743 char *err_name = NULL;
1744 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1747 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1748 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1750 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1751 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1752 MMCAM_AUDIO_VOLUME, &volume,
1753 MMCAM_AUDIO_FORMAT, &format,
1754 MMCAM_AUDIO_CHANNEL, &channel,
1756 if (err != MM_ERROR_NONE) {
1757 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1758 SAFE_FREE(err_name);
1762 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1764 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1766 /* Set audio stream NULL */
1768 memset(mapinfo.data, 0, mapinfo.size);
1770 /* CALL audio stream callback */
1771 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1772 MMCamcorderAudioStreamDataType stream;
1774 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1775 _mmcam_dbg_warn("Not ready for stream callback");
1776 gst_buffer_unmap(buffer, &mapinfo);
1777 return GST_PAD_PROBE_OK;
1780 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1781 GST_BUFFER_DATA(buffer), width, height, format);*/
1783 stream.data = (void *)mapinfo.data;
1784 stream.format = format;
1785 stream.channel = channel;
1786 stream.length = mapinfo.size;
1787 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1789 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1791 if (hcamcorder->astream_cb)
1792 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1794 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1797 gst_buffer_unmap(buffer, &mapinfo);
1798 return GST_PAD_PROBE_OK;
1802 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1804 gboolean bret = FALSE;
1806 switch (fileformat) {
1807 case MM_FILE_FORMAT_3GP:
1808 case MM_FILE_FORMAT_MP4:
1809 bret = __mmcamcorder_add_metadata_mp4(handle);
1812 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1820 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1824 guint64 udta_size = 0;
1825 gint64 current_pos = 0;
1826 gint64 moov_pos = 0;
1827 gint64 udta_pos = 0;
1828 gdouble longitude = 0;
1829 gdouble latitude = 0;
1830 gdouble altitude = 0;
1832 int orientation = 0;
1834 char *err_name = NULL;
1835 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1836 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1837 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1839 _MMCamcorderVideoInfo *info = NULL;
1840 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1841 _MMCamcorderSubContext *sc = NULL;
1843 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1844 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1846 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1847 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1851 info = sc->info_video;
1853 f = fopen64(info->filename, "rb+");
1855 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1856 _mmcam_dbg_err("file open failed [%s]", err_msg);
1860 mm_camcorder_get_attributes(handle, &err_name,
1861 MMCAM_TAG_LATITUDE, &latitude,
1862 MMCAM_TAG_LONGITUDE, &longitude,
1863 MMCAM_TAG_ALTITUDE, &altitude,
1864 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1865 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1868 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1869 SAFE_FREE(err_name);
1872 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1873 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1874 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1875 geo_info.longitude = longitude *10000;
1876 geo_info.latitude = latitude *10000;
1877 geo_info.altitude = altitude *10000;
1878 /* find udta container.
1879 if, there are udta container, write loci box after that
1880 else, make udta container and write loci box. */
1881 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1884 _mmcam_dbg_log("find udta container");
1887 if (fseek(f, -8L, SEEK_CUR) != 0)
1890 udta_pos = ftello(f);
1894 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1896 _mmcam_dbg_log("recorded file fread %d", nread);
1898 udta_size = _mmcamcorder_get_container_size(buf);
1900 /* goto end of udta and write 'loci' box */
1901 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1905 if (!_mmcamcorder_write_loci(f, location_info)) {
1906 _mmcam_dbg_err("failed to write loci");
1910 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1911 _mmcam_dbg_err("failed to write geodata");
1916 current_pos = ftello(f);
1917 if (current_pos < 0)
1920 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1923 _mmcam_dbg_log("No udta container");
1924 if (fseek(f, 0, SEEK_END) != 0)
1927 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1928 _mmcam_dbg_err("failed to write udta");
1933 /* find moov container.
1934 update moov container size. */
1935 if ((current_pos = ftello(f)) < 0)
1938 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1939 gint64 internal_pos = ftello(f);
1941 _mmcam_dbg_log("found moov container");
1942 if (fseek(f, -8L, SEEK_CUR) != 0)
1945 moov_pos = ftello(f);
1949 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
1952 /* add orientation info */
1953 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1954 _mmcam_dbg_err("fseek failed : errno %d", errno);
1958 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
1959 _mmcam_dbg_err("failed to find [trak] tag");
1963 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
1964 _mmcam_dbg_err("failed to find [tkhd] tag");
1968 _mmcam_dbg_log("found [tkhd] tag");
1970 /* seek to start position of composition matrix */
1971 fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR);
1973 /* update composition matrix for orientation */
1974 _mmcamcorder_update_composition_matrix(f, orientation);
1976 _mmcam_dbg_err("No 'moov' container");
1988 _mmcam_dbg_err("ftell() returns negative value.");
1994 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
1996 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1997 _MMCamcorderSubContext *sc = NULL;
1999 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2001 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2002 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2004 /* check video source element */
2005 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2006 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2007 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2008 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2009 G_CALLBACK(__mmcamcorder_video_stream_cb),
2011 return MM_ERROR_NONE;
2013 _mmcam_dbg_err("videosrc element is not created yet");
2014 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2019 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2021 int ret = MM_ERROR_NONE;
2023 _MMCamcorderVideoInfo *info = NULL;
2024 _MMCamcorderSubContext *sc = NULL;
2025 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2027 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2029 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2030 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2031 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2033 info = sc->info_video;
2035 _mmcam_dbg_warn("start");
2037 /* create encoding pipeline */
2038 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2039 if (ret != MM_ERROR_NONE)
2040 goto _ERR_PREPARE_RECORD;
2042 if (info->filename == NULL) {
2043 char *temp_filename = NULL;
2046 mm_camcorder_get_attributes(handle, NULL,
2047 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2050 info->filename = g_strdup(temp_filename);
2052 if (!info->filename) {
2053 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2054 goto _ERR_PREPARE_RECORD;
2058 _mmcam_dbg_log("Record file name [%s]", info->filename);
2060 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2061 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2063 /* Adjust display FPS */
2064 sc->display_interval = 0;
2065 sc->previous_slot_time = 0;
2067 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2068 if (ret != MM_ERROR_NONE)
2069 goto _ERR_PREPARE_RECORD;
2071 _mmcam_dbg_warn("done");
2075 _ERR_PREPARE_RECORD:
2076 /* Remove recorder pipeline and recording file which size maybe zero */
2077 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2078 if (info && info->filename) {
2079 _mmcam_dbg_log("file delete(%s)", info->filename);
2080 unlink(info->filename);