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 gboolean __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, GstBuffer *buffer)
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 */
71 mmf_return_val_if_fail(hcamcorder, FALSE);
72 mmf_return_val_if_fail(MMF_CAMCORDER_SUBCONTEXT(hcamcorder), FALSE);
74 mmf_return_val_if_fail(buffer, FALSE);
75 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
77 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
79 mmf_return_val_if_fail(sc->info_image, FALSE);
80 mmf_return_val_if_fail(sc->info_video, FALSE);
81 mmf_return_val_if_fail(sc->encode_element, FALSE);
83 info_image = sc->info_image;
84 info_video = sc->info_video;
85 element = sc->encode_element;
87 if (info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
88 element[_MMCAMCORDER_ENCSINK_SRC].gst) {
90 GstClock *clock = NULL;
92 MMCAM_LOG_VERBOSE("GST_BUFFER_FLAG_DELTA_UNIT is set : %d",
93 GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT));
95 current_ts = GST_BUFFER_PTS(buffer);
97 if (info_video->is_first_frame) {
98 /* check first I frame for H.264 stream */
99 if (info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
100 if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
101 MMCAM_LOG_WARNING("NOT I frame.. skip this buffer");
104 MMCAM_LOG_WARNING("[H.264] first I frame");
108 /* set base timestamp */
109 if (element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
110 clock = GST_ELEMENT_CLOCK(element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
112 gst_object_ref(clock);
113 info_video->base_video_ts = current_ts - (gst_clock_get_time(clock) - \
114 GST_ELEMENT(element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
115 gst_object_unref(clock);
118 /* for image capture with encodebin and v4l2src */
119 if (sc->bencbin_capture && info_image->capturing) {
120 g_mutex_lock(&hcamcorder->task_thread_lock);
121 MMCAM_LOG_INFO("send signal for sound play");
122 hcamcorder->task_thread_state = _MMCAMCORDER_TASK_THREAD_STATE_SOUND_SOLO_PLAY_START;
123 g_cond_signal(&hcamcorder->task_thread_cond);
124 g_mutex_unlock(&hcamcorder->task_thread_lock);
126 info_video->base_video_ts = current_ts;
129 if (_mmcamcorder_invoke_video_stream_cb(handle, buffer, FALSE) == FALSE) {
130 /* increase base video timestamp by frame duration,
131 it will remove delay of dropped buffer when play recorded file. */
132 info_video->base_video_ts += current_ts - info_video->last_video_ts;
133 MMCAM_LOG_DEBUG("do not push buffer to encode by app's return value");
134 goto _VIDEO_PUSH_BUFFER_DONE;
138 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer) = current_ts - info_video->base_video_ts;
140 MMCAM_LOG_DEBUG("buffer %p, timestamp %"GST_TIME_FORMAT,
141 buffer, GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));
143 if (info_video->record_dual_stream) {
144 /* It will NOT INCREASE reference count of buffer */
145 ret = gst_app_src_push_buffer((GstAppSrc *)element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
147 /* It will INCREASE reference count of buffer */
148 g_signal_emit_by_name(element[_MMCAMCORDER_ENCSINK_SRC].gst, "push-buffer", buffer, &ret);
151 MMCAM_LOG_VERBOSE("push buffer result : 0x%x", ret);
153 _VIDEO_PUSH_BUFFER_DONE:
154 info_video->last_video_ts = current_ts;
156 if (info_video->is_first_frame) {
157 info_video->is_first_frame = FALSE;
159 /* drop buffer if it's from tizen allocator */
160 if (gst_is_tizen_memory(gst_buffer_peek_memory(buffer, 0))) {
161 MMCAM_LOG_WARNING("drop first buffer from tizen allocator to avoid copy in basesrc");
167 /* skip display if too fast FPS */
168 if (info_video->record_dual_stream == FALSE &&
169 info_video->fps > _MMCAMCORDER_FRAME_PASS_MIN_FPS) {
170 if (info_video->prev_preview_ts != 0) {
171 if (GST_BUFFER_PTS(buffer) - info_video->prev_preview_ts < _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME) {
172 MMCAM_LOG_VERBOSE("it's too fast. drop frame...");
177 MMCAM_LOG_VERBOSE("display buffer [%p]", buffer);
179 info_video->prev_preview_ts = GST_BUFFER_PTS(buffer);
186 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
188 return _mmcamcorder_video_push_buffer(u_data, gst_sample_get_buffer(sample));
192 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
195 int err = MM_ERROR_NONE;
196 const char* gst_element_rsink_name = NULL;
199 GstPad *srcpad = NULL;
200 GstPad *sinkpad = NULL;
202 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
203 _MMCamcorderSubContext *sc = NULL;
205 type_element *RecordsinkElement = NULL;
207 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
209 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
210 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
211 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
213 MMCAM_LOG_WARNING("start");
215 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
216 if (err != MM_ERROR_NONE)
220 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
221 MMCAM_LOG_INFO("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
222 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
223 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
226 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
228 /* get audio disable */
229 mm_camcorder_get_attributes(handle, NULL,
230 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
233 MMCAM_LOG_INFO("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d, ved_cb %p",
234 sc->audio_disable, sc->is_modified_rate, hcamcorder->vedecision_cb);
236 if (sc->is_modified_rate || hcamcorder->vedecision_cb)
237 sc->audio_disable = TRUE;
239 if (sc->audio_disable == FALSE) {
240 /* create audiosrc bin */
241 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
242 if (err != MM_ERROR_NONE)
246 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
247 if (err != MM_ERROR_NONE)
250 if (sc->audio_disable == FALSE) {
251 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
252 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
255 /* add elements and encodesink bin to encode main pipeline */
256 if (sc->info_video->use_videoscale) {
257 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
258 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
259 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
260 sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst,
261 sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst,
262 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
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_BIN].gst,
272 /* Link each element : appsrc - capsfilter - encodesink bin */
273 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
274 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
275 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
277 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
278 if (sc->info_video->use_videoscale) {
279 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst, "sink");
280 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
282 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst, "src");
283 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, "sink");
284 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
286 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, "src");
288 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
289 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
291 if (sc->audio_disable == FALSE) {
292 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
293 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
294 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
297 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
298 CONFIGURE_CATEGORY_MAIN_RECORD,
301 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
303 if (!gst_element_rsink_name) {
304 MMCAM_LOG_ERROR("failed to get recordsink name");
305 err = MM_ERROR_CAMCORDER_INTERNAL;
306 goto pipeline_creation_error;
309 /* set data probe function */
311 /* register message cb */
313 /* set data probe functions */
314 if (sc->audio_disable == FALSE) {
315 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
316 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
317 __mmcamcorder_audioque_dataprobe, hcamcorder);
318 gst_object_unref(sinkpad);
322 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
323 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
324 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
325 gst_object_unref(srcpad);
328 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
329 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
330 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
331 __mmcamcorder_eventprobe_monitor, hcamcorder);
332 gst_object_unref(srcpad);
337 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
338 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
339 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
340 __mmcamcorder_eventprobe_monitor, hcamcorder);
341 gst_object_unref(srcpad);
345 if (sc->audio_disable) {
346 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
347 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
348 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
349 gst_object_unref(sinkpad);
353 if (!strcmp(gst_element_rsink_name, "filesink")) {
354 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
355 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
356 __mmcamcorder_video_dataprobe_encoded, hcamcorder);
357 gst_object_unref(srcpad);
360 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
361 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
362 __mmcamcorder_audio_dataprobe_check, hcamcorder);
363 gst_object_unref(srcpad);
367 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
368 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
369 __mmcamcorder_muxed_dataprobe, hcamcorder);
370 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
371 __mmcamcorder_eventprobe_monitor, hcamcorder);
372 gst_object_unref(sinkpad);
375 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
377 /* register pipeline message callback */
378 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
380 /* set sync handler */
381 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
383 gst_object_unref(bus);
386 return MM_ERROR_NONE;
388 pipeline_creation_error:
389 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
390 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
392 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
397 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
399 GstPad *srcpad = NULL;
400 GstPad *sinkpad = NULL;
401 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
402 _MMCamcorderSubContext *sc = NULL;
404 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
406 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
407 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
408 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
412 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
413 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
414 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
415 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
417 /* release audiosrc bin */
418 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
419 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
422 To avoid conflicting between old elements and newly created elements,
423 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
424 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
425 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
426 It's because the pipeline of audio recording destroys at the same time,
427 and '_mmcamcorder_element_release_noti' will perfom removing handle.
429 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
431 MMCAM_LOG_INFO("Audio pipeline removed");
434 return MM_ERROR_NONE;
438 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
440 GstPad *reqpad = NULL;
441 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
442 _MMCamcorderSubContext *sc = NULL;
443 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
444 int ret = MM_ERROR_NONE;
445 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
447 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
449 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
450 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
451 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
455 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
456 /* release request pad */
457 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
459 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
460 gst_object_unref(reqpad);
464 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
466 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
467 gst_object_unref(reqpad);
471 /* release encode main pipeline */
472 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
475 To avoid conflicting between old elements and newly created elements,
476 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
477 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
478 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
479 It's because the pipeline of audio recording destroys at the same time,
480 and '_mmcamcorder_element_release_noti' will perfom removing handle.
482 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
483 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
485 MMCAM_LOG_WARNING("Encoder pipeline removed");
487 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
488 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
490 MMCAM_LOG_WARNING("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
492 if (hcamcorder->is_release_cb_calling == FALSE) {
493 /* release resource */
494 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
495 hcamcorder->video_encoder_resource);
496 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
497 hcamcorder->video_encoder_resource = NULL;
499 MMCAM_LOG_WARNING("mark resource for release 0x%x", ret);
501 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
503 MMCAM_LOG_WARNING("commit resource release 0x%x", ret);
506 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
508 MMCAM_LOG_WARNING("unlock resource");
509 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
512 return MM_ERROR_NONE;
516 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
518 int ret = MM_ERROR_NONE;
519 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
520 _MMCamcorderSubContext *sc = NULL;
524 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
525 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
526 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
528 MMCAM_LOG_INFO("start");
530 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
531 MMCAM_LOG_WARNING("pipeline is not existed.");
532 return MM_ERROR_NONE;
535 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
537 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
538 if (ret != MM_ERROR_NONE) {
539 MMCAM_LOG_ERROR("Failed to change encode main pipeline [0x%x]", ret);
543 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
545 /* remove audio pipeline first */
546 ret = _mmcamcorder_remove_audio_pipeline(handle);
547 if (ret != MM_ERROR_NONE) {
548 MMCAM_LOG_ERROR("Fail to remove audio pipeline");
552 ret = _mmcamcorder_remove_encode_pipeline(handle);
553 if (ret != MM_ERROR_NONE) {
554 MMCAM_LOG_ERROR("Fail to remove encoder pipeline");
558 /* Remove pipeline message callback */
559 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
560 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
561 hcamcorder->encode_pipeline_cb_event_id = 0;
564 /* Remove remained message */
566 GstMessage *gst_msg = NULL;
567 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
568 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
569 gst_message_unref(gst_msg);
572 gst_object_unref(bus);
576 MMCAM_LOG_INFO("done");
582 int _mmcamcorder_video_command(MMHandleType handle, int command)
587 int gop_interval = 0;
588 int ret = MM_ERROR_NONE;
589 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
590 char *err_name = NULL;
591 char *target_filename = NULL;
592 GstCameraControl *CameraControl = NULL;
595 GstElement *pipeline = NULL;
597 _MMCamcorderVideoInfo *info = NULL;
598 _MMCamcorderSubContext *sc = NULL;
599 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
601 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
603 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
604 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
605 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
606 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
608 info = sc->info_video;
610 MMCAM_LOG_INFO("Command(%d)", command);
612 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
615 case _MMCamcorder_CMD_RECORD:
617 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
621 gboolean storage_validity = FALSE;
624 int root_directory_length = 0;
627 MMCAM_LOG_INFO("Record Start - dual stream %d", info->support_dual_stream);
629 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
630 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
632 /* prepare resource manager for H/W encoder */
633 if (hcamcorder->video_encoder_resource == NULL) {
634 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
635 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
636 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
637 &hcamcorder->video_encoder_resource);
638 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
639 MMCAM_LOG_ERROR("could not prepare for encoder resource");
640 ret = MM_ERROR_RESOURCE_INTERNAL;
641 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
642 goto _ERR_CAMCORDER_VIDEO_COMMAND;
645 MMCAM_LOG_INFO("encoder already acquired");
648 /* acquire resources */
649 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
650 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
651 MMCAM_LOG_ERROR("could not acquire resources");
652 ret = MM_ERROR_RESOURCE_INTERNAL;
653 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
654 goto _ERR_CAMCORDER_VIDEO_COMMAND;
657 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
658 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
660 /* init record_dual_stream */
661 info->record_dual_stream = FALSE;
663 ret = mm_camcorder_get_attributes(handle, &err_name,
664 MMCAM_CAMERA_FPS, &fps,
665 MMCAM_CAMERA_WIDTH, &(info->preview_width),
666 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
667 MMCAM_VIDEO_WIDTH, &(info->video_width),
668 MMCAM_VIDEO_HEIGHT, &(info->video_height),
669 MMCAM_FILE_FORMAT, &fileformat,
670 MMCAM_TARGET_FILENAME, &target_filename, &size,
671 MMCAM_TARGET_MAX_SIZE, &imax_size,
672 MMCAM_TARGET_TIME_LIMIT, &imax_time,
673 MMCAM_FILE_FORMAT, &(info->fileformat),
674 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
675 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
677 if (ret != MM_ERROR_NONE) {
678 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, ret);
680 goto _ERR_CAMCORDER_VIDEO_COMMAND;
683 if (!target_filename && !hcamcorder->mstream_cb) {
684 MMCAM_LOG_ERROR("filename is not set and muxed stream cb is NULL");
685 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
686 goto _ERR_CAMCORDER_VIDEO_COMMAND;
691 info->max_size = 0; /* do not check */
693 info->max_size = ((guint64)imax_size) << 10; /* to byte */
697 info->max_time = 0; /* do not check */
699 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
701 ret = _mmcamcorder_get_storage_validity(hcamcorder, target_filename,
702 _MMCAMCORDER_VIDEO_MINIMUM_SPACE, &storage_validity);
703 if (ret != MM_ERROR_NONE) {
704 MMCAM_LOG_ERROR("storage validation failed[0x%x]:%d", ret, storage_validity);
708 _mmcamcorder_adjust_recording_max_size(target_filename, &info->max_size);
710 g_mutex_lock(&hcamcorder->task_thread_lock);
711 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
712 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
713 /* Play record start sound */
714 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
716 g_mutex_unlock(&hcamcorder->task_thread_lock);
718 MMCAM_LOG_WARNING("video size [%dx%d]", info->video_width, info->video_height);
720 if (info->video_width == 0 || info->video_height == 0) {
721 MMCAM_LOG_WARNING("video size is invalid [%dx%d] use preview size [%dx%d]",
722 info->video_width, info->video_height, info->preview_width, info->preview_height);
723 info->video_width = info->preview_width;
724 info->video_height = info->preview_height;
727 if (info->support_dual_stream) {
728 MMCAM_LOG_WARNING("DUAL STREAM MODE");
730 info->record_dual_stream = TRUE;
732 /* No need to restart preview */
733 info->restart_preview = FALSE;
735 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
736 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
737 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
738 info->preview_width == info->video_width &&
739 info->preview_height == info->video_height) {
740 MMCAM_LOG_INFO("H264 preview mode and same resolution");
742 /* No need to restart preview */
743 info->restart_preview = FALSE;
744 } else if (info->use_videoscale &&
745 info->preview_width >= info->video_width &&
746 info->preview_height >= info->video_height) {
747 info->restart_preview = FALSE;
749 info->restart_preview = TRUE;
750 /* reset use_videoscale */
751 info->use_videoscale = FALSE;
754 /* set recording hint */
755 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
757 if (info->restart_preview) {
758 /* stop preview and set new size */
759 MMCAM_LOG_INFO("restart preview");
761 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
762 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
763 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
765 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
767 /* check decoder recreation */
768 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
769 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
770 ret = MM_ERROR_CAMCORDER_INTERNAL;
771 goto _ERR_CAMCORDER_VIDEO_COMMAND;
774 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
775 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
776 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
778 if (ret != MM_ERROR_NONE)
779 goto _ERR_CAMCORDER_VIDEO_COMMAND;
781 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
782 ret = MM_ERROR_CAMCORDER_INTERNAL;
783 goto _ERR_CAMCORDER_VIDEO_COMMAND;
786 /* Start preview again with new setting */
787 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
788 if (ret != MM_ERROR_NONE)
789 goto _ERR_CAMCORDER_VIDEO_COMMAND;
791 if (motion_rate < 1.0) {
792 MMCAM_LOG_WARNING("wait for stabilization of frame");
796 MMCAM_LOG_INFO("no need to restart preview");
799 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
800 CONFIGURE_CATEGORY_MAIN_RECORD,
804 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
805 CONFIGURE_CATEGORY_MAIN_RECORD,
806 "PassFirstVideoFrame",
807 &(sc->pass_first_vframe));
809 MMCAM_LOG_INFO("Drop video frame count[%d], Pass fisrt video frame count[%d]",
810 sc->drop_vframe, sc->pass_first_vframe);
812 info->record_drop_count = (guint)motion_rate;
813 info->record_motion_rate = motion_rate;
814 if (sc->is_modified_rate)
815 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
817 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
819 MMCAM_LOG_WARNING("recording fps %d, motion rate %f, timestamp_ratio %f",
820 fps, info->record_motion_rate, info->record_timestamp_ratio);
822 /* set push buffer flag */
823 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
824 info->base_video_ts = 0;
826 /* connect video stream cb signal if it supports dual stream. */
827 if (info->record_dual_stream) {
828 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
829 goto _ERR_CAMCORDER_VIDEO_COMMAND;
832 /* start video stream */
833 if (info->record_dual_stream) {
834 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
836 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
838 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
839 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
841 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
843 MMCAM_LOG_ERROR("could not get camera control");
847 /* check pre-created encode pipeline */
848 g_mutex_lock(&hcamcorder->task_thread_lock);
849 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
850 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
851 /* create encoding pipeline */
852 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
853 if (ret != MM_ERROR_NONE) {
854 g_mutex_unlock(&hcamcorder->task_thread_lock);
855 goto _ERR_CAMCORDER_VIDEO_COMMAND;
858 g_mutex_unlock(&hcamcorder->task_thread_lock);
860 /* check recording start sound */
861 _mmcamcorder_sound_solo_play_wait(handle);
863 /**< To fix video recording hanging
864 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
865 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
866 basetime wouldn't change if you set (GstClockTime)0.
867 3. Move set start time position below PAUSED of pipeline.
870 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
871 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
874 info->video_frame_count = 0;
875 info->is_first_frame = TRUE;
876 info->audio_frame_count = 0;
878 sc->ferror_send = FALSE;
879 sc->ferror_count = 0;
880 hcamcorder->error_occurs = FALSE;
881 sc->bget_eos = FALSE;
882 sc->muxed_stream_offset = 0;
884 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
885 if (ret != MM_ERROR_NONE) {
886 /* stop video stream */
887 if (info->record_dual_stream) {
888 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
890 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
892 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
893 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
895 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
897 MMCAM_LOG_ERROR("failed to get camera control");
901 /* Remove recorder pipeline and recording file which size maybe zero */
902 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
903 if (info->filename) {
904 MMCAM_LOG_INFO("file delete(%s)", info->filename);
905 unlink(info->filename);
907 goto _ERR_CAMCORDER_VIDEO_COMMAND;
910 /*set the GOP so that video record will get a new key frame*/
911 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
912 if (mm_camcorder_get_attributes(handle, NULL,
913 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
914 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
916 MMCAM_LOG_ERROR("get gop interval failed");
920 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
921 if (mm_camcorder_get_attributes(handle, NULL,
922 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
923 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
925 MMCAM_LOG_ERROR("get gop interval failed");
928 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
930 MMCAM_LOG_INFO("Object property settings done");
934 case _MMCamcorder_CMD_PAUSE:
936 if (info->b_committing) {
937 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
938 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
941 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
942 if (sc->audio_disable) {
943 /* check only video frame */
944 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
946 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
947 MMCAM_LOG_ERROR("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
948 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
950 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
953 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
955 /* check both of video and audio frame */
956 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
958 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
959 MMCAM_LOG_ERROR("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
960 info->video_frame_count, info->audio_frame_count);
961 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
963 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
964 count, info->video_frame_count, info->audio_frame_count);
967 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
971 /* block encodebin */
972 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
975 case _MMCamcorder_CMD_CANCEL:
977 if (info->b_committing) {
978 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
979 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
982 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
984 if (hcamcorder->capture_in_recording == FALSE) {
986 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
987 MMCAM_LOG_ERROR("Failed to Wait capture data");
988 hcamcorder->capture_in_recording = FALSE;
991 MMCAM_LOG_WARNING("Waiting for capture data - retrial [%d]", count);
994 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
997 /* block push buffer */
998 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1000 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1001 if (ret != MM_ERROR_NONE)
1002 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1004 /* set recording hint */
1005 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1007 /* stop video stream */
1008 if (info->record_dual_stream) {
1009 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1010 if (CameraControl) {
1011 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1013 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1014 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1016 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1018 MMCAM_LOG_ERROR("failed to get camera control");
1022 if (info->restart_preview) {
1023 /* restart preview */
1024 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1025 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1026 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1028 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1030 /* check decoder recreation */
1031 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1032 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1033 ret = MM_ERROR_CAMCORDER_INTERNAL;
1036 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1037 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1038 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1040 if (ret != MM_ERROR_NONE)
1041 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1043 /* reset restart_preview for inset window layout */
1044 info->restart_preview = FALSE;
1046 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1047 ret = MM_ERROR_CAMCORDER_INTERNAL;
1048 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1051 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1052 if (ret != MM_ERROR_NONE)
1053 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1056 /* remove target file */
1057 if (info->filename) {
1058 MMCAM_LOG_INFO("file delete(%s)", info->filename);
1059 unlink(info->filename);
1062 sc->isMaxsizePausing = FALSE;
1063 sc->isMaxtimePausing = FALSE;
1065 sc->display_interval = 0;
1066 sc->previous_slot_time = 0;
1067 info->video_frame_count = 0;
1068 info->audio_frame_count = 0;
1070 hcamcorder->capture_in_recording = FALSE;
1073 case _MMCamcorder_CMD_COMMIT:
1077 if (info->b_committing) {
1078 MMCAM_LOG_ERROR("now on committing previous file!!(command : %d)", command);
1079 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1081 MMCAM_LOG_INFO("_MMCamcorder_CMD_COMMIT : start");
1082 info->b_committing = TRUE;
1083 sc->bget_eos = FALSE;
1086 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1087 if (sc->audio_disable) {
1088 /* check only video frame */
1089 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1090 hcamcorder->capture_in_recording == FALSE) {
1092 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1093 MMCAM_LOG_ERROR("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1094 info->video_frame_count, hcamcorder->capture_in_recording);
1096 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1097 MMCAM_LOG_WARNING("video frames are enough. keep going...");
1099 info->b_committing = FALSE;
1100 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1103 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1104 count, info->video_frame_count, hcamcorder->capture_in_recording);
1107 /* check both of video and audio frame */
1108 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1109 info->audio_frame_count &&
1110 hcamcorder->capture_in_recording == FALSE) {
1112 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1113 MMCAM_LOG_ERROR("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1114 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1116 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1117 MMCAM_LOG_WARNING("video/audio frames are enough. keep going...");
1119 info->b_committing = FALSE;
1120 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1123 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1125 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1126 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1130 if (hcamcorder->capture_in_recording) {
1131 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1132 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1133 MMCAM_LOG_WARNING("timeout");
1135 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1139 /* block push buffer */
1140 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1141 MMCAM_LOG_INFO("block push buffer to appsrc");
1143 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1144 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1145 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1146 ret = MM_ERROR_OUT_OF_STORAGE;
1147 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1150 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1151 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1152 MMCAM_LOG_WARNING("VIDEO: send eos to appsrc done");
1154 MMCAM_LOG_ERROR("VIDEO: send EOS failed");
1155 info->b_committing = FALSE;
1156 ret = MM_ERROR_CAMCORDER_INTERNAL;
1157 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1160 MMCAM_LOG_ERROR("No video stream source");
1161 info->b_committing = FALSE;
1162 ret = MM_ERROR_CAMCORDER_INTERNAL;
1163 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1166 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1167 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1168 MMCAM_LOG_WARNING("AUDIO: send eos to audiosrc done");
1170 MMCAM_LOG_ERROR("AUDIO: send EOS failed");
1171 info->b_committing = FALSE;
1172 ret = MM_ERROR_CAMCORDER_INTERNAL;
1173 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1176 MMCAM_LOG_INFO("No audio stream");
1180 sc->display_interval = 0;
1181 sc->previous_slot_time = 0;
1184 MMCAM_LOG_INFO("Start to wait EOS");
1185 ret = _mmcamcorder_get_eos_message(handle);
1186 if (ret != MM_ERROR_NONE) {
1187 info->b_committing = FALSE;
1188 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1192 hcamcorder->capture_in_recording = FALSE;
1196 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1197 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1200 return MM_ERROR_NONE;
1202 _ERR_CAMCORDER_VIDEO_COMMAND:
1203 if (command == _MMCamcorder_CMD_RECORD)
1204 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1210 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1212 int ret = MM_ERROR_NONE;
1214 guint64 file_size = 0;
1216 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1217 _MMCamcorderSubContext *sc = NULL;
1218 _MMCamcorderVideoInfo *info = NULL;
1219 _MMCamcorderMsgItem msg;
1220 MMCamRecordingReport *report = NULL;
1222 mmf_return_val_if_fail(hcamcorder, FALSE);
1224 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1225 mmf_return_val_if_fail(sc, FALSE);
1226 mmf_return_val_if_fail(sc->info_video, FALSE);
1228 info = sc->info_video;
1230 MMCAM_LOG_ERROR("");
1232 /* Play record stop sound */
1233 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1235 /* remove blocking part */
1236 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1238 mm_camcorder_get_attributes(handle, NULL,
1239 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1242 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1243 if (ret != MM_ERROR_NONE)
1244 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1246 /* set recording hint */
1247 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1249 /* stop video stream */
1250 if (info->record_dual_stream) {
1251 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1253 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1255 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1256 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1258 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1260 MMCAM_LOG_ERROR("failed to get camera control");
1264 if (enabletag && !(sc->ferror_send)) {
1265 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1266 MMCAM_LOG_INFO("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1269 /* Check file size */
1270 if (info->max_size > 0) {
1271 _mmcamcorder_get_file_size(info->filename, &file_size);
1272 MMCAM_LOG_INFO("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1273 info->max_size, file_size);
1275 if (file_size > info->max_size) {
1276 _MMCamcorderMsgItem message;
1277 MMCAM_LOG_ERROR("File size is greater than max size !!");
1278 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1279 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1280 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1284 if (info->restart_preview) {
1286 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1287 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1288 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1290 MMCAM_LOG_INFO("Set state of pipeline as READY");
1291 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1293 /* check decoder recreation */
1294 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1295 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1296 ret = MM_ERROR_CAMCORDER_INTERNAL;
1300 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1301 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1302 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1304 if (ret != MM_ERROR_NONE) {
1305 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1306 msg.param.code = ret;
1307 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1308 MMCAM_LOG_ERROR("Failed to set state READY[%x]", ret);
1311 /* reset restart_preview for inset window layout */
1312 info->restart_preview = FALSE;
1314 /* recover preview size */
1315 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1316 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1317 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1318 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1319 MMCAM_LOG_ERROR("Failed to set camera resolution %dx%d",
1320 info->preview_width, info->preview_height);
1323 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1324 /* Do not return when error is occurred.
1325 Recording file was created successfully, but starting pipeline failed */
1326 if (ret != MM_ERROR_NONE) {
1327 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1328 msg.param.code = ret;
1329 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1330 MMCAM_LOG_ERROR("Failed to set state PLAYING[%x]", ret);
1333 MMCAM_LOG_INFO("No need to restart preview");
1336 /* Send recording report to application */
1337 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1338 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1339 report->recording_filename = g_strdup(info->filename);
1340 msg.param.data = report;
1342 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1345 sc->pipeline_time = 0;
1347 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1348 sc->isMaxtimePausing = FALSE;
1349 hcamcorder->error_occurs = FALSE;
1351 info->video_frame_count = 0;
1352 info->audio_frame_count = 0;
1354 info->b_committing = FALSE;
1356 /* check recording stop sound */
1357 _mmcamcorder_sound_solo_play_wait(handle);
1359 MMCAM_LOG_ERROR("_MMCamcorder_CMD_COMMIT : end");
1365 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1367 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1368 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1370 _MMCamcorderSubContext *sc = NULL;
1371 _MMCamcorderVideoInfo *videoinfo = NULL;
1372 _MMCamcorderMsgItem msg;
1373 guint64 buffer_size = 0;
1374 guint64 trailer_size = 0;
1375 guint64 max_size = 0;
1377 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1378 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1379 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1381 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1382 videoinfo = sc->info_video;
1384 /* get buffer size */
1385 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1386 MMCAM_LOG_WARNING("map failed : buffer %p", buffer);
1387 return GST_PAD_PROBE_OK;
1390 buffer_size = mapinfo.size;
1391 gst_buffer_unmap(buffer, &mapinfo);
1393 g_mutex_lock(&videoinfo->size_check_lock);
1395 if (videoinfo->audio_frame_count == 0) {
1396 videoinfo->filesize += buffer_size;
1397 videoinfo->audio_frame_count++;
1398 g_mutex_unlock(&videoinfo->size_check_lock);
1399 return GST_PAD_PROBE_OK;
1402 if (sc->ferror_send || sc->isMaxsizePausing) {
1403 MMCAM_LOG_WARNING("Recording is paused, drop frames");
1404 g_mutex_unlock(&videoinfo->size_check_lock);
1405 return GST_PAD_PROBE_DROP;
1408 /* get trailer size */
1409 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1410 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1414 /* check max size of recorded file */
1415 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1416 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1417 GstState pipeline_state = GST_STATE_VOID_PENDING;
1418 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1420 MMCAM_LOG_WARNING("Max size[%"G_GUINT64_FORMAT"], current size[%"G_GUINT64_FORMAT"],"\
1421 " buffer size[%"G_GUINT64_FORMAT"], trailer size[%"G_GUINT64_FORMAT"]",
1422 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1424 if (!sc->isMaxsizePausing) {
1425 sc->isMaxsizePausing = TRUE;
1426 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1427 if (pipeline_state == GST_STATE_PLAYING)
1428 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1430 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1431 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1434 g_mutex_unlock(&videoinfo->size_check_lock);
1439 videoinfo->filesize += buffer_size;
1440 videoinfo->audio_frame_count++;
1442 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1443 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1445 g_mutex_unlock(&videoinfo->size_check_lock);
1447 return GST_PAD_PROBE_OK;
1451 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1456 guint64 free_space = 0;
1457 guint64 buffer_size = 0;
1458 guint64 trailer_size = 0;
1459 guint64 queued_buffer = 0;
1460 guint64 max_size = 0;
1461 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1463 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1465 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1466 _MMCamcorderMsgItem msg;
1467 _MMCamcorderSubContext *sc = NULL;
1468 _MMCamcorderVideoInfo *videoinfo = NULL;
1470 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1471 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1473 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1474 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1475 videoinfo = sc->info_video;
1477 if (sc->ferror_send) {
1478 MMCAM_LOG_WARNING("file write error, drop frames");
1479 return GST_PAD_PROBE_DROP;
1482 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1483 buffer_size = mapinfo.size;
1484 gst_buffer_unmap(buffer, &mapinfo);
1486 videoinfo->video_frame_count++;
1487 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1488 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1489 g_mutex_lock(&videoinfo->size_check_lock);
1490 videoinfo->filesize += buffer_size;
1491 g_mutex_unlock(&videoinfo->size_check_lock);
1492 return GST_PAD_PROBE_OK;
1495 /* get trailer size */
1496 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1497 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1501 /* check free space */
1502 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1504 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1505 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1506 sc->ferror_send = TRUE;
1508 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1509 msg.param.code = MM_ERROR_FILE_READ;
1511 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1516 return GST_PAD_PROBE_DROP; /* skip this buffer */
1519 if (free_space == 0) {
1520 /* check storage state */
1521 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1523 MMCAM_LOG_WARNING("storage state %d", storage_state);
1525 if (storage_state == STORAGE_STATE_REMOVED ||
1526 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1527 MMCAM_LOG_ERROR("storage was removed!");
1529 _MMCAMCORDER_LOCK(hcamcorder);
1531 if (sc->ferror_send == FALSE) {
1532 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1534 sc->ferror_send = TRUE;
1536 _MMCAMCORDER_UNLOCK(hcamcorder);
1538 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1539 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1541 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1543 _MMCAMCORDER_UNLOCK(hcamcorder);
1544 MMCAM_LOG_WARNING("error was already sent");
1547 return GST_PAD_PROBE_DROP;
1551 /* get queued buffer size */
1552 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1553 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1555 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1556 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1558 queued_buffer = aq_size + vq_size;
1560 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1561 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1562 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1563 free_space, trailer_size, buffer_size, queued_buffer);
1565 if (!sc->isMaxsizePausing) {
1566 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1567 sc->isMaxsizePausing = TRUE;
1569 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1570 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1573 return GST_PAD_PROBE_DROP;
1576 g_mutex_lock(&videoinfo->size_check_lock);
1578 /* check max size of recorded file */
1579 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1580 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1581 GstState pipeline_state = GST_STATE_VOID_PENDING;
1582 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1584 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1585 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1586 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1588 if (!sc->isMaxsizePausing) {
1589 sc->isMaxsizePausing = TRUE;
1590 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1591 if (pipeline_state == GST_STATE_PLAYING)
1592 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1594 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1595 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1598 g_mutex_unlock(&videoinfo->size_check_lock);
1600 return GST_PAD_PROBE_DROP;
1603 videoinfo->filesize += (guint64)buffer_size;
1605 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1606 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1608 g_mutex_unlock(&videoinfo->size_check_lock);
1610 return GST_PAD_PROBE_OK;
1614 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1616 guint64 trailer_size = 0;
1617 guint64 rec_pipe_time = 0;
1618 unsigned int remained_time = 0;
1620 GstClockTime b_time;
1622 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1623 _MMCamcorderMsgItem msg;
1624 _MMCamcorderSubContext *sc = NULL;
1625 _MMCamcorderVideoInfo *videoinfo = NULL;
1627 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1629 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1630 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1632 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1633 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1634 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1636 videoinfo = sc->info_video;
1638 b_time = GST_BUFFER_PTS(buffer);
1640 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1642 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1643 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1647 /* check max time */
1648 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1649 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1650 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1652 if (!sc->isMaxtimePausing) {
1653 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1655 sc->isMaxtimePausing = TRUE;
1657 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1658 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1659 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1660 msg.param.recording_status.remained_time = 0;
1661 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1663 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1664 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1667 return GST_PAD_PROBE_DROP;
1670 /* calculate remained time can be recorded */
1671 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1672 remained_time = videoinfo->max_time - rec_pipe_time;
1673 } else if (videoinfo->max_size > 0) {
1674 long double max_size = (long double)videoinfo->max_size;
1675 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1677 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1680 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1681 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1682 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1683 msg.param.recording_status.remained_time = remained_time;
1684 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1686 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1687 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1689 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1690 record_motion_rate, videoinfo->record_drop_count);
1692 /* drop some frame if fast motion */
1693 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1694 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1695 MMCAM_LOG_VERBOSE("drop frame");
1696 return GST_PAD_PROBE_DROP;
1699 videoinfo->record_drop_count = 1;
1700 MMCAM_LOG_VERBOSE("pass frame");
1703 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1704 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1707 return GST_PAD_PROBE_OK;
1711 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1713 _MMCamcorderMsgItem msg;
1714 guint64 trailer_size = 0;
1715 guint64 rec_pipe_time = 0;
1716 _MMCamcorderSubContext *sc = NULL;
1717 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1718 _MMCamcorderVideoInfo *videoinfo = NULL;
1719 unsigned int remained_time = 0;
1720 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1722 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1723 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1724 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1726 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1727 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1728 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1730 videoinfo = sc->info_video;
1732 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1733 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1734 return GST_PAD_PROBE_OK;
1737 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1739 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1740 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1744 /* calculate remained time can be recorded */
1745 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1746 remained_time = videoinfo->max_time - rec_pipe_time;
1747 } else if (videoinfo->max_size > 0) {
1748 long double max_size = (long double)videoinfo->max_size;
1749 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1751 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1754 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1755 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1756 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1758 if (!sc->isMaxtimePausing) {
1759 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1761 sc->isMaxtimePausing = TRUE;
1763 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1764 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1765 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1766 msg.param.recording_status.remained_time = 0;
1767 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1769 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1770 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1773 return GST_PAD_PROBE_DROP;
1776 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1777 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1778 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1779 msg.param.recording_status.remained_time = remained_time;
1780 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1782 MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1783 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1785 return GST_PAD_PROBE_OK;
1789 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1791 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1792 double volume = 0.0;
1795 int err = MM_ERROR_UNKNOWN;
1796 char *err_name = NULL;
1797 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1800 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1801 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1803 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1804 MMCAM_AUDIO_VOLUME, &volume,
1805 MMCAM_AUDIO_FORMAT, &format,
1806 MMCAM_AUDIO_CHANNEL, &channel,
1808 if (err != MM_ERROR_NONE) {
1809 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1810 SAFE_FREE(err_name);
1814 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1816 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1818 /* Set audio stream NULL */
1820 memset(mapinfo.data, 0, mapinfo.size);
1822 MMCAM_LOG_DEBUG("audio stream[%"GST_TIME_FORMAT"] - cb[%p], fmt[%d], ch[%d], size[%"G_GSIZE_FORMAT"]",
1823 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), hcamcorder->astream_cb, format, channel, mapinfo.size);
1825 /* CALL audio stream callback */
1826 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1827 MMCamcorderAudioStreamDataType stream;
1829 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1830 MMCAM_LOG_WARNING("Not ready for stream callback");
1831 gst_buffer_unmap(buffer, &mapinfo);
1832 return GST_PAD_PROBE_OK;
1835 stream.data = (void *)mapinfo.data;
1836 stream.format = format;
1837 stream.channel = channel;
1838 stream.length = mapinfo.size;
1839 stream.timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)));
1841 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1843 if (hcamcorder->astream_cb)
1844 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1846 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1849 gst_buffer_unmap(buffer, &mapinfo);
1851 return GST_PAD_PROBE_OK;
1855 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1857 gboolean bret = FALSE;
1859 switch (fileformat) {
1860 case MM_FILE_FORMAT_3GP:
1861 case MM_FILE_FORMAT_MP4:
1862 bret = __mmcamcorder_add_metadata_mp4(handle);
1865 MMCAM_LOG_WARNING("Unsupported fileformat to insert location info (%d)", fileformat);
1873 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1877 guint64 udta_size = 0;
1878 gint64 current_pos = 0;
1879 gint64 moov_pos = 0;
1880 gint64 udta_pos = 0;
1881 gdouble longitude = 0;
1882 gdouble latitude = 0;
1883 gdouble altitude = 0;
1885 int orientation = 0;
1887 char *err_name = NULL;
1888 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1889 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1890 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1892 _MMCamcorderVideoInfo *info = NULL;
1893 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1894 _MMCamcorderSubContext *sc = NULL;
1896 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1897 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1899 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1900 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1904 info = sc->info_video;
1906 f = fopen64(info->filename, "rb+");
1908 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1909 MMCAM_LOG_ERROR("file open failed [%s]", err_msg);
1913 mm_camcorder_get_attributes(handle, &err_name,
1914 MMCAM_TAG_LATITUDE, &latitude,
1915 MMCAM_TAG_LONGITUDE, &longitude,
1916 MMCAM_TAG_ALTITUDE, &altitude,
1917 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1918 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1921 MMCAM_LOG_WARNING("Get tag attrs fail. (%s:%x)", err_name, err);
1922 SAFE_FREE(err_name);
1925 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1926 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1927 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1928 geo_info.longitude = longitude *10000;
1929 geo_info.latitude = latitude *10000;
1930 geo_info.altitude = altitude *10000;
1931 /* find udta container.
1932 if, there are udta container, write loci box after that
1933 else, make udta container and write loci box. */
1934 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1937 MMCAM_LOG_INFO("find udta container");
1940 if (fseek(f, -8L, SEEK_CUR) != 0)
1943 udta_pos = ftello(f);
1947 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1949 MMCAM_LOG_INFO("recorded file fread %zu", nread);
1951 udta_size = _mmcamcorder_get_container_size(buf);
1953 /* goto end of udta and write 'loci' box */
1954 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1958 if (!_mmcamcorder_write_loci(f, location_info)) {
1959 MMCAM_LOG_ERROR("failed to write loci");
1963 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1964 MMCAM_LOG_ERROR("failed to write geodata");
1969 current_pos = ftello(f);
1970 if (current_pos < 0)
1973 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1976 MMCAM_LOG_INFO("No udta container");
1977 if (fseek(f, 0, SEEK_END) != 0)
1980 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1981 MMCAM_LOG_ERROR("failed to write udta");
1986 /* find moov container.
1987 update moov container size. */
1988 if ((current_pos = ftello(f)) < 0)
1991 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1992 gint64 internal_pos = ftello(f);
1994 MMCAM_LOG_INFO("found moov container");
1995 if (fseek(f, -8L, SEEK_CUR) != 0)
1998 moov_pos = ftello(f);
2002 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2005 /* add orientation info */
2006 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2007 MMCAM_LOG_ERROR("fseeko failed : errno %d", errno);
2011 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2012 MMCAM_LOG_ERROR("failed to find [trak] tag");
2016 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2017 MMCAM_LOG_ERROR("failed to find [tkhd] tag");
2021 MMCAM_LOG_INFO("found [tkhd] tag");
2023 /* seek to start position of composition matrix */
2024 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2025 /* update composition matrix for orientation */
2026 _mmcamcorder_update_composition_matrix(f, orientation);
2028 MMCAM_LOG_ERROR("fseek failed : errno %d", errno);
2032 MMCAM_LOG_ERROR("No 'moov' container");
2044 MMCAM_LOG_ERROR("ftell() returns negative value.");
2050 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2052 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2053 _MMCamcorderSubContext *sc = NULL;
2055 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2057 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2058 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2060 /* check video source element */
2061 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2062 MMCAM_LOG_WARNING("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2063 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2064 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2065 G_CALLBACK(__mmcamcorder_video_stream_cb),
2067 return MM_ERROR_NONE;
2069 MMCAM_LOG_ERROR("videosrc element is not created yet");
2070 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2075 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2077 int ret = MM_ERROR_NONE;
2079 char *temp_filename = NULL;
2081 _MMCamcorderVideoInfo *info = NULL;
2082 _MMCamcorderSubContext *sc = NULL;
2083 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2085 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2087 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2088 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2089 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2091 info = sc->info_video;
2093 MMCAM_LOG_WARNING("start");
2095 /* create encoding pipeline */
2096 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2097 if (ret != MM_ERROR_NONE)
2098 goto _ERR_PREPARE_RECORD;
2100 SAFE_G_FREE(info->filename);
2102 mm_camcorder_get_attributes(handle, NULL,
2103 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2105 if (temp_filename) {
2106 info->filename = g_strdup(temp_filename);
2107 if (!info->filename) {
2108 MMCAM_LOG_ERROR("strdup[src:%p] was failed", temp_filename);
2109 goto _ERR_PREPARE_RECORD;
2112 MMCAM_LOG_INFO("Record file name [%s]", info->filename);
2113 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2115 MMCAM_LOG_INFO("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2116 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2119 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2121 /* Adjust display FPS */
2122 sc->display_interval = 0;
2123 sc->previous_slot_time = 0;
2125 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2126 if (ret != MM_ERROR_NONE)
2127 goto _ERR_PREPARE_RECORD;
2129 MMCAM_LOG_WARNING("done");
2133 _ERR_PREPARE_RECORD:
2134 /* Remove recorder pipeline and recording file which size maybe zero */
2135 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2136 if (info && info->filename) {
2137 MMCAM_LOG_INFO("file delete(%s)", info->filename);
2138 unlink(info->filename);