4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jeongmo Yang <jm80.yang@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 /*=======================================================================================
24 =======================================================================================*/
25 #include <gst/allocators/gsttizenmemory.h>
26 #include <gst/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
30 /*---------------------------------------------------------------------------------------
31 | LOCAL VARIABLE DEFINITIONS for internal |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_MINIMUM_FRAME 5
34 #define _MMCAMCORDER_RETRIAL_COUNT 15
35 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* us */
36 #define _MMCAMCORDER_FRAME_PASS_MIN_FPS 30
37 #define _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME 30000000 /* ns */
38 #define _MMCAMCORDER_VIDEO_MINIMUM_SPACE (_MMCAMCORDER_MINIMUM_SPACE << 1) /* byte */
39 #define OFFSET_COMPOSITION_MATRIX 40L
40 #define MAX_ERROR_MESSAGE_LEN 128
42 /*---------------------------------------------------------------------------------------
43 | LOCAL FUNCTION PROTOTYPES: |
44 ---------------------------------------------------------------------------------------*/
45 /* STATIC INTERNAL FUNCTION */
46 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
47 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
48 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
49 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
50 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
53 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
55 /*=======================================================================================
56 | FUNCTION DEFINITIONS |
57 =======================================================================================*/
58 /*---------------------------------------------------------------------------------------
59 | GLOBAL FUNCTION DEFINITIONS: |
60 ---------------------------------------------------------------------------------------*/
61 gboolean _mmcamcorder_video_push_buffer(void *handle, GstSample *sample)
63 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
64 _MMCamcorderSubContext *sc = NULL;
65 _MMCamcorderImageInfo *info_image = NULL;
66 _MMCamcorderVideoInfo *info_video = NULL;
67 _MMCamcorderGstElement *element = NULL;
68 GstClockTime current_ts = 0; /* nsec */
69 GstBuffer *buffer = NULL;
71 mmf_return_val_if_fail(hcamcorder, FALSE);
72 mmf_return_val_if_fail(MMF_CAMCORDER_SUBCONTEXT(hcamcorder), FALSE);
74 buffer = gst_sample_get_buffer(sample);
76 mmf_return_val_if_fail(buffer, FALSE);
77 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
79 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
81 mmf_return_val_if_fail(sc->info_image, FALSE);
82 mmf_return_val_if_fail(sc->info_video, FALSE);
83 mmf_return_val_if_fail(sc->encode_element, FALSE);
85 info_image = sc->info_image;
86 info_video = sc->info_video;
87 element = sc->encode_element;
89 if (info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
90 element[_MMCAMCORDER_ENCSINK_SRC].gst) {
92 GstClock *clock = NULL;
94 MMCAM_LOG_VERBOSE("buffer[%p] - delta flag[%d]",
95 buffer, GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT));
97 current_ts = GST_BUFFER_PTS(buffer);
99 if (info_video->is_first_frame) {
100 /* check first I frame for H.264 stream */
101 if (_mmcamcorder_is_encoded_preview_pixel_format(info_image->preview_format)) {
102 if (!GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_HEADER)) {
103 MMCAM_LOG_WARNING("No header in buffer");
107 MMCAM_LOG_WARNING("Got buffer with header");
110 /* set base timestamp */
111 if (element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
112 clock = GST_ELEMENT_CLOCK(element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
114 gst_object_ref(clock);
115 info_video->base_video_ts = current_ts - (gst_clock_get_time(clock) - \
116 GST_ELEMENT(element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
117 gst_object_unref(clock);
120 /* for image capture with encodebin and v4l2src */
121 if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_ENCODEBIN && info_image->capturing) {
122 g_mutex_lock(&hcamcorder->task_thread_lock);
123 MMCAM_LOG_INFO("send signal for sound play");
124 hcamcorder->task_thread_state = _MMCAMCORDER_TASK_THREAD_STATE_SOUND_SOLO_PLAY_START;
125 g_cond_signal(&hcamcorder->task_thread_cond);
126 g_mutex_unlock(&hcamcorder->task_thread_lock);
128 info_video->base_video_ts = current_ts;
131 if (_mmcamcorder_invoke_video_stream_cb(handle, sample, FALSE, -1) == FALSE) {
132 /* increase base video timestamp by frame duration,
133 it will remove delay of dropped buffer when play recorded file. */
134 info_video->base_video_ts += current_ts - info_video->last_video_ts;
135 MMCAM_LOG_DEBUG("do not push buffer to encode by app's return value");
136 goto _VIDEO_PUSH_BUFFER_DONE;
140 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer) = current_ts - info_video->base_video_ts;
142 MMCAM_LOG_DEBUG("buffer[%p] - timestamp[%"GST_TIME_FORMAT"]",
143 buffer, GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));
145 /* It will INCREASE reference count of buffer */
146 g_signal_emit_by_name(element[_MMCAMCORDER_ENCSINK_SRC].gst, "push-buffer", buffer, &ret);
148 MMCAM_LOG_VERBOSE("push buffer result : 0x%x", ret);
150 _VIDEO_PUSH_BUFFER_DONE:
151 info_video->last_video_ts = current_ts;
153 if (info_video->is_first_frame) {
154 info_video->is_first_frame = FALSE;
156 /* drop buffer if it's from tizen allocator */
157 if (gst_is_tizen_memory(gst_buffer_peek_memory(buffer, 0))) {
158 MMCAM_LOG_WARNING("drop first buffer from tizen allocator to avoid copy in basesrc");
164 /* skip display if too fast FPS */
165 if (info_video->record_dual_stream == FALSE &&
166 info_video->fps > _MMCAMCORDER_FRAME_PASS_MIN_FPS) {
167 if (info_video->prev_preview_ts != 0) {
168 if (GST_BUFFER_PTS(buffer) - info_video->prev_preview_ts < _MMCAMCORDER_MIN_TIME_TO_PASS_FRAME) {
169 MMCAM_LOG_VERBOSE("it's too fast. drop frame...");
174 MMCAM_LOG_VERBOSE("display buffer [%p]", buffer);
176 info_video->prev_preview_ts = GST_BUFFER_PTS(buffer);
183 static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
185 mmf_return_if_fail(sample);
187 /* no need to check return value here */
188 _mmcamcorder_video_push_buffer(u_data, sample);
190 gst_sample_unref(sample);
194 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
197 int err = MM_ERROR_NONE;
198 const char* gst_element_rsink_name = NULL;
201 GstPad *srcpad = NULL;
202 GstPad *sinkpad = NULL;
204 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
205 _MMCamcorderSubContext *sc = NULL;
207 type_element *RecordsinkElement = NULL;
209 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
211 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
212 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
213 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
215 MMCAM_LOG_WARNING("start");
217 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
218 if (err != MM_ERROR_NONE)
222 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
223 MMCAM_LOG_INFO("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
224 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
225 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
228 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
230 /* get audio disable */
231 mm_camcorder_get_attributes(handle, NULL,
232 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
235 MMCAM_LOG_INFO("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d, ved_cb %p",
236 sc->audio_disable, sc->is_modified_rate, hcamcorder->vedecision_cb);
238 if (sc->is_modified_rate || hcamcorder->vedecision_cb) {
239 MMCAM_LOG_INFO("audio disabled[prev:%d]", sc->audio_disable);
240 sc->audio_disable = TRUE;
243 if (sc->audio_disable == FALSE) {
244 /* create audiosrc bin */
245 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
246 if (err != MM_ERROR_NONE)
250 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
251 if (err != MM_ERROR_NONE)
254 if (sc->audio_disable == FALSE) {
255 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
256 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
259 /* add elements and encodesink bin to encode main pipeline */
260 if (sc->info_video->use_videoscale) {
261 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
262 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
263 sc->encode_element[_MMCAMCORDER_ENCSINK_CAPS].gst,
264 sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst,
265 sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_CAPS].gst,
266 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
269 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
270 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
271 sc->encode_element[_MMCAMCORDER_ENCSINK_CAPS].gst,
272 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
276 /* Link each element : appsrc - capsfilter - encodesink bin */
277 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
278 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_CAPS].gst, "sink");
279 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
281 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_CAPS].gst, "src");
282 if (sc->info_video->use_videoscale) {
283 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].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].gst, "src");
287 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_CAPS].gst, "sink");
288 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
290 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_CAPS].gst, "src");
292 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
293 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
295 if (sc->audio_disable == FALSE) {
296 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
297 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
298 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
301 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
302 CONFIGURE_CATEGORY_MAIN_RECORD,
305 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
307 if (!gst_element_rsink_name) {
308 MMCAM_LOG_ERROR("failed to get recordsink name");
309 err = MM_ERROR_CAMCORDER_INTERNAL;
310 goto pipeline_creation_error;
313 /* set data probe function */
315 /* register message cb */
317 /* set data probe functions */
318 if (sc->audio_disable == FALSE) {
319 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
320 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
321 __mmcamcorder_audioque_dataprobe, hcamcorder);
322 gst_object_unref(sinkpad);
326 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
327 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
328 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
329 gst_object_unref(srcpad);
332 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
333 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
334 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
335 __mmcamcorder_eventprobe_monitor, hcamcorder);
336 gst_object_unref(srcpad);
341 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
342 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
343 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
344 __mmcamcorder_eventprobe_monitor, hcamcorder);
345 gst_object_unref(srcpad);
349 if (sc->audio_disable) {
350 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
351 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
352 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
353 gst_object_unref(sinkpad);
357 if (!strcmp(gst_element_rsink_name, "filesink")) {
358 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
359 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
360 __mmcamcorder_video_dataprobe_encoded, hcamcorder);
361 gst_object_unref(srcpad);
364 if (sc->audio_disable == FALSE) {
365 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
366 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
367 __mmcamcorder_audio_dataprobe_check, hcamcorder);
368 gst_object_unref(srcpad);
373 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
374 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
375 __mmcamcorder_muxed_dataprobe, hcamcorder);
376 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
377 __mmcamcorder_eventprobe_monitor, hcamcorder);
378 gst_object_unref(sinkpad);
381 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
383 /* set sync handler */
384 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
386 gst_object_unref(bus);
389 return MM_ERROR_NONE;
391 pipeline_creation_error:
392 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
393 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
395 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
400 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
402 GstPad *srcpad = NULL;
403 GstPad *sinkpad = NULL;
404 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
405 _MMCamcorderSubContext *sc = NULL;
407 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
409 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
410 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
411 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
415 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
416 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
417 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
418 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
420 /* release audiosrc bin */
421 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
422 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
425 To avoid conflicting between old elements and newly created elements,
426 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
427 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
428 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
429 It's because the pipeline of audio recording destroys at the same time,
430 and '_mmcamcorder_element_release_noti' will perform removing handle.
432 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
434 MMCAM_LOG_INFO("Audio pipeline removed");
437 return MM_ERROR_NONE;
441 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
443 GstPad *reqpad = NULL;
444 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
445 _MMCamcorderSubContext *sc = NULL;
446 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
447 int ret = MM_ERROR_NONE;
448 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
450 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
452 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
453 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
454 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
458 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
459 /* release request pad */
460 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
462 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
463 gst_object_unref(reqpad);
467 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
469 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
470 gst_object_unref(reqpad);
474 /* release encode main pipeline */
475 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
478 To avoid conflicting between old elements and newly created elements,
479 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
480 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
481 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
482 It's because the pipeline of audio recording destroys at the same time,
483 and '_mmcamcorder_element_release_noti' will perform removing handle.
485 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
486 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
488 MMCAM_LOG_WARNING("Encoder pipeline removed");
490 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
491 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
493 MMCAM_LOG_WARNING("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
495 if (hcamcorder->is_release_cb_calling == FALSE) {
496 /* release resource */
497 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
498 hcamcorder->video_encoder_resource);
499 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
500 hcamcorder->video_encoder_resource = NULL;
502 MMCAM_LOG_WARNING("mark resource for release 0x%x", ret);
504 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
506 MMCAM_LOG_WARNING("commit resource release 0x%x", ret);
509 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
511 MMCAM_LOG_WARNING("unlock resource");
512 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
515 return MM_ERROR_NONE;
519 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
521 int ret = MM_ERROR_NONE;
522 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
523 _MMCamcorderSubContext *sc = NULL;
527 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
528 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
529 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
531 MMCAM_LOG_INFO("start");
533 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
534 MMCAM_LOG_WARNING("pipeline is not existed.");
535 return MM_ERROR_NONE;
538 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
540 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
541 if (ret != MM_ERROR_NONE) {
542 MMCAM_LOG_ERROR("Failed to change encode main pipeline [0x%x]", ret);
546 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
548 /* remove audio pipeline first */
549 ret = _mmcamcorder_remove_audio_pipeline(handle);
550 if (ret != MM_ERROR_NONE) {
551 MMCAM_LOG_ERROR("Fail to remove audio pipeline");
555 ret = _mmcamcorder_remove_encode_pipeline(handle);
556 if (ret != MM_ERROR_NONE) {
557 MMCAM_LOG_ERROR("Fail to remove encoder pipeline");
561 /* Remove remained message */
563 GstMessage *gst_msg = NULL;
564 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
565 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
566 gst_message_unref(gst_msg);
569 gst_object_unref(bus);
573 MMCAM_LOG_INFO("done");
579 int _mmcamcorder_video_command(MMHandleType handle, int command)
584 int gop_interval = 0;
585 int ret = MM_ERROR_NONE;
586 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
587 char *err_name = NULL;
588 char *target_filename = NULL;
589 GstCameraControl *CameraControl = NULL;
592 GstElement *pipeline = NULL;
594 _MMCamcorderVideoInfo *info = NULL;
595 _MMCamcorderSubContext *sc = NULL;
596 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
598 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
600 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
601 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
602 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
603 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
605 info = sc->info_video;
607 MMCAM_LOG_INFO("Command(%d)", command);
609 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
612 case _MMCamcorder_CMD_RECORD:
614 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
618 gboolean storage_validity = FALSE;
621 int root_directory_length = 0;
624 MMCAM_LOG_INFO("Record Start - dual stream %d", info->support_dual_stream);
626 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
627 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
629 /* prepare resource manager for H/W encoder */
630 if (hcamcorder->video_encoder_resource == NULL) {
631 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
632 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
633 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
634 &hcamcorder->video_encoder_resource);
635 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
636 MMCAM_LOG_ERROR("could not prepare for encoder resource");
637 ret = MM_ERROR_RESOURCE_INTERNAL;
638 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
639 goto _ERR_CAMCORDER_VIDEO_COMMAND;
642 MMCAM_LOG_INFO("encoder already acquired");
645 /* acquire resources */
646 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
647 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
648 MMCAM_LOG_ERROR("could not acquire resources");
649 ret = MM_ERROR_RESOURCE_INTERNAL;
650 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
651 goto _ERR_CAMCORDER_VIDEO_COMMAND;
654 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
655 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
657 /* init record_dual_stream */
658 info->record_dual_stream = FALSE;
660 ret = mm_camcorder_get_attributes(handle, &err_name,
661 MMCAM_CAMERA_FPS, &fps,
662 MMCAM_CAMERA_WIDTH, &(info->preview_width),
663 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
664 MMCAM_VIDEO_WIDTH, &(info->video_width),
665 MMCAM_VIDEO_HEIGHT, &(info->video_height),
666 MMCAM_FILE_FORMAT, &fileformat,
667 MMCAM_TARGET_FILENAME, &target_filename, &size,
668 MMCAM_TARGET_MAX_SIZE, &imax_size,
669 MMCAM_TARGET_TIME_LIMIT, &imax_time,
670 MMCAM_FILE_FORMAT, &(info->fileformat),
671 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
672 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
674 if (ret != MM_ERROR_NONE) {
675 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, ret);
677 goto _ERR_CAMCORDER_VIDEO_COMMAND;
680 if (!target_filename && !hcamcorder->mstream_cb) {
681 MMCAM_LOG_ERROR("filename is not set and muxed stream cb is NULL");
682 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
683 goto _ERR_CAMCORDER_VIDEO_COMMAND;
688 info->max_size = 0; /* do not check */
690 info->max_size = ((guint64)imax_size) << 10; /* to byte */
694 info->max_time = 0; /* do not check */
696 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
698 ret = _mmcamcorder_get_storage_validity(hcamcorder, target_filename,
699 _MMCAMCORDER_VIDEO_MINIMUM_SPACE, &storage_validity);
700 if (ret != MM_ERROR_NONE) {
701 MMCAM_LOG_ERROR("storage validation failed[0x%x]:%d", ret, storage_validity);
705 _mmcamcorder_adjust_recording_max_size(target_filename, &info->max_size);
707 g_mutex_lock(&hcamcorder->task_thread_lock);
708 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
709 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
710 /* Play record start sound */
711 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
713 g_mutex_unlock(&hcamcorder->task_thread_lock);
715 MMCAM_LOG_WARNING("video size [%dx%d]", info->video_width, info->video_height);
717 if (info->video_width == 0 || info->video_height == 0) {
718 MMCAM_LOG_WARNING("video size is invalid [%dx%d] use preview size [%dx%d]",
719 info->video_width, info->video_height, info->preview_width, info->preview_height);
720 info->video_width = info->preview_width;
721 info->video_height = info->preview_height;
724 if (info->support_dual_stream) {
725 MMCAM_LOG_WARNING("DUAL STREAM MODE");
727 info->record_dual_stream = TRUE;
729 /* No need to restart preview */
730 info->restart_preview = FALSE;
732 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
733 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
734 } else if (_mmcamcorder_is_encoded_preview_pixel_format(sc->info_image->preview_format) &&
735 info->preview_width == info->video_width &&
736 info->preview_height == info->video_height) {
737 MMCAM_LOG_INFO("Encoded[%d] preview mode and same resolution", sc->info_image->preview_format);
738 /* No need to restart preview */
739 info->restart_preview = FALSE;
740 } else if (info->use_videoscale &&
741 info->preview_width >= info->video_width &&
742 info->preview_height >= info->video_height) {
743 info->restart_preview = FALSE;
745 info->restart_preview = TRUE;
746 /* reset use_videoscale */
747 info->use_videoscale = FALSE;
750 /* set recording hint */
751 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
753 if (info->restart_preview) {
754 /* stop preview and set new size */
755 MMCAM_LOG_INFO("restart preview");
757 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
758 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
759 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
761 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
763 /* check decoder recreation */
764 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
765 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
766 ret = MM_ERROR_CAMCORDER_INTERNAL;
767 goto _ERR_CAMCORDER_VIDEO_COMMAND;
770 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
771 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
772 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
774 if (ret != MM_ERROR_NONE)
775 goto _ERR_CAMCORDER_VIDEO_COMMAND;
777 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
778 ret = MM_ERROR_CAMCORDER_INTERNAL;
779 goto _ERR_CAMCORDER_VIDEO_COMMAND;
782 /* Start preview again with new setting */
783 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
784 if (ret != MM_ERROR_NONE)
785 goto _ERR_CAMCORDER_VIDEO_COMMAND;
787 if (motion_rate < 1.0) {
788 MMCAM_LOG_WARNING("wait for stabilization of frame");
792 MMCAM_LOG_INFO("no need to restart preview");
795 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
796 CONFIGURE_CATEGORY_MAIN_RECORD,
800 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
801 CONFIGURE_CATEGORY_MAIN_RECORD,
802 "PassFirstVideoFrame",
803 &(sc->pass_first_vframe));
805 MMCAM_LOG_INFO("Drop video frame count[%d], Pass first video frame count[%d]",
806 sc->drop_vframe, sc->pass_first_vframe);
808 info->record_drop_count = (guint)motion_rate;
809 info->record_motion_rate = motion_rate;
810 if (sc->is_modified_rate)
811 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
813 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
815 MMCAM_LOG_WARNING("recording fps %d, motion rate %f, timestamp_ratio %f",
816 fps, info->record_motion_rate, info->record_timestamp_ratio);
818 /* set push buffer flag */
819 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
820 info->base_video_ts = 0;
822 /* connect video stream cb signal if it supports dual stream. */
823 if (info->record_dual_stream) {
824 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
825 goto _ERR_CAMCORDER_VIDEO_COMMAND;
828 /* start video stream */
829 if (info->record_dual_stream) {
830 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
832 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
834 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
835 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
837 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
839 MMCAM_LOG_ERROR("could not get camera control");
843 /* check pre-created encode pipeline */
844 g_mutex_lock(&hcamcorder->task_thread_lock);
845 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
846 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
847 /* create encoding pipeline */
848 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
849 if (ret != MM_ERROR_NONE) {
850 g_mutex_unlock(&hcamcorder->task_thread_lock);
851 goto _ERR_CAMCORDER_VIDEO_COMMAND;
854 g_mutex_unlock(&hcamcorder->task_thread_lock);
856 /* check recording start sound */
857 _mmcamcorder_sound_solo_play_wait(handle);
859 /**< To fix video recording hanging
860 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
861 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
862 basetime wouldn't change if you set (GstClockTime)0.
863 3. Move set start time position below PAUSED of pipeline.
866 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
867 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
870 info->video_frame_count = 0;
871 info->is_first_frame = TRUE;
872 info->audio_frame_count = 0;
874 sc->ferror_send = FALSE;
875 sc->ferror_count = 0;
876 hcamcorder->error_occurs = FALSE;
877 sc->bget_eos = FALSE;
878 sc->muxed_stream_offset = 0;
880 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
881 if (ret != MM_ERROR_NONE) {
882 /* stop video stream */
883 if (info->record_dual_stream) {
884 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
886 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
888 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
889 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
891 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
893 MMCAM_LOG_ERROR("failed to get camera control");
897 /* Remove recorder pipeline and recording file which size maybe zero */
898 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
899 if (info->filename) {
900 MMCAM_LOG_INFO("file delete(%s)", info->filename);
901 unlink(info->filename);
903 goto _ERR_CAMCORDER_VIDEO_COMMAND;
906 /*set the GOP so that video record will get a new key frame*/
907 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
908 if (mm_camcorder_get_attributes(handle, NULL,
909 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
910 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
912 MMCAM_LOG_ERROR("get gop interval failed");
916 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
917 if (mm_camcorder_get_attributes(handle, NULL,
918 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
919 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
921 MMCAM_LOG_ERROR("get gop interval failed");
924 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
926 MMCAM_LOG_INFO("Object property settings done");
930 case _MMCamcorder_CMD_PAUSE:
932 if (info->b_committing) {
933 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
934 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
937 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
938 if (sc->audio_disable) {
939 /* check only video frame */
940 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
942 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
943 MMCAM_LOG_ERROR("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
944 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
946 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
949 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
951 /* check both of video and audio frame */
952 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
954 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
955 MMCAM_LOG_ERROR("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
956 info->video_frame_count, info->audio_frame_count);
957 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
959 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
960 count, info->video_frame_count, info->audio_frame_count);
963 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
967 /* block encodebin */
968 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
971 case _MMCamcorder_CMD_CANCEL:
973 if (info->b_committing) {
974 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
975 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
978 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
980 if (hcamcorder->capture_in_recording == FALSE) {
982 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
983 MMCAM_LOG_ERROR("Failed to Wait capture data");
984 hcamcorder->capture_in_recording = FALSE;
987 MMCAM_LOG_WARNING("Waiting for capture data - retrial [%d]", count);
990 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
993 /* block push buffer */
994 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
996 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
997 if (ret != MM_ERROR_NONE)
998 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1000 /* set recording hint */
1001 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1003 /* stop video stream */
1004 if (info->record_dual_stream) {
1005 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1006 if (CameraControl) {
1007 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1009 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1010 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1012 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1014 MMCAM_LOG_ERROR("failed to get camera control");
1018 if (info->restart_preview) {
1019 /* restart preview */
1020 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1021 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1022 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1024 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1026 /* check decoder recreation */
1027 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1028 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1029 ret = MM_ERROR_CAMCORDER_INTERNAL;
1032 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1033 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1034 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1036 if (ret != MM_ERROR_NONE)
1037 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1039 /* reset restart_preview for inset window layout */
1040 info->restart_preview = FALSE;
1042 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1043 ret = MM_ERROR_CAMCORDER_INTERNAL;
1044 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1047 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1048 if (ret != MM_ERROR_NONE)
1049 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1052 /* remove target file */
1053 if (info->filename) {
1054 MMCAM_LOG_INFO("file delete(%s)", info->filename);
1055 unlink(info->filename);
1058 sc->isMaxsizePausing = FALSE;
1059 sc->isMaxtimePausing = FALSE;
1061 sc->display_interval = 0;
1062 sc->previous_slot_time = 0;
1063 info->video_frame_count = 0;
1064 info->audio_frame_count = 0;
1066 hcamcorder->capture_in_recording = FALSE;
1069 case _MMCamcorder_CMD_COMMIT:
1073 if (info->b_committing) {
1074 MMCAM_LOG_ERROR("now on committing previous file!!(command : %d)", command);
1075 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1077 MMCAM_LOG_INFO("_MMCamcorder_CMD_COMMIT : start");
1078 info->b_committing = TRUE;
1079 sc->bget_eos = FALSE;
1082 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1083 if (sc->audio_disable) {
1084 /* check only video frame */
1085 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1086 hcamcorder->capture_in_recording == FALSE) {
1088 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1089 MMCAM_LOG_ERROR("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1090 info->video_frame_count, hcamcorder->capture_in_recording);
1092 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1093 MMCAM_LOG_WARNING("video frames are enough. keep going...");
1095 info->b_committing = FALSE;
1096 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1099 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1100 count, info->video_frame_count, hcamcorder->capture_in_recording);
1103 /* check both of video and audio frame */
1104 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1105 info->audio_frame_count &&
1106 hcamcorder->capture_in_recording == FALSE) {
1108 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1109 MMCAM_LOG_ERROR("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1110 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1112 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1113 MMCAM_LOG_WARNING("video/audio frames are enough. keep going...");
1115 info->b_committing = FALSE;
1116 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1119 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1121 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1122 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1126 if (hcamcorder->capture_in_recording) {
1127 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1128 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1129 MMCAM_LOG_WARNING("timeout");
1131 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1135 /* block push buffer */
1136 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1137 MMCAM_LOG_INFO("block push buffer to appsrc");
1139 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1140 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1141 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1142 ret = MM_ERROR_OUT_OF_STORAGE;
1143 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1146 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1147 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1148 MMCAM_LOG_WARNING("VIDEO: send eos to appsrc done");
1150 MMCAM_LOG_ERROR("VIDEO: send EOS failed");
1151 info->b_committing = FALSE;
1152 ret = MM_ERROR_CAMCORDER_INTERNAL;
1153 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1156 MMCAM_LOG_ERROR("No video stream source");
1157 info->b_committing = FALSE;
1158 ret = MM_ERROR_CAMCORDER_INTERNAL;
1159 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1162 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1163 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1164 MMCAM_LOG_WARNING("AUDIO: send eos to audiosrc done");
1166 MMCAM_LOG_ERROR("AUDIO: send EOS failed");
1167 info->b_committing = FALSE;
1168 ret = MM_ERROR_CAMCORDER_INTERNAL;
1169 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1172 MMCAM_LOG_INFO("No audio stream");
1176 sc->display_interval = 0;
1177 sc->previous_slot_time = 0;
1180 MMCAM_LOG_INFO("Start to wait EOS");
1181 ret = _mmcamcorder_get_eos_message(handle);
1182 if (ret != MM_ERROR_NONE) {
1183 info->b_committing = FALSE;
1184 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1188 hcamcorder->capture_in_recording = FALSE;
1192 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1193 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1196 return MM_ERROR_NONE;
1198 _ERR_CAMCORDER_VIDEO_COMMAND:
1199 if (command == _MMCamcorder_CMD_RECORD)
1200 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1206 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1208 int ret = MM_ERROR_NONE;
1210 guint64 file_size = 0;
1212 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1213 _MMCamcorderSubContext *sc = NULL;
1214 _MMCamcorderVideoInfo *info = NULL;
1215 _MMCamcorderMsgItem msg;
1216 MMCamRecordingReport *report = NULL;
1218 mmf_return_val_if_fail(hcamcorder, FALSE);
1220 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1221 mmf_return_val_if_fail(sc, FALSE);
1222 mmf_return_val_if_fail(sc->info_video, FALSE);
1224 info = sc->info_video;
1226 MMCAM_LOG_ERROR("");
1228 /* Play record stop sound */
1229 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1231 /* remove blocking part */
1232 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1234 mm_camcorder_get_attributes(handle, NULL,
1235 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1238 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1239 if (ret != MM_ERROR_NONE)
1240 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1242 /* set recording hint */
1243 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1245 /* stop video stream */
1246 if (info->record_dual_stream) {
1247 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1249 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1251 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1252 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1254 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1256 MMCAM_LOG_ERROR("failed to get camera control");
1260 if (enabletag && !(sc->ferror_send)) {
1261 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1262 MMCAM_LOG_INFO("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1265 /* Check file size */
1266 if (info->max_size > 0) {
1267 _mmcamcorder_get_file_size(info->filename, &file_size);
1268 MMCAM_LOG_INFO("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1269 info->max_size, file_size);
1271 if (file_size > info->max_size) {
1272 _MMCamcorderMsgItem message;
1273 MMCAM_LOG_ERROR("File size is greater than max size !!");
1274 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1275 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1276 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1280 if (info->restart_preview) {
1282 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1283 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1284 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1286 MMCAM_LOG_INFO("Set state of pipeline as READY");
1287 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1289 /* check decoder recreation */
1290 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1291 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1292 ret = MM_ERROR_CAMCORDER_INTERNAL;
1296 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1297 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1298 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1300 if (ret != MM_ERROR_NONE) {
1301 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1302 msg.param.code = ret;
1303 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1304 MMCAM_LOG_ERROR("Failed to set state READY[%x]", ret);
1307 /* reset restart_preview for inset window layout */
1308 info->restart_preview = FALSE;
1310 /* recover preview size */
1311 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1312 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1313 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1314 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1315 MMCAM_LOG_ERROR("Failed to set camera resolution %dx%d",
1316 info->preview_width, info->preview_height);
1319 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1320 /* Do not return when error is occurred.
1321 Recording file was created successfully, but starting pipeline failed */
1322 if (ret != MM_ERROR_NONE) {
1323 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1324 msg.param.code = ret;
1325 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1326 MMCAM_LOG_ERROR("Failed to set state PLAYING[%x]", ret);
1329 MMCAM_LOG_INFO("No need to restart preview");
1332 /* Send recording report to application */
1333 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1334 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1335 report->recording_filename = g_strdup(info->filename);
1336 msg.param.data = report;
1338 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1341 sc->pipeline_time = 0;
1343 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1344 sc->isMaxtimePausing = FALSE;
1345 hcamcorder->error_occurs = FALSE;
1347 info->video_frame_count = 0;
1348 info->audio_frame_count = 0;
1350 info->b_committing = FALSE;
1352 /* check recording stop sound */
1353 _mmcamcorder_sound_solo_play_wait(handle);
1355 MMCAM_LOG_ERROR("_MMCamcorder_CMD_COMMIT : end");
1361 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1363 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1364 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1366 _MMCamcorderSubContext *sc = NULL;
1367 _MMCamcorderVideoInfo *videoinfo = NULL;
1368 _MMCamcorderMsgItem msg;
1369 guint64 buffer_size = 0;
1370 guint64 trailer_size = 0;
1371 guint64 max_size = 0;
1373 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1374 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1375 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1377 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1378 videoinfo = sc->info_video;
1380 /* get buffer size */
1381 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1382 MMCAM_LOG_WARNING("map failed : buffer %p", buffer);
1383 return GST_PAD_PROBE_OK;
1386 buffer_size = mapinfo.size;
1387 gst_buffer_unmap(buffer, &mapinfo);
1389 g_mutex_lock(&videoinfo->size_check_lock);
1391 if (videoinfo->audio_frame_count == 0) {
1392 videoinfo->filesize += buffer_size;
1393 videoinfo->audio_frame_count++;
1394 g_mutex_unlock(&videoinfo->size_check_lock);
1395 return GST_PAD_PROBE_OK;
1398 if (sc->ferror_send || sc->isMaxsizePausing) {
1399 MMCAM_LOG_WARNING("Recording is paused, drop frames");
1400 g_mutex_unlock(&videoinfo->size_check_lock);
1401 return GST_PAD_PROBE_DROP;
1404 /* get trailer size */
1405 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1406 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1410 /* check max size of recorded file */
1411 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1412 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1413 GstState pipeline_state = GST_STATE_VOID_PENDING;
1414 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1416 MMCAM_LOG_WARNING("Max size[%"G_GUINT64_FORMAT"], current size[%"G_GUINT64_FORMAT"],"\
1417 " buffer size[%"G_GUINT64_FORMAT"], trailer size[%"G_GUINT64_FORMAT"]",
1418 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1420 if (!sc->isMaxsizePausing) {
1421 sc->isMaxsizePausing = TRUE;
1422 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1423 if (pipeline_state == GST_STATE_PLAYING)
1424 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1426 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1427 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1430 g_mutex_unlock(&videoinfo->size_check_lock);
1435 videoinfo->filesize += buffer_size;
1436 videoinfo->audio_frame_count++;
1438 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1439 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1441 g_mutex_unlock(&videoinfo->size_check_lock);
1443 return GST_PAD_PROBE_OK;
1447 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1452 guint64 free_space = 0;
1453 guint64 buffer_size = 0;
1454 guint64 trailer_size = 0;
1455 guint64 queued_buffer = 0;
1456 guint64 max_size = 0;
1457 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1459 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1461 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1462 _MMCamcorderMsgItem msg;
1463 _MMCamcorderSubContext *sc = NULL;
1464 _MMCamcorderVideoInfo *videoinfo = NULL;
1466 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1467 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1469 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1470 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1471 videoinfo = sc->info_video;
1473 if (sc->ferror_send) {
1474 MMCAM_LOG_WARNING("file write error, drop frames");
1475 return GST_PAD_PROBE_DROP;
1478 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1479 buffer_size = mapinfo.size;
1480 gst_buffer_unmap(buffer, &mapinfo);
1482 videoinfo->video_frame_count++;
1483 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1484 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1485 g_mutex_lock(&videoinfo->size_check_lock);
1486 videoinfo->filesize += buffer_size;
1487 g_mutex_unlock(&videoinfo->size_check_lock);
1488 return GST_PAD_PROBE_OK;
1491 /* get trailer size */
1492 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1493 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1497 /* check free space */
1498 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1500 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1501 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1502 sc->ferror_send = TRUE;
1504 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1505 msg.param.code = MM_ERROR_FILE_READ;
1507 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1512 return GST_PAD_PROBE_DROP; /* skip this buffer */
1515 if (free_space == 0) {
1516 /* check storage state */
1517 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1519 MMCAM_LOG_WARNING("storage state %d", storage_state);
1521 if (storage_state == STORAGE_STATE_REMOVED ||
1522 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1523 MMCAM_LOG_ERROR("storage was removed!");
1525 _MMCAMCORDER_LOCK(hcamcorder);
1527 if (sc->ferror_send == FALSE) {
1528 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1530 sc->ferror_send = TRUE;
1532 _MMCAMCORDER_UNLOCK(hcamcorder);
1534 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1535 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1537 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1539 _MMCAMCORDER_UNLOCK(hcamcorder);
1540 MMCAM_LOG_WARNING("error was already sent");
1543 return GST_PAD_PROBE_DROP;
1547 /* get queued buffer size */
1548 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1549 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1551 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1552 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1554 queued_buffer = aq_size + vq_size;
1556 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1557 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1558 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1559 free_space, trailer_size, buffer_size, queued_buffer);
1561 if (!sc->isMaxsizePausing) {
1562 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1563 sc->isMaxsizePausing = TRUE;
1565 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1566 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1569 return GST_PAD_PROBE_DROP;
1572 g_mutex_lock(&videoinfo->size_check_lock);
1574 /* check max size of recorded file */
1575 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1576 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1577 GstState pipeline_state = GST_STATE_VOID_PENDING;
1578 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1580 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1581 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1582 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1584 if (!sc->isMaxsizePausing) {
1585 sc->isMaxsizePausing = TRUE;
1586 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1587 if (pipeline_state == GST_STATE_PLAYING)
1588 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1590 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1591 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1594 g_mutex_unlock(&videoinfo->size_check_lock);
1596 return GST_PAD_PROBE_DROP;
1599 videoinfo->filesize += (guint64)buffer_size;
1601 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1602 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1604 g_mutex_unlock(&videoinfo->size_check_lock);
1606 return GST_PAD_PROBE_OK;
1610 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1612 guint64 trailer_size = 0;
1613 guint64 rec_pipe_time = 0;
1614 unsigned int remained_time = 0;
1616 GstClockTime b_time;
1618 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1619 _MMCamcorderMsgItem msg;
1620 _MMCamcorderSubContext *sc = NULL;
1621 _MMCamcorderVideoInfo *videoinfo = NULL;
1623 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1625 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1626 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1628 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1629 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1630 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1632 videoinfo = sc->info_video;
1634 b_time = GST_BUFFER_PTS(buffer);
1636 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1638 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1639 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1643 /* check max time */
1644 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1645 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1646 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1648 if (!sc->isMaxtimePausing) {
1649 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1651 sc->isMaxtimePausing = TRUE;
1653 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1654 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1655 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1656 msg.param.recording_status.remained_time = 0;
1657 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1659 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1660 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1663 return GST_PAD_PROBE_DROP;
1666 /* calculate remained time can be recorded */
1667 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1668 remained_time = videoinfo->max_time - rec_pipe_time;
1669 } else if (videoinfo->max_size > 0) {
1670 long double max_size = (long double)videoinfo->max_size;
1671 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1673 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1676 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1677 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1678 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1679 msg.param.recording_status.remained_time = remained_time;
1680 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1682 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1683 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1685 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1686 record_motion_rate, videoinfo->record_drop_count);
1688 /* drop some frame if fast motion */
1689 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1690 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1691 MMCAM_LOG_VERBOSE("drop frame");
1692 return GST_PAD_PROBE_DROP;
1695 videoinfo->record_drop_count = 1;
1696 MMCAM_LOG_VERBOSE("pass frame");
1699 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1700 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1703 return GST_PAD_PROBE_OK;
1707 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1709 _MMCamcorderMsgItem msg;
1710 guint64 trailer_size = 0;
1711 guint64 rec_pipe_time = 0;
1712 _MMCamcorderSubContext *sc = NULL;
1713 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1714 _MMCamcorderVideoInfo *videoinfo = NULL;
1715 unsigned int remained_time = 0;
1716 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1718 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1719 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1720 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1722 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1723 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1724 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1726 videoinfo = sc->info_video;
1728 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1729 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1730 return GST_PAD_PROBE_OK;
1733 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1735 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1736 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1740 /* calculate remained time can be recorded */
1741 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1742 remained_time = videoinfo->max_time - rec_pipe_time;
1743 } else if (videoinfo->max_size > 0) {
1744 long double max_size = (long double)videoinfo->max_size;
1745 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1747 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1750 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1751 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1752 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1754 if (!sc->isMaxtimePausing) {
1755 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1757 sc->isMaxtimePausing = TRUE;
1759 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1760 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1761 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1762 msg.param.recording_status.remained_time = 0;
1763 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1765 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1766 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1769 return GST_PAD_PROBE_DROP;
1772 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1773 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1774 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1775 msg.param.recording_status.remained_time = remained_time;
1776 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1778 MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1779 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1781 return GST_PAD_PROBE_OK;
1785 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1787 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1788 double volume = 0.0;
1791 int err = MM_ERROR_UNKNOWN;
1792 char *err_name = NULL;
1793 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1796 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1797 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1799 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1800 MMCAM_AUDIO_VOLUME, &volume,
1801 MMCAM_AUDIO_FORMAT, &format,
1802 MMCAM_AUDIO_CHANNEL, &channel,
1804 if (err != MM_ERROR_NONE) {
1805 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1806 SAFE_FREE(err_name);
1810 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1812 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1814 /* Set audio stream NULL */
1816 memset(mapinfo.data, 0, mapinfo.size);
1818 MMCAM_LOG_DEBUG("audio stream[%"GST_TIME_FORMAT"] - cb[%p], fmt[%d], ch[%d], size[%"G_GSIZE_FORMAT"]",
1819 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), hcamcorder->astream_cb, format, channel, mapinfo.size);
1821 /* CALL audio stream callback */
1822 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1823 MMCamcorderAudioStreamDataType stream;
1825 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1826 MMCAM_LOG_WARNING("Not ready for stream callback");
1827 gst_buffer_unmap(buffer, &mapinfo);
1828 return GST_PAD_PROBE_OK;
1831 stream.data = (void *)mapinfo.data;
1832 stream.format = format;
1833 stream.channel = channel;
1834 stream.length = mapinfo.size;
1835 stream.timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)));
1837 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1839 if (hcamcorder->astream_cb)
1840 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1842 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1845 gst_buffer_unmap(buffer, &mapinfo);
1847 return GST_PAD_PROBE_OK;
1851 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1853 gboolean bret = FALSE;
1855 switch (fileformat) {
1856 case MM_FILE_FORMAT_3GP:
1857 case MM_FILE_FORMAT_MP4:
1858 bret = __mmcamcorder_add_metadata_mp4(handle);
1861 MMCAM_LOG_WARNING("Unsupported fileformat to insert location info (%d)", fileformat);
1869 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1873 guint64 udta_size = 0;
1874 gint64 current_pos = 0;
1875 gint64 moov_pos = 0;
1876 gint64 udta_pos = 0;
1877 gdouble longitude = 0;
1878 gdouble latitude = 0;
1879 gdouble altitude = 0;
1881 int orientation = 0;
1883 char *err_name = NULL;
1884 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1885 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1886 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1888 _MMCamcorderVideoInfo *info = NULL;
1889 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1890 _MMCamcorderSubContext *sc = NULL;
1892 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1893 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1895 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1896 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1900 info = sc->info_video;
1902 f = fopen64(info->filename, "rb+");
1904 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1905 MMCAM_LOG_ERROR("file open failed [%s]", err_msg);
1909 mm_camcorder_get_attributes(handle, &err_name,
1910 MMCAM_TAG_LATITUDE, &latitude,
1911 MMCAM_TAG_LONGITUDE, &longitude,
1912 MMCAM_TAG_ALTITUDE, &altitude,
1913 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1914 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1917 MMCAM_LOG_WARNING("Get tag attrs fail. (%s:%x)", err_name, err);
1918 SAFE_FREE(err_name);
1921 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1922 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1923 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1924 geo_info.longitude = longitude *10000;
1925 geo_info.latitude = latitude *10000;
1926 geo_info.altitude = altitude *10000;
1927 /* find udta container.
1928 if, there are udta container, write loci box after that
1929 else, make udta container and write loci box. */
1930 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1933 MMCAM_LOG_INFO("find udta container");
1936 if (fseek(f, -8L, SEEK_CUR) != 0)
1939 udta_pos = ftello(f);
1943 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1945 MMCAM_LOG_INFO("recorded file fread %zu", nread);
1947 udta_size = _mmcamcorder_get_container_size(buf);
1949 /* goto end of udta and write 'loci' box */
1950 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1954 if (!_mmcamcorder_write_loci(f, location_info)) {
1955 MMCAM_LOG_ERROR("failed to write loci");
1959 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1960 MMCAM_LOG_ERROR("failed to write geodata");
1965 current_pos = ftello(f);
1966 if (current_pos < 0)
1969 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1972 MMCAM_LOG_INFO("No udta container");
1973 if (fseek(f, 0, SEEK_END) != 0)
1976 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1977 MMCAM_LOG_ERROR("failed to write udta");
1982 /* find moov container.
1983 update moov container size. */
1984 if ((current_pos = ftello(f)) < 0)
1987 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1988 gint64 internal_pos = ftello(f);
1990 MMCAM_LOG_INFO("found moov container");
1991 if (fseek(f, -8L, SEEK_CUR) != 0)
1994 moov_pos = ftello(f);
1998 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
2001 /* add orientation info */
2002 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
2003 MMCAM_LOG_ERROR("fseeko failed : errno %d", errno);
2007 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
2008 MMCAM_LOG_ERROR("failed to find [trak] tag");
2012 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2013 MMCAM_LOG_ERROR("failed to find [tkhd] tag");
2017 MMCAM_LOG_INFO("found [tkhd] tag");
2019 /* seek to start position of composition matrix */
2020 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2021 /* update composition matrix for orientation */
2022 _mmcamcorder_update_composition_matrix(f, orientation);
2024 MMCAM_LOG_ERROR("fseek failed : errno %d", errno);
2028 MMCAM_LOG_ERROR("No 'moov' container");
2040 MMCAM_LOG_ERROR("ftell() returns negative value.");
2046 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2048 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2049 _MMCamcorderSubContext *sc = NULL;
2051 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2053 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2054 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2056 /* check video source element */
2057 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2058 MMCAM_LOG_WARNING("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2059 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2060 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2061 G_CALLBACK(__mmcamcorder_video_stream_cb),
2063 return MM_ERROR_NONE;
2065 MMCAM_LOG_ERROR("videosrc element is not created yet");
2066 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2071 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2073 int ret = MM_ERROR_NONE;
2075 char *temp_filename = NULL;
2077 _MMCamcorderVideoInfo *info = NULL;
2078 _MMCamcorderSubContext *sc = NULL;
2079 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2081 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2083 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2084 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2085 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2087 info = sc->info_video;
2089 MMCAM_LOG_WARNING("start");
2091 /* create encoding pipeline */
2092 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2093 if (ret != MM_ERROR_NONE)
2094 goto _ERR_PREPARE_RECORD;
2096 SAFE_G_FREE(info->filename);
2098 mm_camcorder_get_attributes(handle, NULL,
2099 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2101 if (temp_filename) {
2102 info->filename = g_strdup(temp_filename);
2103 if (!info->filename) {
2104 MMCAM_LOG_ERROR("strdup[src:%p] was failed", temp_filename);
2105 goto _ERR_PREPARE_RECORD;
2108 MMCAM_LOG_INFO("Record file name [%s]", info->filename);
2109 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2111 MMCAM_LOG_INFO("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2112 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2115 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2117 /* Adjust display FPS */
2118 sc->display_interval = 0;
2119 sc->previous_slot_time = 0;
2121 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2122 if (ret != MM_ERROR_NONE)
2123 goto _ERR_PREPARE_RECORD;
2125 MMCAM_LOG_WARNING("done");
2129 _ERR_PREPARE_RECORD:
2130 /* Remove recorder pipeline and recording file which size maybe zero */
2131 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2132 if (info && info->filename) {
2133 MMCAM_LOG_INFO("file delete(%s)", info->filename);
2134 unlink(info->filename);