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 (info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
103 if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
104 MMCAM_LOG_WARNING("NOT I frame.. skip this buffer");
107 MMCAM_LOG_WARNING("[H.264] first I 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 (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
737 info->preview_width == info->video_width &&
738 info->preview_height == info->video_height) {
739 MMCAM_LOG_INFO("H264 preview mode and same resolution");
741 /* No need to restart preview */
742 info->restart_preview = FALSE;
743 } else if (info->use_videoscale &&
744 info->preview_width >= info->video_width &&
745 info->preview_height >= info->video_height) {
746 info->restart_preview = FALSE;
748 info->restart_preview = TRUE;
749 /* reset use_videoscale */
750 info->use_videoscale = FALSE;
753 /* set recording hint */
754 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
756 if (info->restart_preview) {
757 /* stop preview and set new size */
758 MMCAM_LOG_INFO("restart preview");
760 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
761 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
762 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
764 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
766 /* check decoder recreation */
767 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
768 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
769 ret = MM_ERROR_CAMCORDER_INTERNAL;
770 goto _ERR_CAMCORDER_VIDEO_COMMAND;
773 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
774 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
775 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
777 if (ret != MM_ERROR_NONE)
778 goto _ERR_CAMCORDER_VIDEO_COMMAND;
780 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
781 ret = MM_ERROR_CAMCORDER_INTERNAL;
782 goto _ERR_CAMCORDER_VIDEO_COMMAND;
785 /* Start preview again with new setting */
786 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
787 if (ret != MM_ERROR_NONE)
788 goto _ERR_CAMCORDER_VIDEO_COMMAND;
790 if (motion_rate < 1.0) {
791 MMCAM_LOG_WARNING("wait for stabilization of frame");
795 MMCAM_LOG_INFO("no need to restart preview");
798 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
799 CONFIGURE_CATEGORY_MAIN_RECORD,
803 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
804 CONFIGURE_CATEGORY_MAIN_RECORD,
805 "PassFirstVideoFrame",
806 &(sc->pass_first_vframe));
808 MMCAM_LOG_INFO("Drop video frame count[%d], Pass fisrt video frame count[%d]",
809 sc->drop_vframe, sc->pass_first_vframe);
811 info->record_drop_count = (guint)motion_rate;
812 info->record_motion_rate = motion_rate;
813 if (sc->is_modified_rate)
814 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
816 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
818 MMCAM_LOG_WARNING("recording fps %d, motion rate %f, timestamp_ratio %f",
819 fps, info->record_motion_rate, info->record_timestamp_ratio);
821 /* set push buffer flag */
822 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
823 info->base_video_ts = 0;
825 /* connect video stream cb signal if it supports dual stream. */
826 if (info->record_dual_stream) {
827 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
828 goto _ERR_CAMCORDER_VIDEO_COMMAND;
831 /* start video stream */
832 if (info->record_dual_stream) {
833 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
835 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
837 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
838 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
840 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
842 MMCAM_LOG_ERROR("could not get camera control");
846 /* check pre-created encode pipeline */
847 g_mutex_lock(&hcamcorder->task_thread_lock);
848 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
849 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
850 /* create encoding pipeline */
851 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
852 if (ret != MM_ERROR_NONE) {
853 g_mutex_unlock(&hcamcorder->task_thread_lock);
854 goto _ERR_CAMCORDER_VIDEO_COMMAND;
857 g_mutex_unlock(&hcamcorder->task_thread_lock);
859 /* check recording start sound */
860 _mmcamcorder_sound_solo_play_wait(handle);
862 /**< To fix video recording hanging
863 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
864 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
865 basetime wouldn't change if you set (GstClockTime)0.
866 3. Move set start time position below PAUSED of pipeline.
869 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
870 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
873 info->video_frame_count = 0;
874 info->is_first_frame = TRUE;
875 info->audio_frame_count = 0;
877 sc->ferror_send = FALSE;
878 sc->ferror_count = 0;
879 hcamcorder->error_occurs = FALSE;
880 sc->bget_eos = FALSE;
881 sc->muxed_stream_offset = 0;
883 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
884 if (ret != MM_ERROR_NONE) {
885 /* stop video stream */
886 if (info->record_dual_stream) {
887 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
889 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
891 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
892 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
894 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
896 MMCAM_LOG_ERROR("failed to get camera control");
900 /* Remove recorder pipeline and recording file which size maybe zero */
901 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
902 if (info->filename) {
903 MMCAM_LOG_INFO("file delete(%s)", info->filename);
904 unlink(info->filename);
906 goto _ERR_CAMCORDER_VIDEO_COMMAND;
909 /*set the GOP so that video record will get a new key frame*/
910 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
911 if (mm_camcorder_get_attributes(handle, NULL,
912 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
913 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
915 MMCAM_LOG_ERROR("get gop interval failed");
919 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
920 if (mm_camcorder_get_attributes(handle, NULL,
921 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
922 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
924 MMCAM_LOG_ERROR("get gop interval failed");
927 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
929 MMCAM_LOG_INFO("Object property settings done");
933 case _MMCamcorder_CMD_PAUSE:
935 if (info->b_committing) {
936 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
937 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
940 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
941 if (sc->audio_disable) {
942 /* check only video frame */
943 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
945 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
946 MMCAM_LOG_ERROR("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
947 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
949 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
952 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
954 /* check both of video and audio frame */
955 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
957 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
958 MMCAM_LOG_ERROR("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
959 info->video_frame_count, info->audio_frame_count);
960 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
962 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
963 count, info->video_frame_count, info->audio_frame_count);
966 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
970 /* block encodebin */
971 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
974 case _MMCamcorder_CMD_CANCEL:
976 if (info->b_committing) {
977 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
978 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
981 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
983 if (hcamcorder->capture_in_recording == FALSE) {
985 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
986 MMCAM_LOG_ERROR("Failed to Wait capture data");
987 hcamcorder->capture_in_recording = FALSE;
990 MMCAM_LOG_WARNING("Waiting for capture data - retrial [%d]", count);
993 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
996 /* block push buffer */
997 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
999 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1000 if (ret != MM_ERROR_NONE)
1001 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1003 /* set recording hint */
1004 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1006 /* stop video stream */
1007 if (info->record_dual_stream) {
1008 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1009 if (CameraControl) {
1010 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1012 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1013 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1015 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1017 MMCAM_LOG_ERROR("failed to get camera control");
1021 if (info->restart_preview) {
1022 /* restart preview */
1023 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1024 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1025 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1027 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1029 /* check decoder recreation */
1030 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1031 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1032 ret = MM_ERROR_CAMCORDER_INTERNAL;
1035 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1036 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1037 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1039 if (ret != MM_ERROR_NONE)
1040 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1042 /* reset restart_preview for inset window layout */
1043 info->restart_preview = FALSE;
1045 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1046 ret = MM_ERROR_CAMCORDER_INTERNAL;
1047 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1050 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1051 if (ret != MM_ERROR_NONE)
1052 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1055 /* remove target file */
1056 if (info->filename) {
1057 MMCAM_LOG_INFO("file delete(%s)", info->filename);
1058 unlink(info->filename);
1061 sc->isMaxsizePausing = FALSE;
1062 sc->isMaxtimePausing = FALSE;
1064 sc->display_interval = 0;
1065 sc->previous_slot_time = 0;
1066 info->video_frame_count = 0;
1067 info->audio_frame_count = 0;
1069 hcamcorder->capture_in_recording = FALSE;
1072 case _MMCamcorder_CMD_COMMIT:
1076 if (info->b_committing) {
1077 MMCAM_LOG_ERROR("now on committing previous file!!(command : %d)", command);
1078 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1080 MMCAM_LOG_INFO("_MMCamcorder_CMD_COMMIT : start");
1081 info->b_committing = TRUE;
1082 sc->bget_eos = FALSE;
1085 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1086 if (sc->audio_disable) {
1087 /* check only video frame */
1088 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1089 hcamcorder->capture_in_recording == FALSE) {
1091 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1092 MMCAM_LOG_ERROR("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1093 info->video_frame_count, hcamcorder->capture_in_recording);
1095 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1096 MMCAM_LOG_WARNING("video frames are enough. keep going...");
1098 info->b_committing = FALSE;
1099 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1102 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1103 count, info->video_frame_count, hcamcorder->capture_in_recording);
1106 /* check both of video and audio frame */
1107 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1108 info->audio_frame_count &&
1109 hcamcorder->capture_in_recording == FALSE) {
1111 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1112 MMCAM_LOG_ERROR("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1113 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1115 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1116 MMCAM_LOG_WARNING("video/audio frames are enough. keep going...");
1118 info->b_committing = FALSE;
1119 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1122 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1124 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1125 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1129 if (hcamcorder->capture_in_recording) {
1130 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1131 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1132 MMCAM_LOG_WARNING("timeout");
1134 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1138 /* block push buffer */
1139 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1140 MMCAM_LOG_INFO("block push buffer to appsrc");
1142 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1143 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1144 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1145 ret = MM_ERROR_OUT_OF_STORAGE;
1146 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1149 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1150 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1151 MMCAM_LOG_WARNING("VIDEO: send eos to appsrc done");
1153 MMCAM_LOG_ERROR("VIDEO: send EOS failed");
1154 info->b_committing = FALSE;
1155 ret = MM_ERROR_CAMCORDER_INTERNAL;
1156 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1159 MMCAM_LOG_ERROR("No video stream source");
1160 info->b_committing = FALSE;
1161 ret = MM_ERROR_CAMCORDER_INTERNAL;
1162 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1165 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1166 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1167 MMCAM_LOG_WARNING("AUDIO: send eos to audiosrc done");
1169 MMCAM_LOG_ERROR("AUDIO: send EOS failed");
1170 info->b_committing = FALSE;
1171 ret = MM_ERROR_CAMCORDER_INTERNAL;
1172 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1175 MMCAM_LOG_INFO("No audio stream");
1179 sc->display_interval = 0;
1180 sc->previous_slot_time = 0;
1183 MMCAM_LOG_INFO("Start to wait EOS");
1184 ret = _mmcamcorder_get_eos_message(handle);
1185 if (ret != MM_ERROR_NONE) {
1186 info->b_committing = FALSE;
1187 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1191 hcamcorder->capture_in_recording = FALSE;
1195 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1196 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1199 return MM_ERROR_NONE;
1201 _ERR_CAMCORDER_VIDEO_COMMAND:
1202 if (command == _MMCamcorder_CMD_RECORD)
1203 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1209 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1211 int ret = MM_ERROR_NONE;
1213 guint64 file_size = 0;
1215 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1216 _MMCamcorderSubContext *sc = NULL;
1217 _MMCamcorderVideoInfo *info = NULL;
1218 _MMCamcorderMsgItem msg;
1219 MMCamRecordingReport *report = NULL;
1221 mmf_return_val_if_fail(hcamcorder, FALSE);
1223 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1224 mmf_return_val_if_fail(sc, FALSE);
1225 mmf_return_val_if_fail(sc->info_video, FALSE);
1227 info = sc->info_video;
1229 MMCAM_LOG_ERROR("");
1231 /* Play record stop sound */
1232 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1234 /* remove blocking part */
1235 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1237 mm_camcorder_get_attributes(handle, NULL,
1238 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1241 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1242 if (ret != MM_ERROR_NONE)
1243 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1245 /* set recording hint */
1246 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1248 /* stop video stream */
1249 if (info->record_dual_stream) {
1250 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1252 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1254 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1255 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1257 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1259 MMCAM_LOG_ERROR("failed to get camera control");
1263 if (enabletag && !(sc->ferror_send)) {
1264 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1265 MMCAM_LOG_INFO("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1268 /* Check file size */
1269 if (info->max_size > 0) {
1270 _mmcamcorder_get_file_size(info->filename, &file_size);
1271 MMCAM_LOG_INFO("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1272 info->max_size, file_size);
1274 if (file_size > info->max_size) {
1275 _MMCamcorderMsgItem message;
1276 MMCAM_LOG_ERROR("File size is greater than max size !!");
1277 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1278 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1279 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1283 if (info->restart_preview) {
1285 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1286 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1287 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1289 MMCAM_LOG_INFO("Set state of pipeline as READY");
1290 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1292 /* check decoder recreation */
1293 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1294 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1295 ret = MM_ERROR_CAMCORDER_INTERNAL;
1299 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1300 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1301 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1303 if (ret != MM_ERROR_NONE) {
1304 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1305 msg.param.code = ret;
1306 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1307 MMCAM_LOG_ERROR("Failed to set state READY[%x]", ret);
1310 /* reset restart_preview for inset window layout */
1311 info->restart_preview = FALSE;
1313 /* recover preview size */
1314 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1315 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1316 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1317 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1318 MMCAM_LOG_ERROR("Failed to set camera resolution %dx%d",
1319 info->preview_width, info->preview_height);
1322 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1323 /* Do not return when error is occurred.
1324 Recording file was created successfully, but starting pipeline failed */
1325 if (ret != MM_ERROR_NONE) {
1326 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1327 msg.param.code = ret;
1328 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1329 MMCAM_LOG_ERROR("Failed to set state PLAYING[%x]", ret);
1332 MMCAM_LOG_INFO("No need to restart preview");
1335 /* Send recording report to application */
1336 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1337 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1338 report->recording_filename = g_strdup(info->filename);
1339 msg.param.data = report;
1341 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1344 sc->pipeline_time = 0;
1346 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1347 sc->isMaxtimePausing = FALSE;
1348 hcamcorder->error_occurs = FALSE;
1350 info->video_frame_count = 0;
1351 info->audio_frame_count = 0;
1353 info->b_committing = FALSE;
1355 /* check recording stop sound */
1356 _mmcamcorder_sound_solo_play_wait(handle);
1358 MMCAM_LOG_ERROR("_MMCamcorder_CMD_COMMIT : end");
1364 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1366 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1367 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1369 _MMCamcorderSubContext *sc = NULL;
1370 _MMCamcorderVideoInfo *videoinfo = NULL;
1371 _MMCamcorderMsgItem msg;
1372 guint64 buffer_size = 0;
1373 guint64 trailer_size = 0;
1374 guint64 max_size = 0;
1376 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1377 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1378 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1380 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1381 videoinfo = sc->info_video;
1383 /* get buffer size */
1384 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1385 MMCAM_LOG_WARNING("map failed : buffer %p", buffer);
1386 return GST_PAD_PROBE_OK;
1389 buffer_size = mapinfo.size;
1390 gst_buffer_unmap(buffer, &mapinfo);
1392 g_mutex_lock(&videoinfo->size_check_lock);
1394 if (videoinfo->audio_frame_count == 0) {
1395 videoinfo->filesize += buffer_size;
1396 videoinfo->audio_frame_count++;
1397 g_mutex_unlock(&videoinfo->size_check_lock);
1398 return GST_PAD_PROBE_OK;
1401 if (sc->ferror_send || sc->isMaxsizePausing) {
1402 MMCAM_LOG_WARNING("Recording is paused, drop frames");
1403 g_mutex_unlock(&videoinfo->size_check_lock);
1404 return GST_PAD_PROBE_DROP;
1407 /* get trailer size */
1408 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1409 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1413 /* check max size of recorded file */
1414 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1415 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1416 GstState pipeline_state = GST_STATE_VOID_PENDING;
1417 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1419 MMCAM_LOG_WARNING("Max size[%"G_GUINT64_FORMAT"], current size[%"G_GUINT64_FORMAT"],"\
1420 " buffer size[%"G_GUINT64_FORMAT"], trailer size[%"G_GUINT64_FORMAT"]",
1421 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1423 if (!sc->isMaxsizePausing) {
1424 sc->isMaxsizePausing = TRUE;
1425 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1426 if (pipeline_state == GST_STATE_PLAYING)
1427 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1429 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1430 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1433 g_mutex_unlock(&videoinfo->size_check_lock);
1438 videoinfo->filesize += buffer_size;
1439 videoinfo->audio_frame_count++;
1441 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1442 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1444 g_mutex_unlock(&videoinfo->size_check_lock);
1446 return GST_PAD_PROBE_OK;
1450 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1455 guint64 free_space = 0;
1456 guint64 buffer_size = 0;
1457 guint64 trailer_size = 0;
1458 guint64 queued_buffer = 0;
1459 guint64 max_size = 0;
1460 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1462 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1464 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1465 _MMCamcorderMsgItem msg;
1466 _MMCamcorderSubContext *sc = NULL;
1467 _MMCamcorderVideoInfo *videoinfo = NULL;
1469 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1470 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1472 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1473 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1474 videoinfo = sc->info_video;
1476 if (sc->ferror_send) {
1477 MMCAM_LOG_WARNING("file write error, drop frames");
1478 return GST_PAD_PROBE_DROP;
1481 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1482 buffer_size = mapinfo.size;
1483 gst_buffer_unmap(buffer, &mapinfo);
1485 videoinfo->video_frame_count++;
1486 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1487 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1488 g_mutex_lock(&videoinfo->size_check_lock);
1489 videoinfo->filesize += buffer_size;
1490 g_mutex_unlock(&videoinfo->size_check_lock);
1491 return GST_PAD_PROBE_OK;
1494 /* get trailer size */
1495 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1496 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1500 /* check free space */
1501 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1503 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1504 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1505 sc->ferror_send = TRUE;
1507 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1508 msg.param.code = MM_ERROR_FILE_READ;
1510 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1515 return GST_PAD_PROBE_DROP; /* skip this buffer */
1518 if (free_space == 0) {
1519 /* check storage state */
1520 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1522 MMCAM_LOG_WARNING("storage state %d", storage_state);
1524 if (storage_state == STORAGE_STATE_REMOVED ||
1525 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1526 MMCAM_LOG_ERROR("storage was removed!");
1528 _MMCAMCORDER_LOCK(hcamcorder);
1530 if (sc->ferror_send == FALSE) {
1531 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1533 sc->ferror_send = TRUE;
1535 _MMCAMCORDER_UNLOCK(hcamcorder);
1537 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1538 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1540 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1542 _MMCAMCORDER_UNLOCK(hcamcorder);
1543 MMCAM_LOG_WARNING("error was already sent");
1546 return GST_PAD_PROBE_DROP;
1550 /* get queued buffer size */
1551 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1552 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1554 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1555 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1557 queued_buffer = aq_size + vq_size;
1559 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1560 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1561 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1562 free_space, trailer_size, buffer_size, queued_buffer);
1564 if (!sc->isMaxsizePausing) {
1565 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1566 sc->isMaxsizePausing = TRUE;
1568 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1569 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1572 return GST_PAD_PROBE_DROP;
1575 g_mutex_lock(&videoinfo->size_check_lock);
1577 /* check max size of recorded file */
1578 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1579 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1580 GstState pipeline_state = GST_STATE_VOID_PENDING;
1581 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1583 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1584 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1585 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1587 if (!sc->isMaxsizePausing) {
1588 sc->isMaxsizePausing = TRUE;
1589 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1590 if (pipeline_state == GST_STATE_PLAYING)
1591 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1593 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1594 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1597 g_mutex_unlock(&videoinfo->size_check_lock);
1599 return GST_PAD_PROBE_DROP;
1602 videoinfo->filesize += (guint64)buffer_size;
1604 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1605 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1607 g_mutex_unlock(&videoinfo->size_check_lock);
1609 return GST_PAD_PROBE_OK;
1613 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1615 guint64 trailer_size = 0;
1616 guint64 rec_pipe_time = 0;
1617 unsigned int remained_time = 0;
1619 GstClockTime b_time;
1621 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1622 _MMCamcorderMsgItem msg;
1623 _MMCamcorderSubContext *sc = NULL;
1624 _MMCamcorderVideoInfo *videoinfo = NULL;
1626 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1628 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1629 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1631 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1632 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1633 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1635 videoinfo = sc->info_video;
1637 b_time = GST_BUFFER_PTS(buffer);
1639 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1641 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1642 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1646 /* check max time */
1647 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1648 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1649 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1651 if (!sc->isMaxtimePausing) {
1652 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1654 sc->isMaxtimePausing = TRUE;
1656 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1657 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1658 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1659 msg.param.recording_status.remained_time = 0;
1660 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1662 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1663 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1666 return GST_PAD_PROBE_DROP;
1669 /* calculate remained time can be recorded */
1670 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1671 remained_time = videoinfo->max_time - rec_pipe_time;
1672 } else if (videoinfo->max_size > 0) {
1673 long double max_size = (long double)videoinfo->max_size;
1674 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1676 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1679 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1680 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1681 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1682 msg.param.recording_status.remained_time = remained_time;
1683 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1685 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1686 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1688 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1689 record_motion_rate, videoinfo->record_drop_count);
1691 /* drop some frame if fast motion */
1692 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1693 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1694 MMCAM_LOG_VERBOSE("drop frame");
1695 return GST_PAD_PROBE_DROP;
1698 videoinfo->record_drop_count = 1;
1699 MMCAM_LOG_VERBOSE("pass frame");
1702 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1703 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1706 return GST_PAD_PROBE_OK;
1710 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1712 _MMCamcorderMsgItem msg;
1713 guint64 trailer_size = 0;
1714 guint64 rec_pipe_time = 0;
1715 _MMCamcorderSubContext *sc = NULL;
1716 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1717 _MMCamcorderVideoInfo *videoinfo = NULL;
1718 unsigned int remained_time = 0;
1719 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1721 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1722 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1723 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1725 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1726 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1727 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1729 videoinfo = sc->info_video;
1731 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1732 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1733 return GST_PAD_PROBE_OK;
1736 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1738 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1739 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1743 /* calculate remained time can be recorded */
1744 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1745 remained_time = videoinfo->max_time - rec_pipe_time;
1746 } else if (videoinfo->max_size > 0) {
1747 long double max_size = (long double)videoinfo->max_size;
1748 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1750 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1753 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1754 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1755 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1757 if (!sc->isMaxtimePausing) {
1758 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1760 sc->isMaxtimePausing = TRUE;
1762 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1763 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1764 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1765 msg.param.recording_status.remained_time = 0;
1766 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1768 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1769 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1772 return GST_PAD_PROBE_DROP;
1775 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1776 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1777 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1778 msg.param.recording_status.remained_time = remained_time;
1779 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1781 MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1782 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1784 return GST_PAD_PROBE_OK;
1788 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1790 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1791 double volume = 0.0;
1794 int err = MM_ERROR_UNKNOWN;
1795 char *err_name = NULL;
1796 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1799 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1800 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1802 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1803 MMCAM_AUDIO_VOLUME, &volume,
1804 MMCAM_AUDIO_FORMAT, &format,
1805 MMCAM_AUDIO_CHANNEL, &channel,
1807 if (err != MM_ERROR_NONE) {
1808 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1809 SAFE_FREE(err_name);
1813 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1815 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1817 /* Set audio stream NULL */
1819 memset(mapinfo.data, 0, mapinfo.size);
1821 MMCAM_LOG_DEBUG("audio stream[%"GST_TIME_FORMAT"] - cb[%p], fmt[%d], ch[%d], size[%"G_GSIZE_FORMAT"]",
1822 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), hcamcorder->astream_cb, format, channel, mapinfo.size);
1824 /* CALL audio stream callback */
1825 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1826 MMCamcorderAudioStreamDataType stream;
1828 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1829 MMCAM_LOG_WARNING("Not ready for stream callback");
1830 gst_buffer_unmap(buffer, &mapinfo);
1831 return GST_PAD_PROBE_OK;
1834 stream.data = (void *)mapinfo.data;
1835 stream.format = format;
1836 stream.channel = channel;
1837 stream.length = mapinfo.size;
1838 stream.timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)));
1840 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1842 if (hcamcorder->astream_cb)
1843 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1845 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1848 gst_buffer_unmap(buffer, &mapinfo);
1850 return GST_PAD_PROBE_OK;
1854 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1856 gboolean bret = FALSE;
1858 switch (fileformat) {
1859 case MM_FILE_FORMAT_3GP:
1860 case MM_FILE_FORMAT_MP4:
1861 bret = __mmcamcorder_add_metadata_mp4(handle);
1864 MMCAM_LOG_WARNING("Unsupported fileformat to insert location info (%d)", fileformat);
1872 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1876 guint64 udta_size = 0;
1877 gint64 current_pos = 0;
1878 gint64 moov_pos = 0;
1879 gint64 udta_pos = 0;
1880 gdouble longitude = 0;
1881 gdouble latitude = 0;
1882 gdouble altitude = 0;
1884 int orientation = 0;
1886 char *err_name = NULL;
1887 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1888 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1889 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1891 _MMCamcorderVideoInfo *info = NULL;
1892 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1893 _MMCamcorderSubContext *sc = NULL;
1895 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1896 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1898 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1899 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1903 info = sc->info_video;
1905 f = fopen64(info->filename, "rb+");
1907 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1908 MMCAM_LOG_ERROR("file open failed [%s]", err_msg);
1912 mm_camcorder_get_attributes(handle, &err_name,
1913 MMCAM_TAG_LATITUDE, &latitude,
1914 MMCAM_TAG_LONGITUDE, &longitude,
1915 MMCAM_TAG_ALTITUDE, &altitude,
1916 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1917 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1920 MMCAM_LOG_WARNING("Get tag attrs fail. (%s:%x)", err_name, err);
1921 SAFE_FREE(err_name);
1924 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1925 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1926 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1927 geo_info.longitude = longitude *10000;
1928 geo_info.latitude = latitude *10000;
1929 geo_info.altitude = altitude *10000;
1930 /* find udta container.
1931 if, there are udta container, write loci box after that
1932 else, make udta container and write loci box. */
1933 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1936 MMCAM_LOG_INFO("find udta container");
1939 if (fseek(f, -8L, SEEK_CUR) != 0)
1942 udta_pos = ftello(f);
1946 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1948 MMCAM_LOG_INFO("recorded file fread %zu", nread);
1950 udta_size = _mmcamcorder_get_container_size(buf);
1952 /* goto end of udta and write 'loci' box */
1953 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1957 if (!_mmcamcorder_write_loci(f, location_info)) {
1958 MMCAM_LOG_ERROR("failed to write loci");
1962 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1963 MMCAM_LOG_ERROR("failed to write geodata");
1968 current_pos = ftello(f);
1969 if (current_pos < 0)
1972 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1975 MMCAM_LOG_INFO("No udta container");
1976 if (fseek(f, 0, SEEK_END) != 0)
1979 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1980 MMCAM_LOG_ERROR("failed to write udta");
1985 /* find moov container.
1986 update moov container size. */
1987 if ((current_pos = ftello(f)) < 0)
1990 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1991 gint64 internal_pos = ftello(f);
1993 MMCAM_LOG_INFO("found moov container");
1994 if (fseek(f, -8L, SEEK_CUR) != 0)
1997 moov_pos = ftello(f);
2001 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2004 /* add orientation info */
2005 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2006 MMCAM_LOG_ERROR("fseeko failed : errno %d", errno);
2010 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2011 MMCAM_LOG_ERROR("failed to find [trak] tag");
2015 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2016 MMCAM_LOG_ERROR("failed to find [tkhd] tag");
2020 MMCAM_LOG_INFO("found [tkhd] tag");
2022 /* seek to start position of composition matrix */
2023 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2024 /* update composition matrix for orientation */
2025 _mmcamcorder_update_composition_matrix(f, orientation);
2027 MMCAM_LOG_ERROR("fseek failed : errno %d", errno);
2031 MMCAM_LOG_ERROR("No 'moov' container");
2043 MMCAM_LOG_ERROR("ftell() returns negative value.");
2049 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2051 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2052 _MMCamcorderSubContext *sc = NULL;
2054 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2056 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2057 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2059 /* check video source element */
2060 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2061 MMCAM_LOG_WARNING("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2062 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2063 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2064 G_CALLBACK(__mmcamcorder_video_stream_cb),
2066 return MM_ERROR_NONE;
2068 MMCAM_LOG_ERROR("videosrc element is not created yet");
2069 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2074 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2076 int ret = MM_ERROR_NONE;
2078 char *temp_filename = NULL;
2080 _MMCamcorderVideoInfo *info = NULL;
2081 _MMCamcorderSubContext *sc = NULL;
2082 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2084 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2086 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2087 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2088 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2090 info = sc->info_video;
2092 MMCAM_LOG_WARNING("start");
2094 /* create encoding pipeline */
2095 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2096 if (ret != MM_ERROR_NONE)
2097 goto _ERR_PREPARE_RECORD;
2099 SAFE_G_FREE(info->filename);
2101 mm_camcorder_get_attributes(handle, NULL,
2102 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2104 if (temp_filename) {
2105 info->filename = g_strdup(temp_filename);
2106 if (!info->filename) {
2107 MMCAM_LOG_ERROR("strdup[src:%p] was failed", temp_filename);
2108 goto _ERR_PREPARE_RECORD;
2111 MMCAM_LOG_INFO("Record file name [%s]", info->filename);
2112 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2114 MMCAM_LOG_INFO("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2115 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2118 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2120 /* Adjust display FPS */
2121 sc->display_interval = 0;
2122 sc->previous_slot_time = 0;
2124 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2125 if (ret != MM_ERROR_NONE)
2126 goto _ERR_PREPARE_RECORD;
2128 MMCAM_LOG_WARNING("done");
2132 _ERR_PREPARE_RECORD:
2133 /* Remove recorder pipeline and recording file which size maybe zero */
2134 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2135 if (info && info->filename) {
2136 MMCAM_LOG_INFO("file delete(%s)", info->filename);
2137 unlink(info->filename);