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 /* set sync handler */
378 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
380 gst_object_unref(bus);
383 return MM_ERROR_NONE;
385 pipeline_creation_error:
386 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
387 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
389 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
394 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
396 GstPad *srcpad = NULL;
397 GstPad *sinkpad = NULL;
398 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
399 _MMCamcorderSubContext *sc = NULL;
401 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
403 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
404 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
405 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
409 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
410 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
411 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
412 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
414 /* release audiosrc bin */
415 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
416 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
419 To avoid conflicting between old elements and newly created elements,
420 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
421 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
422 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
423 It's because the pipeline of audio recording destroys at the same time,
424 and '_mmcamcorder_element_release_noti' will perfom removing handle.
426 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
428 MMCAM_LOG_INFO("Audio pipeline removed");
431 return MM_ERROR_NONE;
435 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
437 GstPad *reqpad = NULL;
438 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
439 _MMCamcorderSubContext *sc = NULL;
440 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
441 int ret = MM_ERROR_NONE;
442 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
444 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
446 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
447 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
448 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
452 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
453 /* release request pad */
454 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
456 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
457 gst_object_unref(reqpad);
461 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
463 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
464 gst_object_unref(reqpad);
468 /* release encode main pipeline */
469 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
472 To avoid conflicting between old elements and newly created elements,
473 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
474 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
475 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
476 It's because the pipeline of audio recording destroys at the same time,
477 and '_mmcamcorder_element_release_noti' will perfom removing handle.
479 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
480 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
482 MMCAM_LOG_WARNING("Encoder pipeline removed");
484 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
485 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
487 MMCAM_LOG_WARNING("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
489 if (hcamcorder->is_release_cb_calling == FALSE) {
490 /* release resource */
491 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
492 hcamcorder->video_encoder_resource);
493 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
494 hcamcorder->video_encoder_resource = NULL;
496 MMCAM_LOG_WARNING("mark resource for release 0x%x", ret);
498 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
500 MMCAM_LOG_WARNING("commit resource release 0x%x", ret);
503 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
505 MMCAM_LOG_WARNING("unlock resource");
506 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
509 return MM_ERROR_NONE;
513 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
515 int ret = MM_ERROR_NONE;
516 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
517 _MMCamcorderSubContext *sc = NULL;
521 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
522 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
523 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
525 MMCAM_LOG_INFO("start");
527 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
528 MMCAM_LOG_WARNING("pipeline is not existed.");
529 return MM_ERROR_NONE;
532 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
534 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
535 if (ret != MM_ERROR_NONE) {
536 MMCAM_LOG_ERROR("Failed to change encode main pipeline [0x%x]", ret);
540 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
542 /* remove audio pipeline first */
543 ret = _mmcamcorder_remove_audio_pipeline(handle);
544 if (ret != MM_ERROR_NONE) {
545 MMCAM_LOG_ERROR("Fail to remove audio pipeline");
549 ret = _mmcamcorder_remove_encode_pipeline(handle);
550 if (ret != MM_ERROR_NONE) {
551 MMCAM_LOG_ERROR("Fail to remove encoder pipeline");
555 /* Remove remained message */
557 GstMessage *gst_msg = NULL;
558 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
559 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
560 gst_message_unref(gst_msg);
563 gst_object_unref(bus);
567 MMCAM_LOG_INFO("done");
573 int _mmcamcorder_video_command(MMHandleType handle, int command)
578 int gop_interval = 0;
579 int ret = MM_ERROR_NONE;
580 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
581 char *err_name = NULL;
582 char *target_filename = NULL;
583 GstCameraControl *CameraControl = NULL;
586 GstElement *pipeline = NULL;
588 _MMCamcorderVideoInfo *info = NULL;
589 _MMCamcorderSubContext *sc = NULL;
590 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
592 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
594 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
595 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
596 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
597 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
599 info = sc->info_video;
601 MMCAM_LOG_INFO("Command(%d)", command);
603 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
606 case _MMCamcorder_CMD_RECORD:
608 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
612 gboolean storage_validity = FALSE;
615 int root_directory_length = 0;
618 MMCAM_LOG_INFO("Record Start - dual stream %d", info->support_dual_stream);
620 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
621 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
623 /* prepare resource manager for H/W encoder */
624 if (hcamcorder->video_encoder_resource == NULL) {
625 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
626 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
627 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
628 &hcamcorder->video_encoder_resource);
629 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
630 MMCAM_LOG_ERROR("could not prepare for encoder resource");
631 ret = MM_ERROR_RESOURCE_INTERNAL;
632 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
633 goto _ERR_CAMCORDER_VIDEO_COMMAND;
636 MMCAM_LOG_INFO("encoder already acquired");
639 /* acquire resources */
640 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
641 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
642 MMCAM_LOG_ERROR("could not acquire resources");
643 ret = MM_ERROR_RESOURCE_INTERNAL;
644 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
645 goto _ERR_CAMCORDER_VIDEO_COMMAND;
648 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
649 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
651 /* init record_dual_stream */
652 info->record_dual_stream = FALSE;
654 ret = mm_camcorder_get_attributes(handle, &err_name,
655 MMCAM_CAMERA_FPS, &fps,
656 MMCAM_CAMERA_WIDTH, &(info->preview_width),
657 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
658 MMCAM_VIDEO_WIDTH, &(info->video_width),
659 MMCAM_VIDEO_HEIGHT, &(info->video_height),
660 MMCAM_FILE_FORMAT, &fileformat,
661 MMCAM_TARGET_FILENAME, &target_filename, &size,
662 MMCAM_TARGET_MAX_SIZE, &imax_size,
663 MMCAM_TARGET_TIME_LIMIT, &imax_time,
664 MMCAM_FILE_FORMAT, &(info->fileformat),
665 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
666 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
668 if (ret != MM_ERROR_NONE) {
669 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, ret);
671 goto _ERR_CAMCORDER_VIDEO_COMMAND;
674 if (!target_filename && !hcamcorder->mstream_cb) {
675 MMCAM_LOG_ERROR("filename is not set and muxed stream cb is NULL");
676 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
677 goto _ERR_CAMCORDER_VIDEO_COMMAND;
682 info->max_size = 0; /* do not check */
684 info->max_size = ((guint64)imax_size) << 10; /* to byte */
688 info->max_time = 0; /* do not check */
690 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
692 ret = _mmcamcorder_get_storage_validity(hcamcorder, target_filename,
693 _MMCAMCORDER_VIDEO_MINIMUM_SPACE, &storage_validity);
694 if (ret != MM_ERROR_NONE) {
695 MMCAM_LOG_ERROR("storage validation failed[0x%x]:%d", ret, storage_validity);
699 _mmcamcorder_adjust_recording_max_size(target_filename, &info->max_size);
701 g_mutex_lock(&hcamcorder->task_thread_lock);
702 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
703 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
704 /* Play record start sound */
705 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
707 g_mutex_unlock(&hcamcorder->task_thread_lock);
709 MMCAM_LOG_WARNING("video size [%dx%d]", info->video_width, info->video_height);
711 if (info->video_width == 0 || info->video_height == 0) {
712 MMCAM_LOG_WARNING("video size is invalid [%dx%d] use preview size [%dx%d]",
713 info->video_width, info->video_height, info->preview_width, info->preview_height);
714 info->video_width = info->preview_width;
715 info->video_height = info->preview_height;
718 if (info->support_dual_stream) {
719 MMCAM_LOG_WARNING("DUAL STREAM MODE");
721 info->record_dual_stream = TRUE;
723 /* No need to restart preview */
724 info->restart_preview = FALSE;
726 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
727 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
728 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
729 info->preview_width == info->video_width &&
730 info->preview_height == info->video_height) {
731 MMCAM_LOG_INFO("H264 preview mode and same resolution");
733 /* No need to restart preview */
734 info->restart_preview = FALSE;
735 } else if (info->use_videoscale &&
736 info->preview_width >= info->video_width &&
737 info->preview_height >= info->video_height) {
738 info->restart_preview = FALSE;
740 info->restart_preview = TRUE;
741 /* reset use_videoscale */
742 info->use_videoscale = FALSE;
745 /* set recording hint */
746 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
748 if (info->restart_preview) {
749 /* stop preview and set new size */
750 MMCAM_LOG_INFO("restart preview");
752 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
753 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
754 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
756 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
758 /* check decoder recreation */
759 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
760 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
761 ret = MM_ERROR_CAMCORDER_INTERNAL;
762 goto _ERR_CAMCORDER_VIDEO_COMMAND;
765 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
766 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
767 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
769 if (ret != MM_ERROR_NONE)
770 goto _ERR_CAMCORDER_VIDEO_COMMAND;
772 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
773 ret = MM_ERROR_CAMCORDER_INTERNAL;
774 goto _ERR_CAMCORDER_VIDEO_COMMAND;
777 /* Start preview again with new setting */
778 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
779 if (ret != MM_ERROR_NONE)
780 goto _ERR_CAMCORDER_VIDEO_COMMAND;
782 if (motion_rate < 1.0) {
783 MMCAM_LOG_WARNING("wait for stabilization of frame");
787 MMCAM_LOG_INFO("no need to restart preview");
790 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
791 CONFIGURE_CATEGORY_MAIN_RECORD,
795 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
796 CONFIGURE_CATEGORY_MAIN_RECORD,
797 "PassFirstVideoFrame",
798 &(sc->pass_first_vframe));
800 MMCAM_LOG_INFO("Drop video frame count[%d], Pass fisrt video frame count[%d]",
801 sc->drop_vframe, sc->pass_first_vframe);
803 info->record_drop_count = (guint)motion_rate;
804 info->record_motion_rate = motion_rate;
805 if (sc->is_modified_rate)
806 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
808 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
810 MMCAM_LOG_WARNING("recording fps %d, motion rate %f, timestamp_ratio %f",
811 fps, info->record_motion_rate, info->record_timestamp_ratio);
813 /* set push buffer flag */
814 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
815 info->base_video_ts = 0;
817 /* connect video stream cb signal if it supports dual stream. */
818 if (info->record_dual_stream) {
819 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
820 goto _ERR_CAMCORDER_VIDEO_COMMAND;
823 /* start video stream */
824 if (info->record_dual_stream) {
825 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
827 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
829 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
830 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
832 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
834 MMCAM_LOG_ERROR("could not get camera control");
838 /* check pre-created encode pipeline */
839 g_mutex_lock(&hcamcorder->task_thread_lock);
840 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
841 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
842 /* create encoding pipeline */
843 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
844 if (ret != MM_ERROR_NONE) {
845 g_mutex_unlock(&hcamcorder->task_thread_lock);
846 goto _ERR_CAMCORDER_VIDEO_COMMAND;
849 g_mutex_unlock(&hcamcorder->task_thread_lock);
851 /* check recording start sound */
852 _mmcamcorder_sound_solo_play_wait(handle);
854 /**< To fix video recording hanging
855 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
856 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
857 basetime wouldn't change if you set (GstClockTime)0.
858 3. Move set start time position below PAUSED of pipeline.
861 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
862 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
865 info->video_frame_count = 0;
866 info->is_first_frame = TRUE;
867 info->audio_frame_count = 0;
869 sc->ferror_send = FALSE;
870 sc->ferror_count = 0;
871 hcamcorder->error_occurs = FALSE;
872 sc->bget_eos = FALSE;
873 sc->muxed_stream_offset = 0;
875 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
876 if (ret != MM_ERROR_NONE) {
877 /* stop video stream */
878 if (info->record_dual_stream) {
879 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
881 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
883 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
884 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
886 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
888 MMCAM_LOG_ERROR("failed to get camera control");
892 /* Remove recorder pipeline and recording file which size maybe zero */
893 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
894 if (info->filename) {
895 MMCAM_LOG_INFO("file delete(%s)", info->filename);
896 unlink(info->filename);
898 goto _ERR_CAMCORDER_VIDEO_COMMAND;
901 /*set the GOP so that video record will get a new key frame*/
902 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
903 if (mm_camcorder_get_attributes(handle, NULL,
904 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
905 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
907 MMCAM_LOG_ERROR("get gop interval failed");
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");
919 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
921 MMCAM_LOG_INFO("Object property settings done");
925 case _MMCamcorder_CMD_PAUSE:
927 if (info->b_committing) {
928 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
929 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
932 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
933 if (sc->audio_disable) {
934 /* check only video frame */
935 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
937 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
938 MMCAM_LOG_ERROR("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
939 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
941 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
944 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
946 /* check both of video and audio frame */
947 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
949 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
950 MMCAM_LOG_ERROR("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
951 info->video_frame_count, info->audio_frame_count);
952 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
954 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
955 count, info->video_frame_count, info->audio_frame_count);
958 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
962 /* block encodebin */
963 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
966 case _MMCamcorder_CMD_CANCEL:
968 if (info->b_committing) {
969 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
970 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
973 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
975 if (hcamcorder->capture_in_recording == FALSE) {
977 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
978 MMCAM_LOG_ERROR("Failed to Wait capture data");
979 hcamcorder->capture_in_recording = FALSE;
982 MMCAM_LOG_WARNING("Waiting for capture data - retrial [%d]", count);
985 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
988 /* block push buffer */
989 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
991 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
992 if (ret != MM_ERROR_NONE)
993 goto _ERR_CAMCORDER_VIDEO_COMMAND;
995 /* set recording hint */
996 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
998 /* stop video stream */
999 if (info->record_dual_stream) {
1000 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1001 if (CameraControl) {
1002 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1004 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1005 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1007 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1009 MMCAM_LOG_ERROR("failed to get camera control");
1013 if (info->restart_preview) {
1014 /* restart preview */
1015 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1016 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1017 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1019 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1021 /* check decoder recreation */
1022 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1023 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1024 ret = MM_ERROR_CAMCORDER_INTERNAL;
1027 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1028 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1029 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1031 if (ret != MM_ERROR_NONE)
1032 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1034 /* reset restart_preview for inset window layout */
1035 info->restart_preview = FALSE;
1037 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1038 ret = MM_ERROR_CAMCORDER_INTERNAL;
1039 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1042 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1043 if (ret != MM_ERROR_NONE)
1044 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1047 /* remove target file */
1048 if (info->filename) {
1049 MMCAM_LOG_INFO("file delete(%s)", info->filename);
1050 unlink(info->filename);
1053 sc->isMaxsizePausing = FALSE;
1054 sc->isMaxtimePausing = FALSE;
1056 sc->display_interval = 0;
1057 sc->previous_slot_time = 0;
1058 info->video_frame_count = 0;
1059 info->audio_frame_count = 0;
1061 hcamcorder->capture_in_recording = FALSE;
1064 case _MMCamcorder_CMD_COMMIT:
1068 if (info->b_committing) {
1069 MMCAM_LOG_ERROR("now on committing previous file!!(command : %d)", command);
1070 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1072 MMCAM_LOG_INFO("_MMCamcorder_CMD_COMMIT : start");
1073 info->b_committing = TRUE;
1074 sc->bget_eos = FALSE;
1077 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1078 if (sc->audio_disable) {
1079 /* check only video frame */
1080 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1081 hcamcorder->capture_in_recording == FALSE) {
1083 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1084 MMCAM_LOG_ERROR("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1085 info->video_frame_count, hcamcorder->capture_in_recording);
1087 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1088 MMCAM_LOG_WARNING("video frames are enough. keep going...");
1090 info->b_committing = FALSE;
1091 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1094 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1095 count, info->video_frame_count, hcamcorder->capture_in_recording);
1098 /* check both of video and audio frame */
1099 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1100 info->audio_frame_count &&
1101 hcamcorder->capture_in_recording == FALSE) {
1103 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1104 MMCAM_LOG_ERROR("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1105 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1107 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1108 MMCAM_LOG_WARNING("video/audio frames are enough. keep going...");
1110 info->b_committing = FALSE;
1111 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1114 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1116 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1117 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1121 if (hcamcorder->capture_in_recording) {
1122 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1123 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1124 MMCAM_LOG_WARNING("timeout");
1126 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1130 /* block push buffer */
1131 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1132 MMCAM_LOG_INFO("block push buffer to appsrc");
1134 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1135 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1136 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1137 ret = MM_ERROR_OUT_OF_STORAGE;
1138 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1141 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1142 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1143 MMCAM_LOG_WARNING("VIDEO: send eos to appsrc done");
1145 MMCAM_LOG_ERROR("VIDEO: send EOS failed");
1146 info->b_committing = FALSE;
1147 ret = MM_ERROR_CAMCORDER_INTERNAL;
1148 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1151 MMCAM_LOG_ERROR("No video stream source");
1152 info->b_committing = FALSE;
1153 ret = MM_ERROR_CAMCORDER_INTERNAL;
1154 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1157 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1158 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1159 MMCAM_LOG_WARNING("AUDIO: send eos to audiosrc done");
1161 MMCAM_LOG_ERROR("AUDIO: send EOS failed");
1162 info->b_committing = FALSE;
1163 ret = MM_ERROR_CAMCORDER_INTERNAL;
1164 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1167 MMCAM_LOG_INFO("No audio stream");
1171 sc->display_interval = 0;
1172 sc->previous_slot_time = 0;
1175 MMCAM_LOG_INFO("Start to wait EOS");
1176 ret = _mmcamcorder_get_eos_message(handle);
1177 if (ret != MM_ERROR_NONE) {
1178 info->b_committing = FALSE;
1179 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1183 hcamcorder->capture_in_recording = FALSE;
1187 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1188 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1191 return MM_ERROR_NONE;
1193 _ERR_CAMCORDER_VIDEO_COMMAND:
1194 if (command == _MMCamcorder_CMD_RECORD)
1195 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1201 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1203 int ret = MM_ERROR_NONE;
1205 guint64 file_size = 0;
1207 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1208 _MMCamcorderSubContext *sc = NULL;
1209 _MMCamcorderVideoInfo *info = NULL;
1210 _MMCamcorderMsgItem msg;
1211 MMCamRecordingReport *report = NULL;
1213 mmf_return_val_if_fail(hcamcorder, FALSE);
1215 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1216 mmf_return_val_if_fail(sc, FALSE);
1217 mmf_return_val_if_fail(sc->info_video, FALSE);
1219 info = sc->info_video;
1221 MMCAM_LOG_ERROR("");
1223 /* Play record stop sound */
1224 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1226 /* remove blocking part */
1227 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1229 mm_camcorder_get_attributes(handle, NULL,
1230 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1233 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1234 if (ret != MM_ERROR_NONE)
1235 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1237 /* set recording hint */
1238 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1240 /* stop video stream */
1241 if (info->record_dual_stream) {
1242 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1244 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1246 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1247 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1249 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1251 MMCAM_LOG_ERROR("failed to get camera control");
1255 if (enabletag && !(sc->ferror_send)) {
1256 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1257 MMCAM_LOG_INFO("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1260 /* Check file size */
1261 if (info->max_size > 0) {
1262 _mmcamcorder_get_file_size(info->filename, &file_size);
1263 MMCAM_LOG_INFO("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1264 info->max_size, file_size);
1266 if (file_size > info->max_size) {
1267 _MMCamcorderMsgItem message;
1268 MMCAM_LOG_ERROR("File size is greater than max size !!");
1269 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1270 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1271 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1275 if (info->restart_preview) {
1277 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1278 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1279 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1281 MMCAM_LOG_INFO("Set state of pipeline as READY");
1282 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1284 /* check decoder recreation */
1285 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1286 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1287 ret = MM_ERROR_CAMCORDER_INTERNAL;
1291 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1292 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1293 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1295 if (ret != MM_ERROR_NONE) {
1296 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1297 msg.param.code = ret;
1298 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1299 MMCAM_LOG_ERROR("Failed to set state READY[%x]", ret);
1302 /* reset restart_preview for inset window layout */
1303 info->restart_preview = FALSE;
1305 /* recover preview size */
1306 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1307 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1308 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1309 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1310 MMCAM_LOG_ERROR("Failed to set camera resolution %dx%d",
1311 info->preview_width, info->preview_height);
1314 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1315 /* Do not return when error is occurred.
1316 Recording file was created successfully, but starting pipeline failed */
1317 if (ret != MM_ERROR_NONE) {
1318 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1319 msg.param.code = ret;
1320 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1321 MMCAM_LOG_ERROR("Failed to set state PLAYING[%x]", ret);
1324 MMCAM_LOG_INFO("No need to restart preview");
1327 /* Send recording report to application */
1328 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1329 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1330 report->recording_filename = g_strdup(info->filename);
1331 msg.param.data = report;
1333 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1336 sc->pipeline_time = 0;
1338 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1339 sc->isMaxtimePausing = FALSE;
1340 hcamcorder->error_occurs = FALSE;
1342 info->video_frame_count = 0;
1343 info->audio_frame_count = 0;
1345 info->b_committing = FALSE;
1347 /* check recording stop sound */
1348 _mmcamcorder_sound_solo_play_wait(handle);
1350 MMCAM_LOG_ERROR("_MMCamcorder_CMD_COMMIT : end");
1356 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1358 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1359 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1361 _MMCamcorderSubContext *sc = NULL;
1362 _MMCamcorderVideoInfo *videoinfo = NULL;
1363 _MMCamcorderMsgItem msg;
1364 guint64 buffer_size = 0;
1365 guint64 trailer_size = 0;
1366 guint64 max_size = 0;
1368 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1369 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1370 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1372 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1373 videoinfo = sc->info_video;
1375 /* get buffer size */
1376 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1377 MMCAM_LOG_WARNING("map failed : buffer %p", buffer);
1378 return GST_PAD_PROBE_OK;
1381 buffer_size = mapinfo.size;
1382 gst_buffer_unmap(buffer, &mapinfo);
1384 g_mutex_lock(&videoinfo->size_check_lock);
1386 if (videoinfo->audio_frame_count == 0) {
1387 videoinfo->filesize += buffer_size;
1388 videoinfo->audio_frame_count++;
1389 g_mutex_unlock(&videoinfo->size_check_lock);
1390 return GST_PAD_PROBE_OK;
1393 if (sc->ferror_send || sc->isMaxsizePausing) {
1394 MMCAM_LOG_WARNING("Recording is paused, drop frames");
1395 g_mutex_unlock(&videoinfo->size_check_lock);
1396 return GST_PAD_PROBE_DROP;
1399 /* get trailer size */
1400 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1401 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1405 /* check max size of recorded file */
1406 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1407 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1408 GstState pipeline_state = GST_STATE_VOID_PENDING;
1409 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1411 MMCAM_LOG_WARNING("Max size[%"G_GUINT64_FORMAT"], current size[%"G_GUINT64_FORMAT"],"\
1412 " buffer size[%"G_GUINT64_FORMAT"], trailer size[%"G_GUINT64_FORMAT"]",
1413 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1415 if (!sc->isMaxsizePausing) {
1416 sc->isMaxsizePausing = TRUE;
1417 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1418 if (pipeline_state == GST_STATE_PLAYING)
1419 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1421 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1422 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1425 g_mutex_unlock(&videoinfo->size_check_lock);
1430 videoinfo->filesize += buffer_size;
1431 videoinfo->audio_frame_count++;
1433 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1434 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1436 g_mutex_unlock(&videoinfo->size_check_lock);
1438 return GST_PAD_PROBE_OK;
1442 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1447 guint64 free_space = 0;
1448 guint64 buffer_size = 0;
1449 guint64 trailer_size = 0;
1450 guint64 queued_buffer = 0;
1451 guint64 max_size = 0;
1452 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1454 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1456 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1457 _MMCamcorderMsgItem msg;
1458 _MMCamcorderSubContext *sc = NULL;
1459 _MMCamcorderVideoInfo *videoinfo = NULL;
1461 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1462 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1464 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1465 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1466 videoinfo = sc->info_video;
1468 if (sc->ferror_send) {
1469 MMCAM_LOG_WARNING("file write error, drop frames");
1470 return GST_PAD_PROBE_DROP;
1473 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1474 buffer_size = mapinfo.size;
1475 gst_buffer_unmap(buffer, &mapinfo);
1477 videoinfo->video_frame_count++;
1478 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1479 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1480 g_mutex_lock(&videoinfo->size_check_lock);
1481 videoinfo->filesize += buffer_size;
1482 g_mutex_unlock(&videoinfo->size_check_lock);
1483 return GST_PAD_PROBE_OK;
1486 /* get trailer size */
1487 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1488 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1492 /* check free space */
1493 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1495 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1496 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1497 sc->ferror_send = TRUE;
1499 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1500 msg.param.code = MM_ERROR_FILE_READ;
1502 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1507 return GST_PAD_PROBE_DROP; /* skip this buffer */
1510 if (free_space == 0) {
1511 /* check storage state */
1512 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1514 MMCAM_LOG_WARNING("storage state %d", storage_state);
1516 if (storage_state == STORAGE_STATE_REMOVED ||
1517 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1518 MMCAM_LOG_ERROR("storage was removed!");
1520 _MMCAMCORDER_LOCK(hcamcorder);
1522 if (sc->ferror_send == FALSE) {
1523 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1525 sc->ferror_send = TRUE;
1527 _MMCAMCORDER_UNLOCK(hcamcorder);
1529 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1530 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1532 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1534 _MMCAMCORDER_UNLOCK(hcamcorder);
1535 MMCAM_LOG_WARNING("error was already sent");
1538 return GST_PAD_PROBE_DROP;
1542 /* get queued buffer size */
1543 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1544 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1546 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1547 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1549 queued_buffer = aq_size + vq_size;
1551 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1552 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1553 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1554 free_space, trailer_size, buffer_size, queued_buffer);
1556 if (!sc->isMaxsizePausing) {
1557 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1558 sc->isMaxsizePausing = TRUE;
1560 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1561 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1564 return GST_PAD_PROBE_DROP;
1567 g_mutex_lock(&videoinfo->size_check_lock);
1569 /* check max size of recorded file */
1570 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1571 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1572 GstState pipeline_state = GST_STATE_VOID_PENDING;
1573 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1575 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1576 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1577 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1579 if (!sc->isMaxsizePausing) {
1580 sc->isMaxsizePausing = TRUE;
1581 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1582 if (pipeline_state == GST_STATE_PLAYING)
1583 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1585 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1586 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1589 g_mutex_unlock(&videoinfo->size_check_lock);
1591 return GST_PAD_PROBE_DROP;
1594 videoinfo->filesize += (guint64)buffer_size;
1596 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1597 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1599 g_mutex_unlock(&videoinfo->size_check_lock);
1601 return GST_PAD_PROBE_OK;
1605 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1607 guint64 trailer_size = 0;
1608 guint64 rec_pipe_time = 0;
1609 unsigned int remained_time = 0;
1611 GstClockTime b_time;
1613 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1614 _MMCamcorderMsgItem msg;
1615 _MMCamcorderSubContext *sc = NULL;
1616 _MMCamcorderVideoInfo *videoinfo = NULL;
1618 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1620 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1621 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1623 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1624 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1625 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1627 videoinfo = sc->info_video;
1629 b_time = GST_BUFFER_PTS(buffer);
1631 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1633 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1634 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1638 /* check max time */
1639 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1640 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1641 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1643 if (!sc->isMaxtimePausing) {
1644 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1646 sc->isMaxtimePausing = TRUE;
1648 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1649 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1650 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1651 msg.param.recording_status.remained_time = 0;
1652 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1654 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1655 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1658 return GST_PAD_PROBE_DROP;
1661 /* calculate remained time can be recorded */
1662 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1663 remained_time = videoinfo->max_time - rec_pipe_time;
1664 } else if (videoinfo->max_size > 0) {
1665 long double max_size = (long double)videoinfo->max_size;
1666 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1668 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1671 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1672 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1673 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1674 msg.param.recording_status.remained_time = remained_time;
1675 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1677 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1678 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1680 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1681 record_motion_rate, videoinfo->record_drop_count);
1683 /* drop some frame if fast motion */
1684 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1685 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1686 MMCAM_LOG_VERBOSE("drop frame");
1687 return GST_PAD_PROBE_DROP;
1690 videoinfo->record_drop_count = 1;
1691 MMCAM_LOG_VERBOSE("pass frame");
1694 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1695 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1698 return GST_PAD_PROBE_OK;
1702 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1704 _MMCamcorderMsgItem msg;
1705 guint64 trailer_size = 0;
1706 guint64 rec_pipe_time = 0;
1707 _MMCamcorderSubContext *sc = NULL;
1708 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1709 _MMCamcorderVideoInfo *videoinfo = NULL;
1710 unsigned int remained_time = 0;
1711 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1713 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1714 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1715 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1717 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1718 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1719 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1721 videoinfo = sc->info_video;
1723 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1724 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1725 return GST_PAD_PROBE_OK;
1728 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1730 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1731 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1735 /* calculate remained time can be recorded */
1736 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1737 remained_time = videoinfo->max_time - rec_pipe_time;
1738 } else if (videoinfo->max_size > 0) {
1739 long double max_size = (long double)videoinfo->max_size;
1740 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1742 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1745 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1746 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1747 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1749 if (!sc->isMaxtimePausing) {
1750 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1752 sc->isMaxtimePausing = TRUE;
1754 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1755 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1756 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1757 msg.param.recording_status.remained_time = 0;
1758 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1760 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1761 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1764 return GST_PAD_PROBE_DROP;
1767 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1768 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1769 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1770 msg.param.recording_status.remained_time = remained_time;
1771 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1773 MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1774 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1776 return GST_PAD_PROBE_OK;
1780 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1782 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1783 double volume = 0.0;
1786 int err = MM_ERROR_UNKNOWN;
1787 char *err_name = NULL;
1788 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1791 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1792 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1794 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1795 MMCAM_AUDIO_VOLUME, &volume,
1796 MMCAM_AUDIO_FORMAT, &format,
1797 MMCAM_AUDIO_CHANNEL, &channel,
1799 if (err != MM_ERROR_NONE) {
1800 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1801 SAFE_FREE(err_name);
1805 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1807 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1809 /* Set audio stream NULL */
1811 memset(mapinfo.data, 0, mapinfo.size);
1813 MMCAM_LOG_DEBUG("audio stream[%"GST_TIME_FORMAT"] - cb[%p], fmt[%d], ch[%d], size[%"G_GSIZE_FORMAT"]",
1814 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), hcamcorder->astream_cb, format, channel, mapinfo.size);
1816 /* CALL audio stream callback */
1817 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1818 MMCamcorderAudioStreamDataType stream;
1820 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1821 MMCAM_LOG_WARNING("Not ready for stream callback");
1822 gst_buffer_unmap(buffer, &mapinfo);
1823 return GST_PAD_PROBE_OK;
1826 stream.data = (void *)mapinfo.data;
1827 stream.format = format;
1828 stream.channel = channel;
1829 stream.length = mapinfo.size;
1830 stream.timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)));
1832 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1834 if (hcamcorder->astream_cb)
1835 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1837 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1840 gst_buffer_unmap(buffer, &mapinfo);
1842 return GST_PAD_PROBE_OK;
1846 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1848 gboolean bret = FALSE;
1850 switch (fileformat) {
1851 case MM_FILE_FORMAT_3GP:
1852 case MM_FILE_FORMAT_MP4:
1853 bret = __mmcamcorder_add_metadata_mp4(handle);
1856 MMCAM_LOG_WARNING("Unsupported fileformat to insert location info (%d)", fileformat);
1864 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1868 guint64 udta_size = 0;
1869 gint64 current_pos = 0;
1870 gint64 moov_pos = 0;
1871 gint64 udta_pos = 0;
1872 gdouble longitude = 0;
1873 gdouble latitude = 0;
1874 gdouble altitude = 0;
1876 int orientation = 0;
1878 char *err_name = NULL;
1879 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1880 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1881 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1883 _MMCamcorderVideoInfo *info = NULL;
1884 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1885 _MMCamcorderSubContext *sc = NULL;
1887 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1888 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1890 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1891 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1895 info = sc->info_video;
1897 f = fopen64(info->filename, "rb+");
1899 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1900 MMCAM_LOG_ERROR("file open failed [%s]", err_msg);
1904 mm_camcorder_get_attributes(handle, &err_name,
1905 MMCAM_TAG_LATITUDE, &latitude,
1906 MMCAM_TAG_LONGITUDE, &longitude,
1907 MMCAM_TAG_ALTITUDE, &altitude,
1908 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1909 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1912 MMCAM_LOG_WARNING("Get tag attrs fail. (%s:%x)", err_name, err);
1913 SAFE_FREE(err_name);
1916 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1917 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1918 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1919 geo_info.longitude = longitude *10000;
1920 geo_info.latitude = latitude *10000;
1921 geo_info.altitude = altitude *10000;
1922 /* find udta container.
1923 if, there are udta container, write loci box after that
1924 else, make udta container and write loci box. */
1925 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1928 MMCAM_LOG_INFO("find udta container");
1931 if (fseek(f, -8L, SEEK_CUR) != 0)
1934 udta_pos = ftello(f);
1938 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1940 MMCAM_LOG_INFO("recorded file fread %zu", nread);
1942 udta_size = _mmcamcorder_get_container_size(buf);
1944 /* goto end of udta and write 'loci' box */
1945 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1949 if (!_mmcamcorder_write_loci(f, location_info)) {
1950 MMCAM_LOG_ERROR("failed to write loci");
1954 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1955 MMCAM_LOG_ERROR("failed to write geodata");
1960 current_pos = ftello(f);
1961 if (current_pos < 0)
1964 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1967 MMCAM_LOG_INFO("No udta container");
1968 if (fseek(f, 0, SEEK_END) != 0)
1971 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1972 MMCAM_LOG_ERROR("failed to write udta");
1977 /* find moov container.
1978 update moov container size. */
1979 if ((current_pos = ftello(f)) < 0)
1982 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1983 gint64 internal_pos = ftello(f);
1985 MMCAM_LOG_INFO("found moov container");
1986 if (fseek(f, -8L, SEEK_CUR) != 0)
1989 moov_pos = ftello(f);
1993 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
1996 /* add orientation info */
1997 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1998 MMCAM_LOG_ERROR("fseeko failed : errno %d", errno);
2002 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2003 MMCAM_LOG_ERROR("failed to find [trak] tag");
2007 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2008 MMCAM_LOG_ERROR("failed to find [tkhd] tag");
2012 MMCAM_LOG_INFO("found [tkhd] tag");
2014 /* seek to start position of composition matrix */
2015 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2016 /* update composition matrix for orientation */
2017 _mmcamcorder_update_composition_matrix(f, orientation);
2019 MMCAM_LOG_ERROR("fseek failed : errno %d", errno);
2023 MMCAM_LOG_ERROR("No 'moov' container");
2035 MMCAM_LOG_ERROR("ftell() returns negative value.");
2041 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2043 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2044 _MMCamcorderSubContext *sc = NULL;
2046 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2048 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2049 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2051 /* check video source element */
2052 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2053 MMCAM_LOG_WARNING("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2054 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2055 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2056 G_CALLBACK(__mmcamcorder_video_stream_cb),
2058 return MM_ERROR_NONE;
2060 MMCAM_LOG_ERROR("videosrc element is not created yet");
2061 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2066 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2068 int ret = MM_ERROR_NONE;
2070 char *temp_filename = NULL;
2072 _MMCamcorderVideoInfo *info = NULL;
2073 _MMCamcorderSubContext *sc = NULL;
2074 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2076 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2078 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2079 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2080 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2082 info = sc->info_video;
2084 MMCAM_LOG_WARNING("start");
2086 /* create encoding pipeline */
2087 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2088 if (ret != MM_ERROR_NONE)
2089 goto _ERR_PREPARE_RECORD;
2091 SAFE_G_FREE(info->filename);
2093 mm_camcorder_get_attributes(handle, NULL,
2094 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2096 if (temp_filename) {
2097 info->filename = g_strdup(temp_filename);
2098 if (!info->filename) {
2099 MMCAM_LOG_ERROR("strdup[src:%p] was failed", temp_filename);
2100 goto _ERR_PREPARE_RECORD;
2103 MMCAM_LOG_INFO("Record file name [%s]", info->filename);
2104 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2106 MMCAM_LOG_INFO("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2107 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2110 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2112 /* Adjust display FPS */
2113 sc->display_interval = 0;
2114 sc->previous_slot_time = 0;
2116 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2117 if (ret != MM_ERROR_NONE)
2118 goto _ERR_PREPARE_RECORD;
2120 MMCAM_LOG_WARNING("done");
2124 _ERR_PREPARE_RECORD:
2125 /* Remove recorder pipeline and recording file which size maybe zero */
2126 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2127 if (info && info->filename) {
2128 MMCAM_LOG_INFO("file delete(%s)", info->filename);
2129 unlink(info->filename);