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/allocators/gsttizenmemory.h>
26 #include <gst/video/cameracontrol.h>
27 #include <gst/app/gstappsrc.h>
28 #include "mm_camcorder_internal.h"
29 #include "mm_camcorder_videorec.h"
31 /*---------------------------------------------------------------------------------------
32 | LOCAL VARIABLE DEFINITIONS for internal |
33 ---------------------------------------------------------------------------------------*/
34 #define _MMCAMCORDER_MINIMUM_FRAME 5
35 #define _MMCAMCORDER_RETRIAL_COUNT 15
36 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* us */
37 #define _MMCAMCORDER_FRAME_PASS_MIN_FPS 30
38 #define _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME 30000000 /* ns */
39 #define _MMCAMCORDER_VIDEO_MINIMUM_SPACE (_MMCAMCORDER_MINIMUM_SPACE << 1) /* byte */
40 #define OFFSET_COMPOSITION_MATRIX 40L
41 #define MAX_ERROR_MESSAGE_LEN 128
43 /*---------------------------------------------------------------------------------------
44 | LOCAL FUNCTION PROTOTYPES: |
45 ---------------------------------------------------------------------------------------*/
46 /* STATIC INTERNAL FUNCTION */
47 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
48 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
49 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
54 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
56 /*=======================================================================================
57 | FUNCTION DEFINITIONS |
58 =======================================================================================*/
59 /*---------------------------------------------------------------------------------------
60 | GLOBAL FUNCTION DEFINITIONS: |
61 ---------------------------------------------------------------------------------------*/
62 gboolean _mmcamcorder_video_push_buffer(void *handle, GstSample *sample)
64 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
65 _MMCamcorderSubContext *sc = NULL;
66 _MMCamcorderImageInfo *info_image = NULL;
67 _MMCamcorderVideoInfo *info_video = NULL;
68 _MMCamcorderGstElement *element = NULL;
69 GstClockTime current_ts = 0; /* nsec */
70 GstBuffer *buffer = NULL;
72 mmf_return_val_if_fail(hcamcorder, FALSE);
73 mmf_return_val_if_fail(MMF_CAMCORDER_SUBCONTEXT(hcamcorder), FALSE);
75 buffer = gst_sample_get_buffer(sample);
77 mmf_return_val_if_fail(buffer, FALSE);
78 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
80 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
82 mmf_return_val_if_fail(sc->info_image, FALSE);
83 mmf_return_val_if_fail(sc->info_video, FALSE);
84 mmf_return_val_if_fail(sc->encode_element, FALSE);
86 info_image = sc->info_image;
87 info_video = sc->info_video;
88 element = sc->encode_element;
90 if (info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
91 element[_MMCAMCORDER_ENCSINK_SRC].gst) {
93 GstClock *clock = NULL;
95 MMCAM_LOG_VERBOSE("GST_BUFFER_FLAG_DELTA_UNIT is set : %d",
96 GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT));
98 current_ts = GST_BUFFER_PTS(buffer);
100 if (info_video->is_first_frame) {
101 /* check first I frame for H.264 stream */
102 if (_mmcamcorder_is_encoded_preview_pixel_format(info_image->preview_format)) {
103 if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
104 MMCAM_LOG_WARNING("NOT key frame.. skip this buffer");
107 MMCAM_LOG_WARNING("first key frame");
111 /* set base timestamp */
112 if (element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
113 clock = GST_ELEMENT_CLOCK(element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
115 gst_object_ref(clock);
116 info_video->base_video_ts = current_ts - (gst_clock_get_time(clock) - \
117 GST_ELEMENT(element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
118 gst_object_unref(clock);
121 /* for image capture with encodebin and v4l2src */
122 if (sc->bencbin_capture && info_image->capturing) {
123 g_mutex_lock(&hcamcorder->task_thread_lock);
124 MMCAM_LOG_INFO("send signal for sound play");
125 hcamcorder->task_thread_state = _MMCAMCORDER_TASK_THREAD_STATE_SOUND_SOLO_PLAY_START;
126 g_cond_signal(&hcamcorder->task_thread_cond);
127 g_mutex_unlock(&hcamcorder->task_thread_lock);
129 info_video->base_video_ts = current_ts;
132 if (_mmcamcorder_invoke_video_stream_cb(handle, sample, FALSE, -1) == FALSE) {
133 /* increase base video timestamp by frame duration,
134 it will remove delay of dropped buffer when play recorded file. */
135 info_video->base_video_ts += current_ts - info_video->last_video_ts;
136 MMCAM_LOG_DEBUG("do not push buffer to encode by app's return value");
137 goto _VIDEO_PUSH_BUFFER_DONE;
141 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer) = current_ts - info_video->base_video_ts;
143 MMCAM_LOG_DEBUG("buffer %p, timestamp %"GST_TIME_FORMAT,
144 buffer, GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));
146 if (info_video->record_dual_stream) {
147 /* It will NOT INCREASE reference count of buffer */
148 ret = gst_app_src_push_buffer((GstAppSrc *)element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
150 /* It will INCREASE reference count of buffer */
151 g_signal_emit_by_name(element[_MMCAMCORDER_ENCSINK_SRC].gst, "push-buffer", buffer, &ret);
154 MMCAM_LOG_VERBOSE("push buffer result : 0x%x", ret);
156 _VIDEO_PUSH_BUFFER_DONE:
157 info_video->last_video_ts = current_ts;
159 if (info_video->is_first_frame) {
160 info_video->is_first_frame = FALSE;
162 /* drop buffer if it's from tizen allocator */
163 if (gst_is_tizen_memory(gst_buffer_peek_memory(buffer, 0))) {
164 MMCAM_LOG_WARNING("drop first buffer from tizen allocator to avoid copy in basesrc");
170 /* skip display if too fast FPS */
171 if (info_video->record_dual_stream == FALSE &&
172 info_video->fps > _MMCAMCORDER_FRAME_PASS_MIN_FPS) {
173 if (info_video->prev_preview_ts != 0) {
174 if (GST_BUFFER_PTS(buffer) - info_video->prev_preview_ts < _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME) {
175 MMCAM_LOG_VERBOSE("it's too fast. drop frame...");
180 MMCAM_LOG_VERBOSE("display buffer [%p]", buffer);
182 info_video->prev_preview_ts = GST_BUFFER_PTS(buffer);
189 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
191 mmf_return_if_fail(sample);
193 /* no need to check return value here */
194 _mmcamcorder_video_push_buffer(u_data, sample);
196 gst_sample_unref(sample);
200 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
203 int err = MM_ERROR_NONE;
204 const char* gst_element_rsink_name = NULL;
207 GstPad *srcpad = NULL;
208 GstPad *sinkpad = NULL;
210 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
211 _MMCamcorderSubContext *sc = NULL;
213 type_element *RecordsinkElement = NULL;
215 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
217 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
218 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
219 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
221 MMCAM_LOG_WARNING("start");
223 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
224 if (err != MM_ERROR_NONE)
228 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
229 MMCAM_LOG_INFO("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
230 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
231 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
234 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
236 /* get audio disable */
237 mm_camcorder_get_attributes(handle, NULL,
238 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
241 MMCAM_LOG_INFO("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d, ved_cb %p",
242 sc->audio_disable, sc->is_modified_rate, hcamcorder->vedecision_cb);
244 if (sc->is_modified_rate || hcamcorder->vedecision_cb)
245 sc->audio_disable = TRUE;
247 if (sc->audio_disable == FALSE) {
248 /* create audiosrc bin */
249 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
250 if (err != MM_ERROR_NONE)
254 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
255 if (err != MM_ERROR_NONE)
258 if (sc->audio_disable == FALSE) {
259 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
260 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
263 /* add elements and encodesink bin to encode main pipeline */
264 if (sc->info_video->use_videoscale) {
265 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
266 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
267 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
268 sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst,
269 sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst,
270 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
273 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
274 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
275 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
276 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
280 /* Link each element : appsrc - capsfilter - encodesink bin */
281 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
282 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
283 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
285 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
286 if (sc->info_video->use_videoscale) {
287 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst, "sink");
288 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
290 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst, "src");
291 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, "sink");
292 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
294 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, "src");
296 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
297 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
299 if (sc->audio_disable == FALSE) {
300 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
301 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
302 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
305 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
306 CONFIGURE_CATEGORY_MAIN_RECORD,
309 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
311 if (!gst_element_rsink_name) {
312 MMCAM_LOG_ERROR("failed to get recordsink name");
313 err = MM_ERROR_CAMCORDER_INTERNAL;
314 goto pipeline_creation_error;
317 /* set data probe function */
319 /* register message cb */
321 /* set data probe functions */
322 if (sc->audio_disable == FALSE) {
323 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
324 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
325 __mmcamcorder_audioque_dataprobe, hcamcorder);
326 gst_object_unref(sinkpad);
330 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
331 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
332 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
333 gst_object_unref(srcpad);
336 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
337 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
338 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
339 __mmcamcorder_eventprobe_monitor, hcamcorder);
340 gst_object_unref(srcpad);
345 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
346 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
347 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
348 __mmcamcorder_eventprobe_monitor, hcamcorder);
349 gst_object_unref(srcpad);
353 if (sc->audio_disable) {
354 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
355 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
356 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
357 gst_object_unref(sinkpad);
361 if (!strcmp(gst_element_rsink_name, "filesink")) {
362 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
363 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
364 __mmcamcorder_video_dataprobe_encoded, hcamcorder);
365 gst_object_unref(srcpad);
368 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
369 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
370 __mmcamcorder_audio_dataprobe_check, hcamcorder);
371 gst_object_unref(srcpad);
375 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
376 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
377 __mmcamcorder_muxed_dataprobe, hcamcorder);
378 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
379 __mmcamcorder_eventprobe_monitor, hcamcorder);
380 gst_object_unref(sinkpad);
383 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
385 /* set sync handler */
386 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
388 gst_object_unref(bus);
391 return MM_ERROR_NONE;
393 pipeline_creation_error:
394 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
395 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
397 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
402 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
404 GstPad *srcpad = NULL;
405 GstPad *sinkpad = NULL;
406 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
407 _MMCamcorderSubContext *sc = NULL;
409 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
411 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
412 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
413 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
417 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
418 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
419 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
420 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
422 /* release audiosrc bin */
423 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
424 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
427 To avoid conflicting between old elements and newly created elements,
428 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
429 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
430 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
431 It's because the pipeline of audio recording destroys at the same time,
432 and '_mmcamcorder_element_release_noti' will perfom removing handle.
434 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
436 MMCAM_LOG_INFO("Audio pipeline removed");
439 return MM_ERROR_NONE;
443 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
445 GstPad *reqpad = NULL;
446 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
447 _MMCamcorderSubContext *sc = NULL;
448 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
449 int ret = MM_ERROR_NONE;
450 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
452 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
454 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
455 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
456 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
460 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
461 /* release request pad */
462 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
464 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
465 gst_object_unref(reqpad);
469 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
471 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
472 gst_object_unref(reqpad);
476 /* release encode main pipeline */
477 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
480 To avoid conflicting between old elements and newly created elements,
481 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
482 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
483 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
484 It's because the pipeline of audio recording destroys at the same time,
485 and '_mmcamcorder_element_release_noti' will perfom removing handle.
487 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
488 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
490 MMCAM_LOG_WARNING("Encoder pipeline removed");
492 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
493 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
495 MMCAM_LOG_WARNING("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
497 if (hcamcorder->is_release_cb_calling == FALSE) {
498 /* release resource */
499 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
500 hcamcorder->video_encoder_resource);
501 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
502 hcamcorder->video_encoder_resource = NULL;
504 MMCAM_LOG_WARNING("mark resource for release 0x%x", ret);
506 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
508 MMCAM_LOG_WARNING("commit resource release 0x%x", ret);
511 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
513 MMCAM_LOG_WARNING("unlock resource");
514 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
517 return MM_ERROR_NONE;
521 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
523 int ret = MM_ERROR_NONE;
524 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
525 _MMCamcorderSubContext *sc = NULL;
529 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
530 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
531 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
533 MMCAM_LOG_INFO("start");
535 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
536 MMCAM_LOG_WARNING("pipeline is not existed.");
537 return MM_ERROR_NONE;
540 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
542 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
543 if (ret != MM_ERROR_NONE) {
544 MMCAM_LOG_ERROR("Failed to change encode main pipeline [0x%x]", ret);
548 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
550 /* remove audio pipeline first */
551 ret = _mmcamcorder_remove_audio_pipeline(handle);
552 if (ret != MM_ERROR_NONE) {
553 MMCAM_LOG_ERROR("Fail to remove audio pipeline");
557 ret = _mmcamcorder_remove_encode_pipeline(handle);
558 if (ret != MM_ERROR_NONE) {
559 MMCAM_LOG_ERROR("Fail to remove encoder pipeline");
563 /* Remove remained message */
565 GstMessage *gst_msg = NULL;
566 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
567 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
568 gst_message_unref(gst_msg);
571 gst_object_unref(bus);
575 MMCAM_LOG_INFO("done");
581 int _mmcamcorder_video_command(MMHandleType handle, int command)
586 int gop_interval = 0;
587 int ret = MM_ERROR_NONE;
588 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
589 char *err_name = NULL;
590 char *target_filename = NULL;
591 GstCameraControl *CameraControl = NULL;
594 GstElement *pipeline = NULL;
596 _MMCamcorderVideoInfo *info = NULL;
597 _MMCamcorderSubContext *sc = NULL;
598 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
600 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
602 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
603 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
604 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
605 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
607 info = sc->info_video;
609 MMCAM_LOG_INFO("Command(%d)", command);
611 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
614 case _MMCamcorder_CMD_RECORD:
616 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
620 gboolean storage_validity = FALSE;
623 int root_directory_length = 0;
626 MMCAM_LOG_INFO("Record Start - dual stream %d", info->support_dual_stream);
628 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
629 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
631 /* prepare resource manager for H/W encoder */
632 if (hcamcorder->video_encoder_resource == NULL) {
633 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
634 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
635 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
636 &hcamcorder->video_encoder_resource);
637 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
638 MMCAM_LOG_ERROR("could not prepare for encoder resource");
639 ret = MM_ERROR_RESOURCE_INTERNAL;
640 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
641 goto _ERR_CAMCORDER_VIDEO_COMMAND;
644 MMCAM_LOG_INFO("encoder already acquired");
647 /* acquire resources */
648 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
649 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
650 MMCAM_LOG_ERROR("could not acquire resources");
651 ret = MM_ERROR_RESOURCE_INTERNAL;
652 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
653 goto _ERR_CAMCORDER_VIDEO_COMMAND;
656 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
657 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
659 /* init record_dual_stream */
660 info->record_dual_stream = FALSE;
662 ret = mm_camcorder_get_attributes(handle, &err_name,
663 MMCAM_CAMERA_FPS, &fps,
664 MMCAM_CAMERA_WIDTH, &(info->preview_width),
665 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
666 MMCAM_VIDEO_WIDTH, &(info->video_width),
667 MMCAM_VIDEO_HEIGHT, &(info->video_height),
668 MMCAM_FILE_FORMAT, &fileformat,
669 MMCAM_TARGET_FILENAME, &target_filename, &size,
670 MMCAM_TARGET_MAX_SIZE, &imax_size,
671 MMCAM_TARGET_TIME_LIMIT, &imax_time,
672 MMCAM_FILE_FORMAT, &(info->fileformat),
673 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
674 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
676 if (ret != MM_ERROR_NONE) {
677 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, ret);
679 goto _ERR_CAMCORDER_VIDEO_COMMAND;
682 if (!target_filename && !hcamcorder->mstream_cb) {
683 MMCAM_LOG_ERROR("filename is not set and muxed stream cb is NULL");
684 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
685 goto _ERR_CAMCORDER_VIDEO_COMMAND;
690 info->max_size = 0; /* do not check */
692 info->max_size = ((guint64)imax_size) << 10; /* to byte */
696 info->max_time = 0; /* do not check */
698 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
700 ret = _mmcamcorder_get_storage_validity(hcamcorder, target_filename,
701 _MMCAMCORDER_VIDEO_MINIMUM_SPACE, &storage_validity);
702 if (ret != MM_ERROR_NONE) {
703 MMCAM_LOG_ERROR("storage validation failed[0x%x]:%d", ret, storage_validity);
707 _mmcamcorder_adjust_recording_max_size(target_filename, &info->max_size);
709 g_mutex_lock(&hcamcorder->task_thread_lock);
710 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
711 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
712 /* Play record start sound */
713 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
715 g_mutex_unlock(&hcamcorder->task_thread_lock);
717 MMCAM_LOG_WARNING("video size [%dx%d]", info->video_width, info->video_height);
719 if (info->video_width == 0 || info->video_height == 0) {
720 MMCAM_LOG_WARNING("video size is invalid [%dx%d] use preview size [%dx%d]",
721 info->video_width, info->video_height, info->preview_width, info->preview_height);
722 info->video_width = info->preview_width;
723 info->video_height = info->preview_height;
726 if (info->support_dual_stream) {
727 MMCAM_LOG_WARNING("DUAL STREAM MODE");
729 info->record_dual_stream = TRUE;
731 /* No need to restart preview */
732 info->restart_preview = FALSE;
734 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
735 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
736 } else if (_mmcamcorder_is_encoded_preview_pixel_format(sc->info_image->preview_format) &&
737 info->preview_width == info->video_width &&
738 info->preview_height == info->video_height) {
739 MMCAM_LOG_INFO("Encoded[%d] preview mode and same resolution", sc->info_image->preview_format);
740 /* No need to restart preview */
741 info->restart_preview = FALSE;
742 } else if (info->use_videoscale &&
743 info->preview_width >= info->video_width &&
744 info->preview_height >= info->video_height) {
745 info->restart_preview = FALSE;
747 info->restart_preview = TRUE;
748 /* reset use_videoscale */
749 info->use_videoscale = FALSE;
752 /* set recording hint */
753 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
755 if (info->restart_preview) {
756 /* stop preview and set new size */
757 MMCAM_LOG_INFO("restart preview");
759 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
760 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
761 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
763 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
765 /* check decoder recreation */
766 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
767 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
768 ret = MM_ERROR_CAMCORDER_INTERNAL;
769 goto _ERR_CAMCORDER_VIDEO_COMMAND;
772 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
773 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
774 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
776 if (ret != MM_ERROR_NONE)
777 goto _ERR_CAMCORDER_VIDEO_COMMAND;
779 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
780 ret = MM_ERROR_CAMCORDER_INTERNAL;
781 goto _ERR_CAMCORDER_VIDEO_COMMAND;
784 /* Start preview again with new setting */
785 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
786 if (ret != MM_ERROR_NONE)
787 goto _ERR_CAMCORDER_VIDEO_COMMAND;
789 if (motion_rate < 1.0) {
790 MMCAM_LOG_WARNING("wait for stabilization of frame");
794 MMCAM_LOG_INFO("no need to restart preview");
797 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
798 CONFIGURE_CATEGORY_MAIN_RECORD,
802 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
803 CONFIGURE_CATEGORY_MAIN_RECORD,
804 "PassFirstVideoFrame",
805 &(sc->pass_first_vframe));
807 MMCAM_LOG_INFO("Drop video frame count[%d], Pass fisrt video frame count[%d]",
808 sc->drop_vframe, sc->pass_first_vframe);
810 info->record_drop_count = (guint)motion_rate;
811 info->record_motion_rate = motion_rate;
812 if (sc->is_modified_rate)
813 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
815 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
817 MMCAM_LOG_WARNING("recording fps %d, motion rate %f, timestamp_ratio %f",
818 fps, info->record_motion_rate, info->record_timestamp_ratio);
820 /* set push buffer flag */
821 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
822 info->base_video_ts = 0;
824 /* connect video stream cb signal if it supports dual stream. */
825 if (info->record_dual_stream) {
826 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
827 goto _ERR_CAMCORDER_VIDEO_COMMAND;
830 /* start video stream */
831 if (info->record_dual_stream) {
832 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
834 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
836 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
837 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
839 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
841 MMCAM_LOG_ERROR("could not get camera control");
845 /* check pre-created encode pipeline */
846 g_mutex_lock(&hcamcorder->task_thread_lock);
847 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
848 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
849 /* create encoding pipeline */
850 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
851 if (ret != MM_ERROR_NONE) {
852 g_mutex_unlock(&hcamcorder->task_thread_lock);
853 goto _ERR_CAMCORDER_VIDEO_COMMAND;
856 g_mutex_unlock(&hcamcorder->task_thread_lock);
858 /* check recording start sound */
859 _mmcamcorder_sound_solo_play_wait(handle);
861 /**< To fix video recording hanging
862 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
863 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
864 basetime wouldn't change if you set (GstClockTime)0.
865 3. Move set start time position below PAUSED of pipeline.
868 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
869 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
872 info->video_frame_count = 0;
873 info->is_first_frame = TRUE;
874 info->audio_frame_count = 0;
876 sc->ferror_send = FALSE;
877 sc->ferror_count = 0;
878 hcamcorder->error_occurs = FALSE;
879 sc->bget_eos = FALSE;
880 sc->muxed_stream_offset = 0;
882 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
883 if (ret != MM_ERROR_NONE) {
884 /* stop video stream */
885 if (info->record_dual_stream) {
886 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
888 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
890 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
891 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
893 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
895 MMCAM_LOG_ERROR("failed to get camera control");
899 /* Remove recorder pipeline and recording file which size maybe zero */
900 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
901 if (info->filename) {
902 MMCAM_LOG_INFO("file delete(%s)", info->filename);
903 unlink(info->filename);
905 goto _ERR_CAMCORDER_VIDEO_COMMAND;
908 /*set the GOP so that video record will get a new key frame*/
909 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
910 if (mm_camcorder_get_attributes(handle, NULL,
911 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
912 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
914 MMCAM_LOG_ERROR("get gop interval failed");
918 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
919 if (mm_camcorder_get_attributes(handle, NULL,
920 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
921 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
923 MMCAM_LOG_ERROR("get gop interval failed");
926 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
928 MMCAM_LOG_INFO("Object property settings done");
932 case _MMCamcorder_CMD_PAUSE:
934 if (info->b_committing) {
935 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
936 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
939 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
940 if (sc->audio_disable) {
941 /* check only video frame */
942 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
944 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
945 MMCAM_LOG_ERROR("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
946 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
948 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
951 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
953 /* check both of video and audio frame */
954 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
956 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
957 MMCAM_LOG_ERROR("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
958 info->video_frame_count, info->audio_frame_count);
959 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
961 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
962 count, info->video_frame_count, info->audio_frame_count);
965 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
969 /* block encodebin */
970 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
973 case _MMCamcorder_CMD_CANCEL:
975 if (info->b_committing) {
976 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
977 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
980 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
982 if (hcamcorder->capture_in_recording == FALSE) {
984 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
985 MMCAM_LOG_ERROR("Failed to Wait capture data");
986 hcamcorder->capture_in_recording = FALSE;
989 MMCAM_LOG_WARNING("Waiting for capture data - retrial [%d]", count);
992 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
995 /* block push buffer */
996 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
998 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
999 if (ret != MM_ERROR_NONE)
1000 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1002 /* set recording hint */
1003 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1005 /* stop video stream */
1006 if (info->record_dual_stream) {
1007 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1008 if (CameraControl) {
1009 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1011 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1012 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1014 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1016 MMCAM_LOG_ERROR("failed to get camera control");
1020 if (info->restart_preview) {
1021 /* restart preview */
1022 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1023 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1024 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1026 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1028 /* check decoder recreation */
1029 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1030 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1031 ret = MM_ERROR_CAMCORDER_INTERNAL;
1034 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1035 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1036 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1038 if (ret != MM_ERROR_NONE)
1039 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1041 /* reset restart_preview for inset window layout */
1042 info->restart_preview = FALSE;
1044 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1045 ret = MM_ERROR_CAMCORDER_INTERNAL;
1046 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1049 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1050 if (ret != MM_ERROR_NONE)
1051 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1054 /* remove target file */
1055 if (info->filename) {
1056 MMCAM_LOG_INFO("file delete(%s)", info->filename);
1057 unlink(info->filename);
1060 sc->isMaxsizePausing = FALSE;
1061 sc->isMaxtimePausing = FALSE;
1063 sc->display_interval = 0;
1064 sc->previous_slot_time = 0;
1065 info->video_frame_count = 0;
1066 info->audio_frame_count = 0;
1068 hcamcorder->capture_in_recording = FALSE;
1071 case _MMCamcorder_CMD_COMMIT:
1075 if (info->b_committing) {
1076 MMCAM_LOG_ERROR("now on committing previous file!!(command : %d)", command);
1077 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1079 MMCAM_LOG_INFO("_MMCamcorder_CMD_COMMIT : start");
1080 info->b_committing = TRUE;
1081 sc->bget_eos = FALSE;
1084 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1085 if (sc->audio_disable) {
1086 /* check only video frame */
1087 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1088 hcamcorder->capture_in_recording == FALSE) {
1090 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1091 MMCAM_LOG_ERROR("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1092 info->video_frame_count, hcamcorder->capture_in_recording);
1094 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1095 MMCAM_LOG_WARNING("video frames are enough. keep going...");
1097 info->b_committing = FALSE;
1098 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1101 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1102 count, info->video_frame_count, hcamcorder->capture_in_recording);
1105 /* check both of video and audio frame */
1106 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1107 info->audio_frame_count &&
1108 hcamcorder->capture_in_recording == FALSE) {
1110 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1111 MMCAM_LOG_ERROR("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1112 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1114 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1115 MMCAM_LOG_WARNING("video/audio frames are enough. keep going...");
1117 info->b_committing = FALSE;
1118 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1121 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1123 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1124 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1128 if (hcamcorder->capture_in_recording) {
1129 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1130 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1131 MMCAM_LOG_WARNING("timeout");
1133 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1137 /* block push buffer */
1138 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1139 MMCAM_LOG_INFO("block push buffer to appsrc");
1141 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1142 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1143 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1144 ret = MM_ERROR_OUT_OF_STORAGE;
1145 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1148 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1149 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1150 MMCAM_LOG_WARNING("VIDEO: send eos to appsrc done");
1152 MMCAM_LOG_ERROR("VIDEO: send EOS failed");
1153 info->b_committing = FALSE;
1154 ret = MM_ERROR_CAMCORDER_INTERNAL;
1155 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1158 MMCAM_LOG_ERROR("No video stream source");
1159 info->b_committing = FALSE;
1160 ret = MM_ERROR_CAMCORDER_INTERNAL;
1161 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1164 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1165 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1166 MMCAM_LOG_WARNING("AUDIO: send eos to audiosrc done");
1168 MMCAM_LOG_ERROR("AUDIO: send EOS failed");
1169 info->b_committing = FALSE;
1170 ret = MM_ERROR_CAMCORDER_INTERNAL;
1171 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1174 MMCAM_LOG_INFO("No audio stream");
1178 sc->display_interval = 0;
1179 sc->previous_slot_time = 0;
1182 MMCAM_LOG_INFO("Start to wait EOS");
1183 ret = _mmcamcorder_get_eos_message(handle);
1184 if (ret != MM_ERROR_NONE) {
1185 info->b_committing = FALSE;
1186 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1190 hcamcorder->capture_in_recording = FALSE;
1194 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1195 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1198 return MM_ERROR_NONE;
1200 _ERR_CAMCORDER_VIDEO_COMMAND:
1201 if (command == _MMCamcorder_CMD_RECORD)
1202 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1208 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1210 int ret = MM_ERROR_NONE;
1212 guint64 file_size = 0;
1214 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1215 _MMCamcorderSubContext *sc = NULL;
1216 _MMCamcorderVideoInfo *info = NULL;
1217 _MMCamcorderMsgItem msg;
1218 MMCamRecordingReport *report = NULL;
1220 mmf_return_val_if_fail(hcamcorder, FALSE);
1222 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1223 mmf_return_val_if_fail(sc, FALSE);
1224 mmf_return_val_if_fail(sc->info_video, FALSE);
1226 info = sc->info_video;
1228 MMCAM_LOG_ERROR("");
1230 /* Play record stop sound */
1231 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1233 /* remove blocking part */
1234 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1236 mm_camcorder_get_attributes(handle, NULL,
1237 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1240 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1241 if (ret != MM_ERROR_NONE)
1242 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1244 /* set recording hint */
1245 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1247 /* stop video stream */
1248 if (info->record_dual_stream) {
1249 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1251 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1253 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1254 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1256 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1258 MMCAM_LOG_ERROR("failed to get camera control");
1262 if (enabletag && !(sc->ferror_send)) {
1263 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1264 MMCAM_LOG_INFO("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1267 /* Check file size */
1268 if (info->max_size > 0) {
1269 _mmcamcorder_get_file_size(info->filename, &file_size);
1270 MMCAM_LOG_INFO("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1271 info->max_size, file_size);
1273 if (file_size > info->max_size) {
1274 _MMCamcorderMsgItem message;
1275 MMCAM_LOG_ERROR("File size is greater than max size !!");
1276 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1277 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1278 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1282 if (info->restart_preview) {
1284 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1285 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1286 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1288 MMCAM_LOG_INFO("Set state of pipeline as READY");
1289 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1291 /* check decoder recreation */
1292 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1293 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1294 ret = MM_ERROR_CAMCORDER_INTERNAL;
1298 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1299 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1300 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1302 if (ret != MM_ERROR_NONE) {
1303 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1304 msg.param.code = ret;
1305 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1306 MMCAM_LOG_ERROR("Failed to set state READY[%x]", ret);
1309 /* reset restart_preview for inset window layout */
1310 info->restart_preview = FALSE;
1312 /* recover preview size */
1313 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1314 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1315 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1316 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1317 MMCAM_LOG_ERROR("Failed to set camera resolution %dx%d",
1318 info->preview_width, info->preview_height);
1321 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1322 /* Do not return when error is occurred.
1323 Recording file was created successfully, but starting pipeline failed */
1324 if (ret != MM_ERROR_NONE) {
1325 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1326 msg.param.code = ret;
1327 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1328 MMCAM_LOG_ERROR("Failed to set state PLAYING[%x]", ret);
1331 MMCAM_LOG_INFO("No need to restart preview");
1334 /* Send recording report to application */
1335 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1336 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1337 report->recording_filename = g_strdup(info->filename);
1338 msg.param.data = report;
1340 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1343 sc->pipeline_time = 0;
1345 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1346 sc->isMaxtimePausing = FALSE;
1347 hcamcorder->error_occurs = FALSE;
1349 info->video_frame_count = 0;
1350 info->audio_frame_count = 0;
1352 info->b_committing = FALSE;
1354 /* check recording stop sound */
1355 _mmcamcorder_sound_solo_play_wait(handle);
1357 MMCAM_LOG_ERROR("_MMCamcorder_CMD_COMMIT : end");
1363 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1365 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1366 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1368 _MMCamcorderSubContext *sc = NULL;
1369 _MMCamcorderVideoInfo *videoinfo = NULL;
1370 _MMCamcorderMsgItem msg;
1371 guint64 buffer_size = 0;
1372 guint64 trailer_size = 0;
1373 guint64 max_size = 0;
1375 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1376 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1377 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1379 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1380 videoinfo = sc->info_video;
1382 /* get buffer size */
1383 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1384 MMCAM_LOG_WARNING("map failed : buffer %p", buffer);
1385 return GST_PAD_PROBE_OK;
1388 buffer_size = mapinfo.size;
1389 gst_buffer_unmap(buffer, &mapinfo);
1391 g_mutex_lock(&videoinfo->size_check_lock);
1393 if (videoinfo->audio_frame_count == 0) {
1394 videoinfo->filesize += buffer_size;
1395 videoinfo->audio_frame_count++;
1396 g_mutex_unlock(&videoinfo->size_check_lock);
1397 return GST_PAD_PROBE_OK;
1400 if (sc->ferror_send || sc->isMaxsizePausing) {
1401 MMCAM_LOG_WARNING("Recording is paused, drop frames");
1402 g_mutex_unlock(&videoinfo->size_check_lock);
1403 return GST_PAD_PROBE_DROP;
1406 /* get trailer size */
1407 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1408 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1412 /* check max size of recorded file */
1413 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1414 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1415 GstState pipeline_state = GST_STATE_VOID_PENDING;
1416 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1418 MMCAM_LOG_WARNING("Max size[%"G_GUINT64_FORMAT"], current size[%"G_GUINT64_FORMAT"],"\
1419 " buffer size[%"G_GUINT64_FORMAT"], trailer size[%"G_GUINT64_FORMAT"]",
1420 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1422 if (!sc->isMaxsizePausing) {
1423 sc->isMaxsizePausing = TRUE;
1424 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1425 if (pipeline_state == GST_STATE_PLAYING)
1426 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1428 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1429 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1432 g_mutex_unlock(&videoinfo->size_check_lock);
1437 videoinfo->filesize += buffer_size;
1438 videoinfo->audio_frame_count++;
1440 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1441 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1443 g_mutex_unlock(&videoinfo->size_check_lock);
1445 return GST_PAD_PROBE_OK;
1449 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1454 guint64 free_space = 0;
1455 guint64 buffer_size = 0;
1456 guint64 trailer_size = 0;
1457 guint64 queued_buffer = 0;
1458 guint64 max_size = 0;
1459 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1461 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1463 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1464 _MMCamcorderMsgItem msg;
1465 _MMCamcorderSubContext *sc = NULL;
1466 _MMCamcorderVideoInfo *videoinfo = NULL;
1468 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1469 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1471 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1472 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1473 videoinfo = sc->info_video;
1475 if (sc->ferror_send) {
1476 MMCAM_LOG_WARNING("file write error, drop frames");
1477 return GST_PAD_PROBE_DROP;
1480 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1481 buffer_size = mapinfo.size;
1482 gst_buffer_unmap(buffer, &mapinfo);
1484 videoinfo->video_frame_count++;
1485 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1486 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1487 g_mutex_lock(&videoinfo->size_check_lock);
1488 videoinfo->filesize += buffer_size;
1489 g_mutex_unlock(&videoinfo->size_check_lock);
1490 return GST_PAD_PROBE_OK;
1493 /* get trailer size */
1494 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1495 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1499 /* check free space */
1500 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1502 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1503 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1504 sc->ferror_send = TRUE;
1506 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1507 msg.param.code = MM_ERROR_FILE_READ;
1509 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1514 return GST_PAD_PROBE_DROP; /* skip this buffer */
1517 if (free_space == 0) {
1518 /* check storage state */
1519 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1521 MMCAM_LOG_WARNING("storage state %d", storage_state);
1523 if (storage_state == STORAGE_STATE_REMOVED ||
1524 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1525 MMCAM_LOG_ERROR("storage was removed!");
1527 _MMCAMCORDER_LOCK(hcamcorder);
1529 if (sc->ferror_send == FALSE) {
1530 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1532 sc->ferror_send = TRUE;
1534 _MMCAMCORDER_UNLOCK(hcamcorder);
1536 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1537 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1539 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1541 _MMCAMCORDER_UNLOCK(hcamcorder);
1542 MMCAM_LOG_WARNING("error was already sent");
1545 return GST_PAD_PROBE_DROP;
1549 /* get queued buffer size */
1550 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1551 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1553 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1554 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1556 queued_buffer = aq_size + vq_size;
1558 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1559 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1560 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1561 free_space, trailer_size, buffer_size, queued_buffer);
1563 if (!sc->isMaxsizePausing) {
1564 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1565 sc->isMaxsizePausing = TRUE;
1567 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1568 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1571 return GST_PAD_PROBE_DROP;
1574 g_mutex_lock(&videoinfo->size_check_lock);
1576 /* check max size of recorded file */
1577 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1578 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1579 GstState pipeline_state = GST_STATE_VOID_PENDING;
1580 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1582 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1583 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1584 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1586 if (!sc->isMaxsizePausing) {
1587 sc->isMaxsizePausing = TRUE;
1588 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1589 if (pipeline_state == GST_STATE_PLAYING)
1590 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1592 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1593 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1596 g_mutex_unlock(&videoinfo->size_check_lock);
1598 return GST_PAD_PROBE_DROP;
1601 videoinfo->filesize += (guint64)buffer_size;
1603 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1604 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1606 g_mutex_unlock(&videoinfo->size_check_lock);
1608 return GST_PAD_PROBE_OK;
1612 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1614 guint64 trailer_size = 0;
1615 guint64 rec_pipe_time = 0;
1616 unsigned int remained_time = 0;
1618 GstClockTime b_time;
1620 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1621 _MMCamcorderMsgItem msg;
1622 _MMCamcorderSubContext *sc = NULL;
1623 _MMCamcorderVideoInfo *videoinfo = NULL;
1625 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1627 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1628 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1630 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1631 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1632 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1634 videoinfo = sc->info_video;
1636 b_time = GST_BUFFER_PTS(buffer);
1638 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1640 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1641 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1645 /* check max time */
1646 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1647 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1648 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1650 if (!sc->isMaxtimePausing) {
1651 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1653 sc->isMaxtimePausing = TRUE;
1655 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1656 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1657 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1658 msg.param.recording_status.remained_time = 0;
1659 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1661 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1662 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1665 return GST_PAD_PROBE_DROP;
1668 /* calculate remained time can be recorded */
1669 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1670 remained_time = videoinfo->max_time - rec_pipe_time;
1671 } else if (videoinfo->max_size > 0) {
1672 long double max_size = (long double)videoinfo->max_size;
1673 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1675 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1678 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1679 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1680 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1681 msg.param.recording_status.remained_time = remained_time;
1682 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1684 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1685 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1687 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1688 record_motion_rate, videoinfo->record_drop_count);
1690 /* drop some frame if fast motion */
1691 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1692 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1693 MMCAM_LOG_VERBOSE("drop frame");
1694 return GST_PAD_PROBE_DROP;
1697 videoinfo->record_drop_count = 1;
1698 MMCAM_LOG_VERBOSE("pass frame");
1701 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1702 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1705 return GST_PAD_PROBE_OK;
1709 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1711 _MMCamcorderMsgItem msg;
1712 guint64 trailer_size = 0;
1713 guint64 rec_pipe_time = 0;
1714 _MMCamcorderSubContext *sc = NULL;
1715 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1716 _MMCamcorderVideoInfo *videoinfo = NULL;
1717 unsigned int remained_time = 0;
1718 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1720 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1721 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1722 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1724 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1725 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1726 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1728 videoinfo = sc->info_video;
1730 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1731 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1732 return GST_PAD_PROBE_OK;
1735 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1737 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1738 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1742 /* calculate remained time can be recorded */
1743 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1744 remained_time = videoinfo->max_time - rec_pipe_time;
1745 } else if (videoinfo->max_size > 0) {
1746 long double max_size = (long double)videoinfo->max_size;
1747 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1749 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1752 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1753 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1754 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1756 if (!sc->isMaxtimePausing) {
1757 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1759 sc->isMaxtimePausing = TRUE;
1761 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1762 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1763 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1764 msg.param.recording_status.remained_time = 0;
1765 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1767 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1768 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1771 return GST_PAD_PROBE_DROP;
1774 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1775 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1776 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1777 msg.param.recording_status.remained_time = remained_time;
1778 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1780 MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1781 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1783 return GST_PAD_PROBE_OK;
1787 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1789 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1790 double volume = 0.0;
1793 int err = MM_ERROR_UNKNOWN;
1794 char *err_name = NULL;
1795 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1798 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1799 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1801 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1802 MMCAM_AUDIO_VOLUME, &volume,
1803 MMCAM_AUDIO_FORMAT, &format,
1804 MMCAM_AUDIO_CHANNEL, &channel,
1806 if (err != MM_ERROR_NONE) {
1807 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1808 SAFE_FREE(err_name);
1812 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1814 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1816 /* Set audio stream NULL */
1818 memset(mapinfo.data, 0, mapinfo.size);
1820 MMCAM_LOG_DEBUG("audio stream[%"GST_TIME_FORMAT"] - cb[%p], fmt[%d], ch[%d], size[%"G_GSIZE_FORMAT"]",
1821 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), hcamcorder->astream_cb, format, channel, mapinfo.size);
1823 /* CALL audio stream callback */
1824 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1825 MMCamcorderAudioStreamDataType stream;
1827 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1828 MMCAM_LOG_WARNING("Not ready for stream callback");
1829 gst_buffer_unmap(buffer, &mapinfo);
1830 return GST_PAD_PROBE_OK;
1833 stream.data = (void *)mapinfo.data;
1834 stream.format = format;
1835 stream.channel = channel;
1836 stream.length = mapinfo.size;
1837 stream.timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)));
1839 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1841 if (hcamcorder->astream_cb)
1842 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1844 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1847 gst_buffer_unmap(buffer, &mapinfo);
1849 return GST_PAD_PROBE_OK;
1853 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1855 gboolean bret = FALSE;
1857 switch (fileformat) {
1858 case MM_FILE_FORMAT_3GP:
1859 case MM_FILE_FORMAT_MP4:
1860 bret = __mmcamcorder_add_metadata_mp4(handle);
1863 MMCAM_LOG_WARNING("Unsupported fileformat to insert location info (%d)", fileformat);
1871 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1875 guint64 udta_size = 0;
1876 gint64 current_pos = 0;
1877 gint64 moov_pos = 0;
1878 gint64 udta_pos = 0;
1879 gdouble longitude = 0;
1880 gdouble latitude = 0;
1881 gdouble altitude = 0;
1883 int orientation = 0;
1885 char *err_name = NULL;
1886 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1887 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1888 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1890 _MMCamcorderVideoInfo *info = NULL;
1891 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1892 _MMCamcorderSubContext *sc = NULL;
1894 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1895 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1897 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1898 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1902 info = sc->info_video;
1904 f = fopen64(info->filename, "rb+");
1906 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1907 MMCAM_LOG_ERROR("file open failed [%s]", err_msg);
1911 mm_camcorder_get_attributes(handle, &err_name,
1912 MMCAM_TAG_LATITUDE, &latitude,
1913 MMCAM_TAG_LONGITUDE, &longitude,
1914 MMCAM_TAG_ALTITUDE, &altitude,
1915 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1916 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1919 MMCAM_LOG_WARNING("Get tag attrs fail. (%s:%x)", err_name, err);
1920 SAFE_FREE(err_name);
1923 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1924 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1925 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1926 geo_info.longitude = longitude *10000;
1927 geo_info.latitude = latitude *10000;
1928 geo_info.altitude = altitude *10000;
1929 /* find udta container.
1930 if, there are udta container, write loci box after that
1931 else, make udta container and write loci box. */
1932 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1935 MMCAM_LOG_INFO("find udta container");
1938 if (fseek(f, -8L, SEEK_CUR) != 0)
1941 udta_pos = ftello(f);
1945 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1947 MMCAM_LOG_INFO("recorded file fread %zu", nread);
1949 udta_size = _mmcamcorder_get_container_size(buf);
1951 /* goto end of udta and write 'loci' box */
1952 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1956 if (!_mmcamcorder_write_loci(f, location_info)) {
1957 MMCAM_LOG_ERROR("failed to write loci");
1961 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1962 MMCAM_LOG_ERROR("failed to write geodata");
1967 current_pos = ftello(f);
1968 if (current_pos < 0)
1971 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1974 MMCAM_LOG_INFO("No udta container");
1975 if (fseek(f, 0, SEEK_END) != 0)
1978 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1979 MMCAM_LOG_ERROR("failed to write udta");
1984 /* find moov container.
1985 update moov container size. */
1986 if ((current_pos = ftello(f)) < 0)
1989 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1990 gint64 internal_pos = ftello(f);
1992 MMCAM_LOG_INFO("found moov container");
1993 if (fseek(f, -8L, SEEK_CUR) != 0)
1996 moov_pos = ftello(f);
2000 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2003 /* add orientation info */
2004 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2005 MMCAM_LOG_ERROR("fseeko failed : errno %d", errno);
2009 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2010 MMCAM_LOG_ERROR("failed to find [trak] tag");
2014 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2015 MMCAM_LOG_ERROR("failed to find [tkhd] tag");
2019 MMCAM_LOG_INFO("found [tkhd] tag");
2021 /* seek to start position of composition matrix */
2022 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2023 /* update composition matrix for orientation */
2024 _mmcamcorder_update_composition_matrix(f, orientation);
2026 MMCAM_LOG_ERROR("fseek failed : errno %d", errno);
2030 MMCAM_LOG_ERROR("No 'moov' container");
2042 MMCAM_LOG_ERROR("ftell() returns negative value.");
2048 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2050 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2051 _MMCamcorderSubContext *sc = NULL;
2053 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2055 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2056 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2058 /* check video source element */
2059 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2060 MMCAM_LOG_WARNING("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2061 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2062 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2063 G_CALLBACK(__mmcamcorder_video_stream_cb),
2065 return MM_ERROR_NONE;
2067 MMCAM_LOG_ERROR("videosrc element is not created yet");
2068 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2073 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2075 int ret = MM_ERROR_NONE;
2077 char *temp_filename = NULL;
2079 _MMCamcorderVideoInfo *info = NULL;
2080 _MMCamcorderSubContext *sc = NULL;
2081 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2083 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2085 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2086 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2087 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2089 info = sc->info_video;
2091 MMCAM_LOG_WARNING("start");
2093 /* create encoding pipeline */
2094 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2095 if (ret != MM_ERROR_NONE)
2096 goto _ERR_PREPARE_RECORD;
2098 SAFE_G_FREE(info->filename);
2100 mm_camcorder_get_attributes(handle, NULL,
2101 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2103 if (temp_filename) {
2104 info->filename = g_strdup(temp_filename);
2105 if (!info->filename) {
2106 MMCAM_LOG_ERROR("strdup[src:%p] was failed", temp_filename);
2107 goto _ERR_PREPARE_RECORD;
2110 MMCAM_LOG_INFO("Record file name [%s]", info->filename);
2111 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2113 MMCAM_LOG_INFO("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2114 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2117 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2119 /* Adjust display FPS */
2120 sc->display_interval = 0;
2121 sc->previous_slot_time = 0;
2123 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2124 if (ret != MM_ERROR_NONE)
2125 goto _ERR_PREPARE_RECORD;
2127 MMCAM_LOG_WARNING("done");
2131 _ERR_PREPARE_RECORD:
2132 /* Remove recorder pipeline and recording file which size maybe zero */
2133 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2134 if (info && info->filename) {
2135 MMCAM_LOG_INFO("file delete(%s)", info->filename);
2136 unlink(info->filename);