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/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
30 /*---------------------------------------------------------------------------------------
31 | LOCAL VARIABLE DEFINITIONS for internal |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_MINIMUM_FRAME 5
34 #define _MMCAMCORDER_RETRIAL_COUNT 15
35 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* us */
36 #define _MMCAMCORDER_FRAME_PASS_MIN_FPS 30
37 #define _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME 30000000 /* ns */
38 #define _MMCAMCORDER_VIDEO_MINIMUM_SPACE (_MMCAMCORDER_MINIMUM_SPACE << 1) /* byte */
39 #define OFFSET_COMPOSITION_MATRIX 40L
40 #define MAX_ERROR_MESSAGE_LEN 128
42 /*---------------------------------------------------------------------------------------
43 | LOCAL FUNCTION PROTOTYPES: |
44 ---------------------------------------------------------------------------------------*/
45 /* STATIC INTERNAL FUNCTION */
46 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
47 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
48 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
49 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
53 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
55 /*=======================================================================================
56 | FUNCTION DEFINITIONS |
57 =======================================================================================*/
58 /*---------------------------------------------------------------------------------------
59 | GLOBAL FUNCTION DEFINITIONS: |
60 ---------------------------------------------------------------------------------------*/
61 gboolean _mmcamcorder_video_push_buffer(void *handle, GstSample *sample)
63 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
64 _MMCamcorderSubContext *sc = NULL;
65 _MMCamcorderImageInfo *info_image = NULL;
66 _MMCamcorderVideoInfo *info_video = NULL;
67 _MMCamcorderGstElement *element = NULL;
68 GstClockTime current_ts = 0; /* nsec */
69 GstBuffer *buffer = NULL;
71 mmf_return_val_if_fail(hcamcorder, FALSE);
72 mmf_return_val_if_fail(MMF_CAMCORDER_SUBCONTEXT(hcamcorder), FALSE);
74 buffer = gst_sample_get_buffer(sample);
76 mmf_return_val_if_fail(buffer, FALSE);
77 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
79 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
81 mmf_return_val_if_fail(sc->info_image, FALSE);
82 mmf_return_val_if_fail(sc->info_video, FALSE);
83 mmf_return_val_if_fail(sc->encode_element, FALSE);
85 info_image = sc->info_image;
86 info_video = sc->info_video;
87 element = sc->encode_element;
89 if (info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
90 element[_MMCAMCORDER_ENCSINK_SRC].gst) {
92 GstClock *clock = NULL;
94 MMCAM_LOG_VERBOSE("GST_BUFFER_FLAG_DELTA_UNIT is set : %d",
95 GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT));
97 current_ts = GST_BUFFER_PTS(buffer);
99 if (info_video->is_first_frame) {
100 /* check first I frame for H.264 stream */
101 if (_mmcamcorder_is_encoded_preview_pixel_format(info_image->preview_format)) {
102 if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
103 MMCAM_LOG_WARNING("NOT key frame.. skip this buffer");
106 MMCAM_LOG_WARNING("first key frame");
110 /* set base timestamp */
111 if (element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
112 clock = GST_ELEMENT_CLOCK(element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
114 gst_object_ref(clock);
115 info_video->base_video_ts = current_ts - (gst_clock_get_time(clock) - \
116 GST_ELEMENT(element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
117 gst_object_unref(clock);
120 /* for image capture with encodebin and v4l2src */
121 if (sc->bencbin_capture && info_image->capturing) {
122 g_mutex_lock(&hcamcorder->task_thread_lock);
123 MMCAM_LOG_INFO("send signal for sound play");
124 hcamcorder->task_thread_state = _MMCAMCORDER_TASK_THREAD_STATE_SOUND_SOLO_PLAY_START;
125 g_cond_signal(&hcamcorder->task_thread_cond);
126 g_mutex_unlock(&hcamcorder->task_thread_lock);
128 info_video->base_video_ts = current_ts;
131 if (_mmcamcorder_invoke_video_stream_cb(handle, sample, FALSE, -1) == FALSE) {
132 /* increase base video timestamp by frame duration,
133 it will remove delay of dropped buffer when play recorded file. */
134 info_video->base_video_ts += current_ts - info_video->last_video_ts;
135 MMCAM_LOG_DEBUG("do not push buffer to encode by app's return value");
136 goto _VIDEO_PUSH_BUFFER_DONE;
140 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer) = current_ts - info_video->base_video_ts;
142 MMCAM_LOG_DEBUG("buffer %p, timestamp %"GST_TIME_FORMAT,
143 buffer, GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));
145 if (info_video->record_dual_stream) {
146 /* It will NOT INCREASE reference count of buffer */
147 ret = gst_app_src_push_buffer((GstAppSrc *)element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
149 /* It will INCREASE reference count of buffer */
150 g_signal_emit_by_name(element[_MMCAMCORDER_ENCSINK_SRC].gst, "push-buffer", buffer, &ret);
153 MMCAM_LOG_VERBOSE("push buffer result : 0x%x", ret);
155 _VIDEO_PUSH_BUFFER_DONE:
156 info_video->last_video_ts = current_ts;
158 if (info_video->is_first_frame) {
159 info_video->is_first_frame = FALSE;
161 /* drop buffer if it's from tizen allocator */
162 if (gst_is_tizen_memory(gst_buffer_peek_memory(buffer, 0))) {
163 MMCAM_LOG_WARNING("drop first buffer from tizen allocator to avoid copy in basesrc");
169 /* skip display if too fast FPS */
170 if (info_video->record_dual_stream == FALSE &&
171 info_video->fps > _MMCAMCORDER_FRAME_PASS_MIN_FPS) {
172 if (info_video->prev_preview_ts != 0) {
173 if (GST_BUFFER_PTS(buffer) - info_video->prev_preview_ts < _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME) {
174 MMCAM_LOG_VERBOSE("it's too fast. drop frame...");
179 MMCAM_LOG_VERBOSE("display buffer [%p]", buffer);
181 info_video->prev_preview_ts = GST_BUFFER_PTS(buffer);
188 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
190 mmf_return_if_fail(sample);
192 /* no need to check return value here */
193 _mmcamcorder_video_push_buffer(u_data, sample);
195 gst_sample_unref(sample);
199 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
202 int err = MM_ERROR_NONE;
203 const char* gst_element_rsink_name = NULL;
206 GstPad *srcpad = NULL;
207 GstPad *sinkpad = NULL;
209 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
210 _MMCamcorderSubContext *sc = NULL;
212 type_element *RecordsinkElement = NULL;
214 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
216 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
217 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
218 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
220 MMCAM_LOG_WARNING("start");
222 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
223 if (err != MM_ERROR_NONE)
227 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
228 MMCAM_LOG_INFO("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
229 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
230 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
233 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
235 /* get audio disable */
236 mm_camcorder_get_attributes(handle, NULL,
237 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
240 MMCAM_LOG_INFO("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d, ved_cb %p",
241 sc->audio_disable, sc->is_modified_rate, hcamcorder->vedecision_cb);
243 if (sc->is_modified_rate || hcamcorder->vedecision_cb)
244 sc->audio_disable = TRUE;
246 if (sc->audio_disable == FALSE) {
247 /* create audiosrc bin */
248 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
249 if (err != MM_ERROR_NONE)
253 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
254 if (err != MM_ERROR_NONE)
257 if (sc->audio_disable == FALSE) {
258 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
259 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
262 /* add elements and encodesink bin to encode main pipeline */
263 if (sc->info_video->use_videoscale) {
264 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
265 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
266 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
267 sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst,
268 sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst,
269 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
272 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
273 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
274 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
275 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
279 /* Link each element : appsrc - capsfilter - encodesink bin */
280 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
281 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
282 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
284 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
285 if (sc->info_video->use_videoscale) {
286 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst, "sink");
287 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
289 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst, "src");
290 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, "sink");
291 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
293 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, "src");
295 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
296 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
298 if (sc->audio_disable == FALSE) {
299 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
300 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
301 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
304 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
305 CONFIGURE_CATEGORY_MAIN_RECORD,
308 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
310 if (!gst_element_rsink_name) {
311 MMCAM_LOG_ERROR("failed to get recordsink name");
312 err = MM_ERROR_CAMCORDER_INTERNAL;
313 goto pipeline_creation_error;
316 /* set data probe function */
318 /* register message cb */
320 /* set data probe functions */
321 if (sc->audio_disable == FALSE) {
322 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
323 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
324 __mmcamcorder_audioque_dataprobe, hcamcorder);
325 gst_object_unref(sinkpad);
329 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
330 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
331 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
332 gst_object_unref(srcpad);
335 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
336 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
337 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
338 __mmcamcorder_eventprobe_monitor, hcamcorder);
339 gst_object_unref(srcpad);
344 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
345 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
346 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
347 __mmcamcorder_eventprobe_monitor, hcamcorder);
348 gst_object_unref(srcpad);
352 if (sc->audio_disable) {
353 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
354 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
355 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
356 gst_object_unref(sinkpad);
360 if (!strcmp(gst_element_rsink_name, "filesink")) {
361 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
362 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
363 __mmcamcorder_video_dataprobe_encoded, hcamcorder);
364 gst_object_unref(srcpad);
367 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
368 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
369 __mmcamcorder_audio_dataprobe_check, hcamcorder);
370 gst_object_unref(srcpad);
374 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
375 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
376 __mmcamcorder_muxed_dataprobe, hcamcorder);
377 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
378 __mmcamcorder_eventprobe_monitor, hcamcorder);
379 gst_object_unref(sinkpad);
382 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
384 /* set sync handler */
385 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
387 gst_object_unref(bus);
390 return MM_ERROR_NONE;
392 pipeline_creation_error:
393 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
394 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
396 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
401 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
403 GstPad *srcpad = NULL;
404 GstPad *sinkpad = NULL;
405 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
406 _MMCamcorderSubContext *sc = NULL;
408 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
410 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
411 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
412 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
416 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
417 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
418 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
419 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
421 /* release audiosrc bin */
422 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
423 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
426 To avoid conflicting between old elements and newly created elements,
427 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
428 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
429 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
430 It's because the pipeline of audio recording destroys at the same time,
431 and '_mmcamcorder_element_release_noti' will perform removing handle.
433 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
435 MMCAM_LOG_INFO("Audio pipeline removed");
438 return MM_ERROR_NONE;
442 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
444 GstPad *reqpad = NULL;
445 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
446 _MMCamcorderSubContext *sc = NULL;
447 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
448 int ret = MM_ERROR_NONE;
449 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
451 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
453 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
454 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
455 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
459 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
460 /* release request pad */
461 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
463 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
464 gst_object_unref(reqpad);
468 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
470 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
471 gst_object_unref(reqpad);
475 /* release encode main pipeline */
476 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
479 To avoid conflicting between old elements and newly created elements,
480 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
481 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
482 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
483 It's because the pipeline of audio recording destroys at the same time,
484 and '_mmcamcorder_element_release_noti' will perform removing handle.
486 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
487 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
489 MMCAM_LOG_WARNING("Encoder pipeline removed");
491 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
492 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
494 MMCAM_LOG_WARNING("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
496 if (hcamcorder->is_release_cb_calling == FALSE) {
497 /* release resource */
498 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
499 hcamcorder->video_encoder_resource);
500 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
501 hcamcorder->video_encoder_resource = NULL;
503 MMCAM_LOG_WARNING("mark resource for release 0x%x", ret);
505 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
507 MMCAM_LOG_WARNING("commit resource release 0x%x", ret);
510 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
512 MMCAM_LOG_WARNING("unlock resource");
513 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
516 return MM_ERROR_NONE;
520 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
522 int ret = MM_ERROR_NONE;
523 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
524 _MMCamcorderSubContext *sc = NULL;
528 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
529 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
530 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
532 MMCAM_LOG_INFO("start");
534 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
535 MMCAM_LOG_WARNING("pipeline is not existed.");
536 return MM_ERROR_NONE;
539 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
541 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
542 if (ret != MM_ERROR_NONE) {
543 MMCAM_LOG_ERROR("Failed to change encode main pipeline [0x%x]", ret);
547 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
549 /* remove audio pipeline first */
550 ret = _mmcamcorder_remove_audio_pipeline(handle);
551 if (ret != MM_ERROR_NONE) {
552 MMCAM_LOG_ERROR("Fail to remove audio pipeline");
556 ret = _mmcamcorder_remove_encode_pipeline(handle);
557 if (ret != MM_ERROR_NONE) {
558 MMCAM_LOG_ERROR("Fail to remove encoder pipeline");
562 /* Remove remained message */
564 GstMessage *gst_msg = NULL;
565 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
566 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
567 gst_message_unref(gst_msg);
570 gst_object_unref(bus);
574 MMCAM_LOG_INFO("done");
580 int _mmcamcorder_video_command(MMHandleType handle, int command)
585 int gop_interval = 0;
586 int ret = MM_ERROR_NONE;
587 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
588 char *err_name = NULL;
589 char *target_filename = NULL;
590 GstCameraControl *CameraControl = NULL;
593 GstElement *pipeline = NULL;
595 _MMCamcorderVideoInfo *info = NULL;
596 _MMCamcorderSubContext *sc = NULL;
597 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
599 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
601 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
602 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
603 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
604 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
606 info = sc->info_video;
608 MMCAM_LOG_INFO("Command(%d)", command);
610 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
613 case _MMCamcorder_CMD_RECORD:
615 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
619 gboolean storage_validity = FALSE;
622 int root_directory_length = 0;
625 MMCAM_LOG_INFO("Record Start - dual stream %d", info->support_dual_stream);
627 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
628 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
630 /* prepare resource manager for H/W encoder */
631 if (hcamcorder->video_encoder_resource == NULL) {
632 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
633 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
634 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
635 &hcamcorder->video_encoder_resource);
636 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
637 MMCAM_LOG_ERROR("could not prepare for encoder resource");
638 ret = MM_ERROR_RESOURCE_INTERNAL;
639 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
640 goto _ERR_CAMCORDER_VIDEO_COMMAND;
643 MMCAM_LOG_INFO("encoder already acquired");
646 /* acquire resources */
647 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
648 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
649 MMCAM_LOG_ERROR("could not acquire resources");
650 ret = MM_ERROR_RESOURCE_INTERNAL;
651 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
652 goto _ERR_CAMCORDER_VIDEO_COMMAND;
655 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
656 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
658 /* init record_dual_stream */
659 info->record_dual_stream = FALSE;
661 ret = mm_camcorder_get_attributes(handle, &err_name,
662 MMCAM_CAMERA_FPS, &fps,
663 MMCAM_CAMERA_WIDTH, &(info->preview_width),
664 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
665 MMCAM_VIDEO_WIDTH, &(info->video_width),
666 MMCAM_VIDEO_HEIGHT, &(info->video_height),
667 MMCAM_FILE_FORMAT, &fileformat,
668 MMCAM_TARGET_FILENAME, &target_filename, &size,
669 MMCAM_TARGET_MAX_SIZE, &imax_size,
670 MMCAM_TARGET_TIME_LIMIT, &imax_time,
671 MMCAM_FILE_FORMAT, &(info->fileformat),
672 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
673 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
675 if (ret != MM_ERROR_NONE) {
676 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, ret);
678 goto _ERR_CAMCORDER_VIDEO_COMMAND;
681 if (!target_filename && !hcamcorder->mstream_cb) {
682 MMCAM_LOG_ERROR("filename is not set and muxed stream cb is NULL");
683 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
684 goto _ERR_CAMCORDER_VIDEO_COMMAND;
689 info->max_size = 0; /* do not check */
691 info->max_size = ((guint64)imax_size) << 10; /* to byte */
695 info->max_time = 0; /* do not check */
697 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
699 ret = _mmcamcorder_get_storage_validity(hcamcorder, target_filename,
700 _MMCAMCORDER_VIDEO_MINIMUM_SPACE, &storage_validity);
701 if (ret != MM_ERROR_NONE) {
702 MMCAM_LOG_ERROR("storage validation failed[0x%x]:%d", ret, storage_validity);
706 _mmcamcorder_adjust_recording_max_size(target_filename, &info->max_size);
708 g_mutex_lock(&hcamcorder->task_thread_lock);
709 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
710 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
711 /* Play record start sound */
712 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
714 g_mutex_unlock(&hcamcorder->task_thread_lock);
716 MMCAM_LOG_WARNING("video size [%dx%d]", info->video_width, info->video_height);
718 if (info->video_width == 0 || info->video_height == 0) {
719 MMCAM_LOG_WARNING("video size is invalid [%dx%d] use preview size [%dx%d]",
720 info->video_width, info->video_height, info->preview_width, info->preview_height);
721 info->video_width = info->preview_width;
722 info->video_height = info->preview_height;
725 if (info->support_dual_stream) {
726 MMCAM_LOG_WARNING("DUAL STREAM MODE");
728 info->record_dual_stream = TRUE;
730 /* No need to restart preview */
731 info->restart_preview = FALSE;
733 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
734 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
735 } else if (_mmcamcorder_is_encoded_preview_pixel_format(sc->info_image->preview_format) &&
736 info->preview_width == info->video_width &&
737 info->preview_height == info->video_height) {
738 MMCAM_LOG_INFO("Encoded[%d] preview mode and same resolution", sc->info_image->preview_format);
739 /* No need to restart preview */
740 info->restart_preview = FALSE;
741 } else if (info->use_videoscale &&
742 info->preview_width >= info->video_width &&
743 info->preview_height >= info->video_height) {
744 info->restart_preview = FALSE;
746 info->restart_preview = TRUE;
747 /* reset use_videoscale */
748 info->use_videoscale = FALSE;
751 /* set recording hint */
752 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
754 if (info->restart_preview) {
755 /* stop preview and set new size */
756 MMCAM_LOG_INFO("restart preview");
758 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
759 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
760 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
762 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
764 /* check decoder recreation */
765 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
766 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
767 ret = MM_ERROR_CAMCORDER_INTERNAL;
768 goto _ERR_CAMCORDER_VIDEO_COMMAND;
771 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
772 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
773 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
775 if (ret != MM_ERROR_NONE)
776 goto _ERR_CAMCORDER_VIDEO_COMMAND;
778 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
779 ret = MM_ERROR_CAMCORDER_INTERNAL;
780 goto _ERR_CAMCORDER_VIDEO_COMMAND;
783 /* Start preview again with new setting */
784 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
785 if (ret != MM_ERROR_NONE)
786 goto _ERR_CAMCORDER_VIDEO_COMMAND;
788 if (motion_rate < 1.0) {
789 MMCAM_LOG_WARNING("wait for stabilization of frame");
793 MMCAM_LOG_INFO("no need to restart preview");
796 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
797 CONFIGURE_CATEGORY_MAIN_RECORD,
801 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
802 CONFIGURE_CATEGORY_MAIN_RECORD,
803 "PassFirstVideoFrame",
804 &(sc->pass_first_vframe));
806 MMCAM_LOG_INFO("Drop video frame count[%d], Pass first video frame count[%d]",
807 sc->drop_vframe, sc->pass_first_vframe);
809 info->record_drop_count = (guint)motion_rate;
810 info->record_motion_rate = motion_rate;
811 if (sc->is_modified_rate)
812 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
814 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
816 MMCAM_LOG_WARNING("recording fps %d, motion rate %f, timestamp_ratio %f",
817 fps, info->record_motion_rate, info->record_timestamp_ratio);
819 /* set push buffer flag */
820 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
821 info->base_video_ts = 0;
823 /* connect video stream cb signal if it supports dual stream. */
824 if (info->record_dual_stream) {
825 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
826 goto _ERR_CAMCORDER_VIDEO_COMMAND;
829 /* start video stream */
830 if (info->record_dual_stream) {
831 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
833 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
835 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
836 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
838 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
840 MMCAM_LOG_ERROR("could not get camera control");
844 /* check pre-created encode pipeline */
845 g_mutex_lock(&hcamcorder->task_thread_lock);
846 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
847 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
848 /* create encoding pipeline */
849 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
850 if (ret != MM_ERROR_NONE) {
851 g_mutex_unlock(&hcamcorder->task_thread_lock);
852 goto _ERR_CAMCORDER_VIDEO_COMMAND;
855 g_mutex_unlock(&hcamcorder->task_thread_lock);
857 /* check recording start sound */
858 _mmcamcorder_sound_solo_play_wait(handle);
860 /**< To fix video recording hanging
861 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
862 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
863 basetime wouldn't change if you set (GstClockTime)0.
864 3. Move set start time position below PAUSED of pipeline.
867 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
868 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
871 info->video_frame_count = 0;
872 info->is_first_frame = TRUE;
873 info->audio_frame_count = 0;
875 sc->ferror_send = FALSE;
876 sc->ferror_count = 0;
877 hcamcorder->error_occurs = FALSE;
878 sc->bget_eos = FALSE;
879 sc->muxed_stream_offset = 0;
881 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
882 if (ret != MM_ERROR_NONE) {
883 /* stop video stream */
884 if (info->record_dual_stream) {
885 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
887 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
889 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
890 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
892 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
894 MMCAM_LOG_ERROR("failed to get camera control");
898 /* Remove recorder pipeline and recording file which size maybe zero */
899 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
900 if (info->filename) {
901 MMCAM_LOG_INFO("file delete(%s)", info->filename);
902 unlink(info->filename);
904 goto _ERR_CAMCORDER_VIDEO_COMMAND;
907 /*set the GOP so that video record will get a new key frame*/
908 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
909 if (mm_camcorder_get_attributes(handle, NULL,
910 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
911 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
913 MMCAM_LOG_ERROR("get gop interval failed");
917 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
918 if (mm_camcorder_get_attributes(handle, NULL,
919 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
920 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
922 MMCAM_LOG_ERROR("get gop interval failed");
925 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
927 MMCAM_LOG_INFO("Object property settings done");
931 case _MMCamcorder_CMD_PAUSE:
933 if (info->b_committing) {
934 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
935 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
938 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
939 if (sc->audio_disable) {
940 /* check only video frame */
941 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
943 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
944 MMCAM_LOG_ERROR("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
945 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
947 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
950 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
952 /* check both of video and audio frame */
953 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
955 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
956 MMCAM_LOG_ERROR("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
957 info->video_frame_count, info->audio_frame_count);
958 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
960 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
961 count, info->video_frame_count, info->audio_frame_count);
964 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
968 /* block encodebin */
969 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
972 case _MMCamcorder_CMD_CANCEL:
974 if (info->b_committing) {
975 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
976 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
979 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
981 if (hcamcorder->capture_in_recording == FALSE) {
983 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
984 MMCAM_LOG_ERROR("Failed to Wait capture data");
985 hcamcorder->capture_in_recording = FALSE;
988 MMCAM_LOG_WARNING("Waiting for capture data - retrial [%d]", count);
991 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
994 /* block push buffer */
995 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
997 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
998 if (ret != MM_ERROR_NONE)
999 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1001 /* set recording hint */
1002 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1004 /* stop video stream */
1005 if (info->record_dual_stream) {
1006 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1007 if (CameraControl) {
1008 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1010 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1011 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1013 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1015 MMCAM_LOG_ERROR("failed to get camera control");
1019 if (info->restart_preview) {
1020 /* restart preview */
1021 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1022 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1023 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1025 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1027 /* check decoder recreation */
1028 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1029 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1030 ret = MM_ERROR_CAMCORDER_INTERNAL;
1033 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1034 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1035 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1037 if (ret != MM_ERROR_NONE)
1038 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1040 /* reset restart_preview for inset window layout */
1041 info->restart_preview = FALSE;
1043 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1044 ret = MM_ERROR_CAMCORDER_INTERNAL;
1045 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1048 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1049 if (ret != MM_ERROR_NONE)
1050 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1053 /* remove target file */
1054 if (info->filename) {
1055 MMCAM_LOG_INFO("file delete(%s)", info->filename);
1056 unlink(info->filename);
1059 sc->isMaxsizePausing = FALSE;
1060 sc->isMaxtimePausing = FALSE;
1062 sc->display_interval = 0;
1063 sc->previous_slot_time = 0;
1064 info->video_frame_count = 0;
1065 info->audio_frame_count = 0;
1067 hcamcorder->capture_in_recording = FALSE;
1070 case _MMCamcorder_CMD_COMMIT:
1074 if (info->b_committing) {
1075 MMCAM_LOG_ERROR("now on committing previous file!!(command : %d)", command);
1076 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1078 MMCAM_LOG_INFO("_MMCamcorder_CMD_COMMIT : start");
1079 info->b_committing = TRUE;
1080 sc->bget_eos = FALSE;
1083 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1084 if (sc->audio_disable) {
1085 /* check only video frame */
1086 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1087 hcamcorder->capture_in_recording == FALSE) {
1089 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1090 MMCAM_LOG_ERROR("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1091 info->video_frame_count, hcamcorder->capture_in_recording);
1093 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1094 MMCAM_LOG_WARNING("video frames are enough. keep going...");
1096 info->b_committing = FALSE;
1097 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1100 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1101 count, info->video_frame_count, hcamcorder->capture_in_recording);
1104 /* check both of video and audio frame */
1105 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1106 info->audio_frame_count &&
1107 hcamcorder->capture_in_recording == FALSE) {
1109 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1110 MMCAM_LOG_ERROR("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1111 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1113 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1114 MMCAM_LOG_WARNING("video/audio frames are enough. keep going...");
1116 info->b_committing = FALSE;
1117 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1120 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1122 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1123 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1127 if (hcamcorder->capture_in_recording) {
1128 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1129 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1130 MMCAM_LOG_WARNING("timeout");
1132 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1136 /* block push buffer */
1137 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1138 MMCAM_LOG_INFO("block push buffer to appsrc");
1140 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1141 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1142 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1143 ret = MM_ERROR_OUT_OF_STORAGE;
1144 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1147 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1148 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1149 MMCAM_LOG_WARNING("VIDEO: send eos to appsrc done");
1151 MMCAM_LOG_ERROR("VIDEO: send EOS failed");
1152 info->b_committing = FALSE;
1153 ret = MM_ERROR_CAMCORDER_INTERNAL;
1154 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1157 MMCAM_LOG_ERROR("No video stream source");
1158 info->b_committing = FALSE;
1159 ret = MM_ERROR_CAMCORDER_INTERNAL;
1160 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1163 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1164 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1165 MMCAM_LOG_WARNING("AUDIO: send eos to audiosrc done");
1167 MMCAM_LOG_ERROR("AUDIO: send EOS failed");
1168 info->b_committing = FALSE;
1169 ret = MM_ERROR_CAMCORDER_INTERNAL;
1170 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1173 MMCAM_LOG_INFO("No audio stream");
1177 sc->display_interval = 0;
1178 sc->previous_slot_time = 0;
1181 MMCAM_LOG_INFO("Start to wait EOS");
1182 ret = _mmcamcorder_get_eos_message(handle);
1183 if (ret != MM_ERROR_NONE) {
1184 info->b_committing = FALSE;
1185 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1189 hcamcorder->capture_in_recording = FALSE;
1193 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1194 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1197 return MM_ERROR_NONE;
1199 _ERR_CAMCORDER_VIDEO_COMMAND:
1200 if (command == _MMCamcorder_CMD_RECORD)
1201 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1207 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1209 int ret = MM_ERROR_NONE;
1211 guint64 file_size = 0;
1213 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1214 _MMCamcorderSubContext *sc = NULL;
1215 _MMCamcorderVideoInfo *info = NULL;
1216 _MMCamcorderMsgItem msg;
1217 MMCamRecordingReport *report = NULL;
1219 mmf_return_val_if_fail(hcamcorder, FALSE);
1221 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1222 mmf_return_val_if_fail(sc, FALSE);
1223 mmf_return_val_if_fail(sc->info_video, FALSE);
1225 info = sc->info_video;
1227 MMCAM_LOG_ERROR("");
1229 /* Play record stop sound */
1230 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1232 /* remove blocking part */
1233 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1235 mm_camcorder_get_attributes(handle, NULL,
1236 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1239 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1240 if (ret != MM_ERROR_NONE)
1241 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1243 /* set recording hint */
1244 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1246 /* stop video stream */
1247 if (info->record_dual_stream) {
1248 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1250 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1252 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1253 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1255 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1257 MMCAM_LOG_ERROR("failed to get camera control");
1261 if (enabletag && !(sc->ferror_send)) {
1262 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1263 MMCAM_LOG_INFO("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1266 /* Check file size */
1267 if (info->max_size > 0) {
1268 _mmcamcorder_get_file_size(info->filename, &file_size);
1269 MMCAM_LOG_INFO("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1270 info->max_size, file_size);
1272 if (file_size > info->max_size) {
1273 _MMCamcorderMsgItem message;
1274 MMCAM_LOG_ERROR("File size is greater than max size !!");
1275 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1276 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1277 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1281 if (info->restart_preview) {
1283 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1284 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1285 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1287 MMCAM_LOG_INFO("Set state of pipeline as READY");
1288 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1290 /* check decoder recreation */
1291 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1292 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1293 ret = MM_ERROR_CAMCORDER_INTERNAL;
1297 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1298 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1299 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1301 if (ret != MM_ERROR_NONE) {
1302 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1303 msg.param.code = ret;
1304 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1305 MMCAM_LOG_ERROR("Failed to set state READY[%x]", ret);
1308 /* reset restart_preview for inset window layout */
1309 info->restart_preview = FALSE;
1311 /* recover preview size */
1312 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1313 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1314 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1315 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1316 MMCAM_LOG_ERROR("Failed to set camera resolution %dx%d",
1317 info->preview_width, info->preview_height);
1320 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1321 /* Do not return when error is occurred.
1322 Recording file was created successfully, but starting pipeline failed */
1323 if (ret != MM_ERROR_NONE) {
1324 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1325 msg.param.code = ret;
1326 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1327 MMCAM_LOG_ERROR("Failed to set state PLAYING[%x]", ret);
1330 MMCAM_LOG_INFO("No need to restart preview");
1333 /* Send recording report to application */
1334 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1335 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1336 report->recording_filename = g_strdup(info->filename);
1337 msg.param.data = report;
1339 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1342 sc->pipeline_time = 0;
1344 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1345 sc->isMaxtimePausing = FALSE;
1346 hcamcorder->error_occurs = FALSE;
1348 info->video_frame_count = 0;
1349 info->audio_frame_count = 0;
1351 info->b_committing = FALSE;
1353 /* check recording stop sound */
1354 _mmcamcorder_sound_solo_play_wait(handle);
1356 MMCAM_LOG_ERROR("_MMCamcorder_CMD_COMMIT : end");
1362 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1364 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1365 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1367 _MMCamcorderSubContext *sc = NULL;
1368 _MMCamcorderVideoInfo *videoinfo = NULL;
1369 _MMCamcorderMsgItem msg;
1370 guint64 buffer_size = 0;
1371 guint64 trailer_size = 0;
1372 guint64 max_size = 0;
1374 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1375 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1376 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1378 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1379 videoinfo = sc->info_video;
1381 /* get buffer size */
1382 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1383 MMCAM_LOG_WARNING("map failed : buffer %p", buffer);
1384 return GST_PAD_PROBE_OK;
1387 buffer_size = mapinfo.size;
1388 gst_buffer_unmap(buffer, &mapinfo);
1390 g_mutex_lock(&videoinfo->size_check_lock);
1392 if (videoinfo->audio_frame_count == 0) {
1393 videoinfo->filesize += buffer_size;
1394 videoinfo->audio_frame_count++;
1395 g_mutex_unlock(&videoinfo->size_check_lock);
1396 return GST_PAD_PROBE_OK;
1399 if (sc->ferror_send || sc->isMaxsizePausing) {
1400 MMCAM_LOG_WARNING("Recording is paused, drop frames");
1401 g_mutex_unlock(&videoinfo->size_check_lock);
1402 return GST_PAD_PROBE_DROP;
1405 /* get trailer size */
1406 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1407 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1411 /* check max size of recorded file */
1412 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1413 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1414 GstState pipeline_state = GST_STATE_VOID_PENDING;
1415 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1417 MMCAM_LOG_WARNING("Max size[%"G_GUINT64_FORMAT"], current size[%"G_GUINT64_FORMAT"],"\
1418 " buffer size[%"G_GUINT64_FORMAT"], trailer size[%"G_GUINT64_FORMAT"]",
1419 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1421 if (!sc->isMaxsizePausing) {
1422 sc->isMaxsizePausing = TRUE;
1423 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1424 if (pipeline_state == GST_STATE_PLAYING)
1425 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1427 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1428 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1431 g_mutex_unlock(&videoinfo->size_check_lock);
1436 videoinfo->filesize += buffer_size;
1437 videoinfo->audio_frame_count++;
1439 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1440 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1442 g_mutex_unlock(&videoinfo->size_check_lock);
1444 return GST_PAD_PROBE_OK;
1448 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1453 guint64 free_space = 0;
1454 guint64 buffer_size = 0;
1455 guint64 trailer_size = 0;
1456 guint64 queued_buffer = 0;
1457 guint64 max_size = 0;
1458 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1460 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1462 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1463 _MMCamcorderMsgItem msg;
1464 _MMCamcorderSubContext *sc = NULL;
1465 _MMCamcorderVideoInfo *videoinfo = NULL;
1467 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1468 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1470 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1471 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1472 videoinfo = sc->info_video;
1474 if (sc->ferror_send) {
1475 MMCAM_LOG_WARNING("file write error, drop frames");
1476 return GST_PAD_PROBE_DROP;
1479 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1480 buffer_size = mapinfo.size;
1481 gst_buffer_unmap(buffer, &mapinfo);
1483 videoinfo->video_frame_count++;
1484 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1485 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1486 g_mutex_lock(&videoinfo->size_check_lock);
1487 videoinfo->filesize += buffer_size;
1488 g_mutex_unlock(&videoinfo->size_check_lock);
1489 return GST_PAD_PROBE_OK;
1492 /* get trailer size */
1493 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1494 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1498 /* check free space */
1499 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1501 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1502 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1503 sc->ferror_send = TRUE;
1505 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1506 msg.param.code = MM_ERROR_FILE_READ;
1508 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1513 return GST_PAD_PROBE_DROP; /* skip this buffer */
1516 if (free_space == 0) {
1517 /* check storage state */
1518 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1520 MMCAM_LOG_WARNING("storage state %d", storage_state);
1522 if (storage_state == STORAGE_STATE_REMOVED ||
1523 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1524 MMCAM_LOG_ERROR("storage was removed!");
1526 _MMCAMCORDER_LOCK(hcamcorder);
1528 if (sc->ferror_send == FALSE) {
1529 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1531 sc->ferror_send = TRUE;
1533 _MMCAMCORDER_UNLOCK(hcamcorder);
1535 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1536 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1538 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1540 _MMCAMCORDER_UNLOCK(hcamcorder);
1541 MMCAM_LOG_WARNING("error was already sent");
1544 return GST_PAD_PROBE_DROP;
1548 /* get queued buffer size */
1549 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1550 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1552 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1553 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1555 queued_buffer = aq_size + vq_size;
1557 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1558 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1559 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1560 free_space, trailer_size, buffer_size, queued_buffer);
1562 if (!sc->isMaxsizePausing) {
1563 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1564 sc->isMaxsizePausing = TRUE;
1566 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1567 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1570 return GST_PAD_PROBE_DROP;
1573 g_mutex_lock(&videoinfo->size_check_lock);
1575 /* check max size of recorded file */
1576 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1577 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1578 GstState pipeline_state = GST_STATE_VOID_PENDING;
1579 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1581 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1582 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1583 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1585 if (!sc->isMaxsizePausing) {
1586 sc->isMaxsizePausing = TRUE;
1587 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1588 if (pipeline_state == GST_STATE_PLAYING)
1589 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1591 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1592 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1595 g_mutex_unlock(&videoinfo->size_check_lock);
1597 return GST_PAD_PROBE_DROP;
1600 videoinfo->filesize += (guint64)buffer_size;
1602 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1603 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1605 g_mutex_unlock(&videoinfo->size_check_lock);
1607 return GST_PAD_PROBE_OK;
1611 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1613 guint64 trailer_size = 0;
1614 guint64 rec_pipe_time = 0;
1615 unsigned int remained_time = 0;
1617 GstClockTime b_time;
1619 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1620 _MMCamcorderMsgItem msg;
1621 _MMCamcorderSubContext *sc = NULL;
1622 _MMCamcorderVideoInfo *videoinfo = NULL;
1624 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1626 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1627 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1629 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1630 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1631 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1633 videoinfo = sc->info_video;
1635 b_time = GST_BUFFER_PTS(buffer);
1637 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1639 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1640 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1644 /* check max time */
1645 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1646 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1647 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1649 if (!sc->isMaxtimePausing) {
1650 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1652 sc->isMaxtimePausing = TRUE;
1654 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1655 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1656 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1657 msg.param.recording_status.remained_time = 0;
1658 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1660 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1661 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1664 return GST_PAD_PROBE_DROP;
1667 /* calculate remained time can be recorded */
1668 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1669 remained_time = videoinfo->max_time - rec_pipe_time;
1670 } else if (videoinfo->max_size > 0) {
1671 long double max_size = (long double)videoinfo->max_size;
1672 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1674 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1677 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1678 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1679 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1680 msg.param.recording_status.remained_time = remained_time;
1681 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1683 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1684 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1686 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1687 record_motion_rate, videoinfo->record_drop_count);
1689 /* drop some frame if fast motion */
1690 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1691 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1692 MMCAM_LOG_VERBOSE("drop frame");
1693 return GST_PAD_PROBE_DROP;
1696 videoinfo->record_drop_count = 1;
1697 MMCAM_LOG_VERBOSE("pass frame");
1700 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1701 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1704 return GST_PAD_PROBE_OK;
1708 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1710 _MMCamcorderMsgItem msg;
1711 guint64 trailer_size = 0;
1712 guint64 rec_pipe_time = 0;
1713 _MMCamcorderSubContext *sc = NULL;
1714 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1715 _MMCamcorderVideoInfo *videoinfo = NULL;
1716 unsigned int remained_time = 0;
1717 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1719 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1720 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1721 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1723 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1724 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1725 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1727 videoinfo = sc->info_video;
1729 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1730 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1731 return GST_PAD_PROBE_OK;
1734 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1736 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1737 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1741 /* calculate remained time can be recorded */
1742 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1743 remained_time = videoinfo->max_time - rec_pipe_time;
1744 } else if (videoinfo->max_size > 0) {
1745 long double max_size = (long double)videoinfo->max_size;
1746 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1748 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1751 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1752 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1753 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1755 if (!sc->isMaxtimePausing) {
1756 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1758 sc->isMaxtimePausing = TRUE;
1760 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1761 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1762 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1763 msg.param.recording_status.remained_time = 0;
1764 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1766 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1767 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1770 return GST_PAD_PROBE_DROP;
1773 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1774 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1775 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1776 msg.param.recording_status.remained_time = remained_time;
1777 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1779 MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1780 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1782 return GST_PAD_PROBE_OK;
1786 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1788 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1789 double volume = 0.0;
1792 int err = MM_ERROR_UNKNOWN;
1793 char *err_name = NULL;
1794 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1797 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1798 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1800 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1801 MMCAM_AUDIO_VOLUME, &volume,
1802 MMCAM_AUDIO_FORMAT, &format,
1803 MMCAM_AUDIO_CHANNEL, &channel,
1805 if (err != MM_ERROR_NONE) {
1806 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1807 SAFE_FREE(err_name);
1811 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1813 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1815 /* Set audio stream NULL */
1817 memset(mapinfo.data, 0, mapinfo.size);
1819 MMCAM_LOG_DEBUG("audio stream[%"GST_TIME_FORMAT"] - cb[%p], fmt[%d], ch[%d], size[%"G_GSIZE_FORMAT"]",
1820 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), hcamcorder->astream_cb, format, channel, mapinfo.size);
1822 /* CALL audio stream callback */
1823 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1824 MMCamcorderAudioStreamDataType stream;
1826 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1827 MMCAM_LOG_WARNING("Not ready for stream callback");
1828 gst_buffer_unmap(buffer, &mapinfo);
1829 return GST_PAD_PROBE_OK;
1832 stream.data = (void *)mapinfo.data;
1833 stream.format = format;
1834 stream.channel = channel;
1835 stream.length = mapinfo.size;
1836 stream.timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)));
1838 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1840 if (hcamcorder->astream_cb)
1841 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1843 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1846 gst_buffer_unmap(buffer, &mapinfo);
1848 return GST_PAD_PROBE_OK;
1852 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1854 gboolean bret = FALSE;
1856 switch (fileformat) {
1857 case MM_FILE_FORMAT_3GP:
1858 case MM_FILE_FORMAT_MP4:
1859 bret = __mmcamcorder_add_metadata_mp4(handle);
1862 MMCAM_LOG_WARNING("Unsupported fileformat to insert location info (%d)", fileformat);
1870 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1874 guint64 udta_size = 0;
1875 gint64 current_pos = 0;
1876 gint64 moov_pos = 0;
1877 gint64 udta_pos = 0;
1878 gdouble longitude = 0;
1879 gdouble latitude = 0;
1880 gdouble altitude = 0;
1882 int orientation = 0;
1884 char *err_name = NULL;
1885 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1886 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1887 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1889 _MMCamcorderVideoInfo *info = NULL;
1890 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1891 _MMCamcorderSubContext *sc = NULL;
1893 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1894 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1896 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1897 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1901 info = sc->info_video;
1903 f = fopen64(info->filename, "rb+");
1905 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1906 MMCAM_LOG_ERROR("file open failed [%s]", err_msg);
1910 mm_camcorder_get_attributes(handle, &err_name,
1911 MMCAM_TAG_LATITUDE, &latitude,
1912 MMCAM_TAG_LONGITUDE, &longitude,
1913 MMCAM_TAG_ALTITUDE, &altitude,
1914 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1915 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1918 MMCAM_LOG_WARNING("Get tag attrs fail. (%s:%x)", err_name, err);
1919 SAFE_FREE(err_name);
1922 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1923 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1924 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1925 geo_info.longitude = longitude *10000;
1926 geo_info.latitude = latitude *10000;
1927 geo_info.altitude = altitude *10000;
1928 /* find udta container.
1929 if, there are udta container, write loci box after that
1930 else, make udta container and write loci box. */
1931 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1934 MMCAM_LOG_INFO("find udta container");
1937 if (fseek(f, -8L, SEEK_CUR) != 0)
1940 udta_pos = ftello(f);
1944 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1946 MMCAM_LOG_INFO("recorded file fread %zu", nread);
1948 udta_size = _mmcamcorder_get_container_size(buf);
1950 /* goto end of udta and write 'loci' box */
1951 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1955 if (!_mmcamcorder_write_loci(f, location_info)) {
1956 MMCAM_LOG_ERROR("failed to write loci");
1960 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1961 MMCAM_LOG_ERROR("failed to write geodata");
1966 current_pos = ftello(f);
1967 if (current_pos < 0)
1970 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1973 MMCAM_LOG_INFO("No udta container");
1974 if (fseek(f, 0, SEEK_END) != 0)
1977 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1978 MMCAM_LOG_ERROR("failed to write udta");
1983 /* find moov container.
1984 update moov container size. */
1985 if ((current_pos = ftello(f)) < 0)
1988 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1989 gint64 internal_pos = ftello(f);
1991 MMCAM_LOG_INFO("found moov container");
1992 if (fseek(f, -8L, SEEK_CUR) != 0)
1995 moov_pos = ftello(f);
1999 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2002 /* add orientation info */
2003 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2004 MMCAM_LOG_ERROR("fseeko failed : errno %d", errno);
2008 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2009 MMCAM_LOG_ERROR("failed to find [trak] tag");
2013 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2014 MMCAM_LOG_ERROR("failed to find [tkhd] tag");
2018 MMCAM_LOG_INFO("found [tkhd] tag");
2020 /* seek to start position of composition matrix */
2021 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2022 /* update composition matrix for orientation */
2023 _mmcamcorder_update_composition_matrix(f, orientation);
2025 MMCAM_LOG_ERROR("fseek failed : errno %d", errno);
2029 MMCAM_LOG_ERROR("No 'moov' container");
2041 MMCAM_LOG_ERROR("ftell() returns negative value.");
2047 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2049 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2050 _MMCamcorderSubContext *sc = NULL;
2052 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2054 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2055 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2057 /* check video source element */
2058 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2059 MMCAM_LOG_WARNING("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2060 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2061 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2062 G_CALLBACK(__mmcamcorder_video_stream_cb),
2064 return MM_ERROR_NONE;
2066 MMCAM_LOG_ERROR("videosrc element is not created yet");
2067 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2072 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2074 int ret = MM_ERROR_NONE;
2076 char *temp_filename = NULL;
2078 _MMCamcorderVideoInfo *info = NULL;
2079 _MMCamcorderSubContext *sc = NULL;
2080 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2082 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2084 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2085 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2086 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2088 info = sc->info_video;
2090 MMCAM_LOG_WARNING("start");
2092 /* create encoding pipeline */
2093 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2094 if (ret != MM_ERROR_NONE)
2095 goto _ERR_PREPARE_RECORD;
2097 SAFE_G_FREE(info->filename);
2099 mm_camcorder_get_attributes(handle, NULL,
2100 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2102 if (temp_filename) {
2103 info->filename = g_strdup(temp_filename);
2104 if (!info->filename) {
2105 MMCAM_LOG_ERROR("strdup[src:%p] was failed", temp_filename);
2106 goto _ERR_PREPARE_RECORD;
2109 MMCAM_LOG_INFO("Record file name [%s]", info->filename);
2110 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2112 MMCAM_LOG_INFO("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2113 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2116 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2118 /* Adjust display FPS */
2119 sc->display_interval = 0;
2120 sc->previous_slot_time = 0;
2122 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2123 if (ret != MM_ERROR_NONE)
2124 goto _ERR_PREPARE_RECORD;
2126 MMCAM_LOG_WARNING("done");
2130 _ERR_PREPARE_RECORD:
2131 /* Remove recorder pipeline and recording file which size maybe zero */
2132 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2133 if (info && info->filename) {
2134 MMCAM_LOG_INFO("file delete(%s)", info->filename);
2135 unlink(info->filename);