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);
325 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
326 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
327 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
328 gst_object_unref(srcpad);
330 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
331 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
332 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
333 __mmcamcorder_eventprobe_monitor, hcamcorder);
334 gst_object_unref(srcpad);
338 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
339 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
340 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
341 __mmcamcorder_eventprobe_monitor, hcamcorder);
342 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);
352 if (!strcmp(gst_element_rsink_name, "filesink")) {
353 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
354 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
355 __mmcamcorder_video_dataprobe_encoded, hcamcorder);
356 gst_object_unref(srcpad);
358 if (sc->audio_disable == FALSE) {
359 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
360 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
361 __mmcamcorder_audio_dataprobe_check, hcamcorder);
362 gst_object_unref(srcpad);
366 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
367 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
368 __mmcamcorder_muxed_dataprobe, hcamcorder);
369 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
370 __mmcamcorder_eventprobe_monitor, hcamcorder);
371 gst_object_unref(sinkpad);
373 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
375 /* set sync handler */
376 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
378 gst_object_unref(bus);
380 return MM_ERROR_NONE;
382 pipeline_creation_error:
383 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
384 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
386 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
391 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
393 GstPad *srcpad = NULL;
394 GstPad *sinkpad = NULL;
395 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
396 _MMCamcorderSubContext *sc = NULL;
398 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
400 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
401 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
402 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
406 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
407 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
408 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
409 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
411 /* release audiosrc bin */
412 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
413 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
416 To avoid conflicting between old elements and newly created elements,
417 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
418 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
419 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
420 It's because the pipeline of audio recording destroys at the same time,
421 and '_mmcamcorder_element_release_noti' will perform removing handle.
423 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
425 MMCAM_LOG_INFO("Audio pipeline removed");
428 return MM_ERROR_NONE;
432 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
434 GstPad *reqpad = NULL;
435 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
436 _MMCamcorderSubContext *sc = NULL;
437 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
438 int ret = MM_ERROR_NONE;
439 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
441 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
443 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
444 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
445 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
449 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
450 /* release request pad */
451 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
453 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
454 gst_object_unref(reqpad);
457 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
459 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
460 gst_object_unref(reqpad);
463 /* release encode main pipeline */
464 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
467 To avoid conflicting between old elements and newly created elements,
468 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
469 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
470 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
471 It's because the pipeline of audio recording destroys at the same time,
472 and '_mmcamcorder_element_release_noti' will perform removing handle.
474 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
475 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
477 MMCAM_LOG_WARNING("Encoder pipeline removed");
479 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
480 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
482 MMCAM_LOG_WARNING("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
484 if (hcamcorder->is_release_cb_calling == FALSE) {
485 /* release resource */
486 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
487 hcamcorder->video_encoder_resource);
488 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
489 hcamcorder->video_encoder_resource = NULL;
491 MMCAM_LOG_WARNING("mark resource for release 0x%x", ret);
493 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
495 MMCAM_LOG_WARNING("commit resource release 0x%x", ret);
498 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
500 MMCAM_LOG_WARNING("unlock resource");
501 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
504 return MM_ERROR_NONE;
508 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
510 int ret = MM_ERROR_NONE;
511 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
512 _MMCamcorderSubContext *sc = NULL;
516 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
517 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
518 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
520 MMCAM_LOG_INFO("start");
522 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
523 MMCAM_LOG_WARNING("pipeline is not existed.");
524 return MM_ERROR_NONE;
527 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
529 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
530 if (ret != MM_ERROR_NONE) {
531 MMCAM_LOG_ERROR("Failed to change encode main pipeline [0x%x]", ret);
535 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
537 /* remove audio pipeline first */
538 ret = _mmcamcorder_remove_audio_pipeline(handle);
539 if (ret != MM_ERROR_NONE) {
540 MMCAM_LOG_ERROR("Fail to remove audio pipeline");
544 ret = _mmcamcorder_remove_encode_pipeline(handle);
545 if (ret != MM_ERROR_NONE) {
546 MMCAM_LOG_ERROR("Fail to remove encoder pipeline");
550 /* Remove remained message */
552 GstMessage *gst_msg = NULL;
553 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
554 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
555 gst_message_unref(gst_msg);
557 gst_object_unref(bus);
560 MMCAM_LOG_INFO("done");
566 int _mmcamcorder_video_command(MMHandleType handle, int command)
571 int gop_interval = 0;
572 int ret = MM_ERROR_NONE;
573 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
574 char *err_name = NULL;
575 char *target_filename = NULL;
576 GstCameraControl *CameraControl = NULL;
579 GstElement *pipeline = NULL;
581 _MMCamcorderVideoInfo *info = NULL;
582 _MMCamcorderSubContext *sc = NULL;
583 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
585 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
587 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
588 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
589 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
590 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
592 info = sc->info_video;
594 MMCAM_LOG_INFO("Command(%d)", command);
596 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
599 case _MMCamcorder_CMD_RECORD:
601 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
605 gboolean storage_validity = FALSE;
608 int root_directory_length = 0;
611 MMCAM_LOG_INFO("Record Start - dual stream %d", info->support_dual_stream);
613 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
614 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
616 /* prepare resource manager for H/W encoder */
617 if (hcamcorder->video_encoder_resource == NULL) {
618 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
619 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
620 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
621 &hcamcorder->video_encoder_resource);
622 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
623 MMCAM_LOG_ERROR("could not prepare for encoder resource");
624 ret = MM_ERROR_RESOURCE_INTERNAL;
625 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
626 goto _ERR_CAMCORDER_VIDEO_COMMAND;
629 MMCAM_LOG_INFO("encoder already acquired");
632 /* acquire resources */
633 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
634 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
635 MMCAM_LOG_ERROR("could not acquire resources");
636 ret = MM_ERROR_RESOURCE_INTERNAL;
637 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
638 goto _ERR_CAMCORDER_VIDEO_COMMAND;
641 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
642 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
644 /* init record_dual_stream */
645 info->record_dual_stream = FALSE;
647 ret = mm_camcorder_get_attributes(handle, &err_name,
648 MMCAM_CAMERA_FPS, &fps,
649 MMCAM_CAMERA_WIDTH, &(info->preview_width),
650 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
651 MMCAM_VIDEO_WIDTH, &(info->video_width),
652 MMCAM_VIDEO_HEIGHT, &(info->video_height),
653 MMCAM_FILE_FORMAT, &fileformat,
654 MMCAM_TARGET_FILENAME, &target_filename, &size,
655 MMCAM_TARGET_MAX_SIZE, &imax_size,
656 MMCAM_TARGET_TIME_LIMIT, &imax_time,
657 MMCAM_FILE_FORMAT, &(info->fileformat),
658 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
659 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
661 if (ret != MM_ERROR_NONE) {
662 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, ret);
664 goto _ERR_CAMCORDER_VIDEO_COMMAND;
667 if (!target_filename && !hcamcorder->mstream_cb) {
668 MMCAM_LOG_ERROR("filename is not set and muxed stream cb is NULL");
669 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
670 goto _ERR_CAMCORDER_VIDEO_COMMAND;
675 info->max_size = 0; /* do not check */
677 info->max_size = ((guint64)imax_size) << 10; /* to byte */
681 info->max_time = 0; /* do not check */
683 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
685 ret = _mmcamcorder_get_storage_validity(hcamcorder, target_filename,
686 _MMCAMCORDER_VIDEO_MINIMUM_SPACE, &storage_validity);
687 if (ret != MM_ERROR_NONE) {
688 MMCAM_LOG_ERROR("storage validation failed[0x%x]:%d", ret, storage_validity);
692 _mmcamcorder_adjust_recording_max_size(target_filename, &info->max_size);
694 g_mutex_lock(&hcamcorder->task_thread_lock);
695 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
696 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
697 /* Play record start sound */
698 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
700 g_mutex_unlock(&hcamcorder->task_thread_lock);
702 MMCAM_LOG_WARNING("video size [%dx%d]", info->video_width, info->video_height);
704 if (info->video_width == 0 || info->video_height == 0) {
705 MMCAM_LOG_WARNING("video size is invalid [%dx%d] use preview size [%dx%d]",
706 info->video_width, info->video_height, info->preview_width, info->preview_height);
707 info->video_width = info->preview_width;
708 info->video_height = info->preview_height;
711 if (info->support_dual_stream) {
712 MMCAM_LOG_WARNING("DUAL STREAM MODE");
714 info->record_dual_stream = TRUE;
716 /* No need to restart preview */
717 info->restart_preview = FALSE;
719 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
720 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
721 } else if (_mmcamcorder_is_encoded_preview_pixel_format(sc->info_image->preview_format) &&
722 info->preview_width == info->video_width &&
723 info->preview_height == info->video_height) {
724 MMCAM_LOG_INFO("Encoded[%d] preview mode and same resolution", sc->info_image->preview_format);
725 /* No need to restart preview */
726 info->restart_preview = FALSE;
727 } else if (info->use_videoscale &&
728 info->preview_width >= info->video_width &&
729 info->preview_height >= info->video_height) {
730 info->restart_preview = FALSE;
732 info->restart_preview = TRUE;
733 /* reset use_videoscale */
734 info->use_videoscale = FALSE;
737 /* set recording hint */
738 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
740 if (info->restart_preview) {
741 /* stop preview and set new size */
742 MMCAM_LOG_INFO("restart preview");
744 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
745 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
746 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
748 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
750 /* check decoder recreation */
751 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
752 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
753 ret = MM_ERROR_CAMCORDER_INTERNAL;
754 goto _ERR_CAMCORDER_VIDEO_COMMAND;
757 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
758 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
759 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
761 if (ret != MM_ERROR_NONE)
762 goto _ERR_CAMCORDER_VIDEO_COMMAND;
764 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
765 ret = MM_ERROR_CAMCORDER_INTERNAL;
766 goto _ERR_CAMCORDER_VIDEO_COMMAND;
769 /* Start preview again with new setting */
770 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
771 if (ret != MM_ERROR_NONE)
772 goto _ERR_CAMCORDER_VIDEO_COMMAND;
774 if (motion_rate < 1.0) {
775 MMCAM_LOG_WARNING("wait for stabilization of frame");
779 MMCAM_LOG_INFO("no need to restart preview");
782 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
783 CONFIGURE_CATEGORY_MAIN_RECORD,
787 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
788 CONFIGURE_CATEGORY_MAIN_RECORD,
789 "PassFirstVideoFrame",
790 &(sc->pass_first_vframe));
792 MMCAM_LOG_INFO("Drop video frame count[%d], Pass first video frame count[%d]",
793 sc->drop_vframe, sc->pass_first_vframe);
795 info->record_drop_count = (guint)motion_rate;
796 info->record_motion_rate = motion_rate;
797 if (sc->is_modified_rate)
798 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
800 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
802 MMCAM_LOG_WARNING("recording fps %d, motion rate %f, timestamp_ratio %f",
803 fps, info->record_motion_rate, info->record_timestamp_ratio);
805 /* set push buffer flag */
806 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
807 info->base_video_ts = 0;
809 /* connect video stream cb signal if it supports dual stream. */
810 if (info->record_dual_stream) {
811 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
812 goto _ERR_CAMCORDER_VIDEO_COMMAND;
815 /* start video stream */
816 if (info->record_dual_stream) {
817 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
819 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
821 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
822 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
824 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
826 MMCAM_LOG_ERROR("could not get camera control");
830 /* check pre-created encode pipeline */
831 g_mutex_lock(&hcamcorder->task_thread_lock);
832 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
833 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
834 /* create encoding pipeline */
835 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
836 if (ret != MM_ERROR_NONE) {
837 g_mutex_unlock(&hcamcorder->task_thread_lock);
838 goto _ERR_CAMCORDER_VIDEO_COMMAND;
841 g_mutex_unlock(&hcamcorder->task_thread_lock);
843 /* check recording start sound */
844 _mmcamcorder_sound_solo_play_wait(handle);
846 /**< To fix video recording hanging
847 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
848 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
849 basetime wouldn't change if you set (GstClockTime)0.
850 3. Move set start time position below PAUSED of pipeline.
853 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
854 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
857 info->video_frame_count = 0;
858 info->is_first_frame = TRUE;
859 info->audio_frame_count = 0;
861 sc->ferror_send = FALSE;
862 sc->ferror_count = 0;
863 hcamcorder->error_occurs = FALSE;
864 sc->bget_eos = FALSE;
865 sc->muxed_stream_offset = 0;
867 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
868 if (ret != MM_ERROR_NONE) {
869 /* stop video stream */
870 if (info->record_dual_stream) {
871 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
873 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
875 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
876 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
878 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
880 MMCAM_LOG_ERROR("failed to get camera control");
884 /* Remove recorder pipeline and recording file which size maybe zero */
885 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
886 if (info->filename) {
887 MMCAM_LOG_INFO("file delete(%s)", info->filename);
888 unlink(info->filename);
890 goto _ERR_CAMCORDER_VIDEO_COMMAND;
893 /*set the GOP so that video record will get a new key frame*/
894 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
895 if (mm_camcorder_get_attributes(handle, NULL,
896 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
897 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
899 MMCAM_LOG_ERROR("get gop interval failed");
903 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
904 if (mm_camcorder_get_attributes(handle, NULL,
905 MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval, NULL) == MM_ERROR_NONE)
906 _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
908 MMCAM_LOG_ERROR("get gop interval failed");
911 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
913 MMCAM_LOG_INFO("Object property settings done");
917 case _MMCamcorder_CMD_PAUSE:
919 if (info->b_committing) {
920 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
921 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
924 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
925 if (sc->audio_disable) {
926 /* check only video frame */
927 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
929 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
930 MMCAM_LOG_ERROR("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
931 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
933 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
936 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
938 /* check both of video and audio frame */
939 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
941 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
942 MMCAM_LOG_ERROR("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
943 info->video_frame_count, info->audio_frame_count);
944 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
946 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
947 count, info->video_frame_count, info->audio_frame_count);
950 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
954 /* block encodebin */
955 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
958 case _MMCamcorder_CMD_CANCEL:
960 if (info->b_committing) {
961 MMCAM_LOG_WARNING("now on committing previous file!!(command : %d)", command);
962 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
965 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
967 if (hcamcorder->capture_in_recording == FALSE) {
969 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
970 MMCAM_LOG_ERROR("Failed to Wait capture data");
971 hcamcorder->capture_in_recording = FALSE;
974 MMCAM_LOG_WARNING("Waiting for capture data - retrial [%d]", count);
977 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
980 /* block push buffer */
981 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
983 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
984 if (ret != MM_ERROR_NONE)
985 goto _ERR_CAMCORDER_VIDEO_COMMAND;
987 /* set recording hint */
988 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
990 /* stop video stream */
991 if (info->record_dual_stream) {
992 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
994 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
996 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
997 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
999 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1001 MMCAM_LOG_ERROR("failed to get camera control");
1005 if (info->restart_preview) {
1006 /* restart preview */
1007 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1008 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1009 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1011 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
1013 /* check decoder recreation */
1014 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1015 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1016 ret = MM_ERROR_CAMCORDER_INTERNAL;
1019 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1020 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1021 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1023 if (ret != MM_ERROR_NONE)
1024 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1026 /* reset restart_preview for inset window layout */
1027 info->restart_preview = FALSE;
1029 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1030 ret = MM_ERROR_CAMCORDER_INTERNAL;
1031 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1034 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
1035 if (ret != MM_ERROR_NONE)
1036 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1039 /* remove target file */
1040 if (info->filename) {
1041 MMCAM_LOG_INFO("file delete(%s)", info->filename);
1042 unlink(info->filename);
1045 sc->isMaxsizePausing = FALSE;
1046 sc->isMaxtimePausing = FALSE;
1048 sc->display_interval = 0;
1049 sc->previous_slot_time = 0;
1050 info->video_frame_count = 0;
1051 info->audio_frame_count = 0;
1053 hcamcorder->capture_in_recording = FALSE;
1056 case _MMCamcorder_CMD_COMMIT:
1060 if (info->b_committing) {
1061 MMCAM_LOG_ERROR("now on committing previous file!!(command : %d)", command);
1062 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1064 MMCAM_LOG_INFO("_MMCamcorder_CMD_COMMIT : start");
1065 info->b_committing = TRUE;
1066 sc->bget_eos = FALSE;
1069 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1070 if (sc->audio_disable) {
1071 /* check only video frame */
1072 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1073 hcamcorder->capture_in_recording == FALSE) {
1075 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1076 MMCAM_LOG_ERROR("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1077 info->video_frame_count, hcamcorder->capture_in_recording);
1079 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1080 MMCAM_LOG_WARNING("video frames are enough. keep going...");
1082 info->b_committing = FALSE;
1083 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1086 MMCAM_LOG_WARNING("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1087 count, info->video_frame_count, hcamcorder->capture_in_recording);
1090 /* check both of video and audio frame */
1091 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1092 info->audio_frame_count &&
1093 hcamcorder->capture_in_recording == FALSE) {
1095 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1096 MMCAM_LOG_ERROR("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1097 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1099 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1100 MMCAM_LOG_WARNING("video/audio frames are enough. keep going...");
1102 info->b_committing = FALSE;
1103 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1106 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1108 MMCAM_LOG_WARNING("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1109 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1113 if (hcamcorder->capture_in_recording) {
1114 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1115 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1116 MMCAM_LOG_WARNING("timeout");
1118 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1122 /* block push buffer */
1123 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1124 MMCAM_LOG_INFO("block push buffer to appsrc");
1126 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1127 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1128 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1129 ret = MM_ERROR_OUT_OF_STORAGE;
1130 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1133 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1134 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1135 MMCAM_LOG_WARNING("VIDEO: send eos to appsrc done");
1137 MMCAM_LOG_ERROR("VIDEO: send EOS failed");
1138 info->b_committing = FALSE;
1139 ret = MM_ERROR_CAMCORDER_INTERNAL;
1140 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1143 MMCAM_LOG_ERROR("No video stream source");
1144 info->b_committing = FALSE;
1145 ret = MM_ERROR_CAMCORDER_INTERNAL;
1146 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1149 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1150 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1151 MMCAM_LOG_WARNING("AUDIO: send eos to audiosrc done");
1153 MMCAM_LOG_ERROR("AUDIO: send EOS failed");
1154 info->b_committing = FALSE;
1155 ret = MM_ERROR_CAMCORDER_INTERNAL;
1156 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1159 MMCAM_LOG_INFO("No audio stream");
1163 sc->display_interval = 0;
1164 sc->previous_slot_time = 0;
1167 MMCAM_LOG_INFO("Start to wait EOS");
1168 ret = _mmcamcorder_get_eos_message(handle);
1169 if (ret != MM_ERROR_NONE) {
1170 info->b_committing = FALSE;
1171 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1175 hcamcorder->capture_in_recording = FALSE;
1179 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1180 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1183 return MM_ERROR_NONE;
1185 _ERR_CAMCORDER_VIDEO_COMMAND:
1186 if (command == _MMCamcorder_CMD_RECORD)
1187 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1193 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1195 int ret = MM_ERROR_NONE;
1197 guint64 file_size = 0;
1199 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1200 _MMCamcorderSubContext *sc = NULL;
1201 _MMCamcorderVideoInfo *info = NULL;
1202 _MMCamcorderMsgItem msg;
1203 MMCamRecordingReport *report = NULL;
1205 mmf_return_val_if_fail(hcamcorder, FALSE);
1207 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1208 mmf_return_val_if_fail(sc, FALSE);
1209 mmf_return_val_if_fail(sc->info_video, FALSE);
1211 info = sc->info_video;
1213 MMCAM_LOG_ERROR("");
1215 /* Play record stop sound */
1216 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1218 /* remove blocking part */
1219 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1221 mm_camcorder_get_attributes(handle, NULL,
1222 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1225 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1226 if (ret != MM_ERROR_NONE)
1227 MMCAM_LOG_WARNING("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1229 /* set recording hint */
1230 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1232 /* stop video stream */
1233 if (info->record_dual_stream) {
1234 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1236 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1238 MMCAM_LOG_INFO("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1239 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1241 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1243 MMCAM_LOG_ERROR("failed to get camera control");
1247 if (enabletag && !(sc->ferror_send)) {
1248 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1249 MMCAM_LOG_INFO("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1252 /* Check file size */
1253 if (info->max_size > 0) {
1254 _mmcamcorder_get_file_size(info->filename, &file_size);
1255 MMCAM_LOG_INFO("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1256 info->max_size, file_size);
1258 if (file_size > info->max_size) {
1259 _MMCamcorderMsgItem message;
1260 MMCAM_LOG_ERROR("File size is greater than max size !!");
1261 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1262 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1263 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1267 if (info->restart_preview) {
1269 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1270 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1271 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1273 MMCAM_LOG_INFO("Set state of pipeline as READY");
1274 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1276 /* check decoder recreation */
1277 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1278 MMCAM_LOG_ERROR("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1279 ret = MM_ERROR_CAMCORDER_INTERNAL;
1283 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1284 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1285 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1287 if (ret != MM_ERROR_NONE) {
1288 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1289 msg.param.code = ret;
1290 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1291 MMCAM_LOG_ERROR("Failed to set state READY[%x]", ret);
1294 /* reset restart_preview for inset window layout */
1295 info->restart_preview = FALSE;
1297 /* recover preview size */
1298 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1299 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1300 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1301 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1302 MMCAM_LOG_ERROR("Failed to set camera resolution %dx%d",
1303 info->preview_width, info->preview_height);
1306 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1307 /* Do not return when error is occurred.
1308 Recording file was created successfully, but starting pipeline failed */
1309 if (ret != MM_ERROR_NONE) {
1310 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1311 msg.param.code = ret;
1312 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1313 MMCAM_LOG_ERROR("Failed to set state PLAYING[%x]", ret);
1316 MMCAM_LOG_INFO("No need to restart preview");
1319 /* Send recording report to application */
1320 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1321 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1322 report->recording_filename = g_strdup(info->filename);
1323 msg.param.data = report;
1325 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1328 sc->pipeline_time = 0;
1330 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1331 sc->isMaxtimePausing = FALSE;
1332 hcamcorder->error_occurs = FALSE;
1334 info->video_frame_count = 0;
1335 info->audio_frame_count = 0;
1337 info->b_committing = FALSE;
1339 /* check recording stop sound */
1340 _mmcamcorder_sound_solo_play_wait(handle);
1342 MMCAM_LOG_ERROR("_MMCamcorder_CMD_COMMIT : end");
1348 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1350 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1351 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1353 _MMCamcorderSubContext *sc = NULL;
1354 _MMCamcorderVideoInfo *videoinfo = NULL;
1355 _MMCamcorderMsgItem msg;
1356 guint64 buffer_size = 0;
1357 guint64 trailer_size = 0;
1358 guint64 max_size = 0;
1360 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1361 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1362 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1364 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1365 videoinfo = sc->info_video;
1367 /* get buffer size */
1368 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1369 MMCAM_LOG_WARNING("map failed : buffer %p", buffer);
1370 return GST_PAD_PROBE_OK;
1373 buffer_size = mapinfo.size;
1374 gst_buffer_unmap(buffer, &mapinfo);
1376 g_mutex_lock(&videoinfo->size_check_lock);
1378 if (videoinfo->audio_frame_count == 0) {
1379 videoinfo->filesize += buffer_size;
1380 videoinfo->audio_frame_count++;
1381 g_mutex_unlock(&videoinfo->size_check_lock);
1382 return GST_PAD_PROBE_OK;
1385 if (sc->ferror_send || sc->isMaxsizePausing) {
1386 MMCAM_LOG_WARNING("Recording is paused, drop frames");
1387 g_mutex_unlock(&videoinfo->size_check_lock);
1388 return GST_PAD_PROBE_DROP;
1391 /* get trailer size */
1392 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1393 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1397 /* check max size of recorded file */
1398 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1399 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1400 GstState pipeline_state = GST_STATE_VOID_PENDING;
1401 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1403 MMCAM_LOG_WARNING("Max size[%"G_GUINT64_FORMAT"], current size[%"G_GUINT64_FORMAT"],"\
1404 " buffer size[%"G_GUINT64_FORMAT"], trailer size[%"G_GUINT64_FORMAT"]",
1405 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1407 if (!sc->isMaxsizePausing) {
1408 sc->isMaxsizePausing = TRUE;
1409 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1410 if (pipeline_state == GST_STATE_PLAYING)
1411 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1413 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1414 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1417 g_mutex_unlock(&videoinfo->size_check_lock);
1422 videoinfo->filesize += buffer_size;
1423 videoinfo->audio_frame_count++;
1425 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1426 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1428 g_mutex_unlock(&videoinfo->size_check_lock);
1430 return GST_PAD_PROBE_OK;
1434 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1439 guint64 free_space = 0;
1440 guint64 buffer_size = 0;
1441 guint64 trailer_size = 0;
1442 guint64 queued_buffer = 0;
1443 guint64 max_size = 0;
1444 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1446 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1448 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1449 _MMCamcorderMsgItem msg;
1450 _MMCamcorderSubContext *sc = NULL;
1451 _MMCamcorderVideoInfo *videoinfo = NULL;
1453 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1454 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1456 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1457 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1458 videoinfo = sc->info_video;
1460 if (sc->ferror_send) {
1461 MMCAM_LOG_WARNING("file write error, drop frames");
1462 return GST_PAD_PROBE_DROP;
1465 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1466 MMCAM_LOG_WARNING("map failed : buffer[%p]", buffer);
1467 return GST_PAD_PROBE_OK;
1471 buffer_size = mapinfo.size;
1472 gst_buffer_unmap(buffer, &mapinfo);
1474 videoinfo->video_frame_count++;
1475 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1476 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1477 g_mutex_lock(&videoinfo->size_check_lock);
1478 videoinfo->filesize += buffer_size;
1479 g_mutex_unlock(&videoinfo->size_check_lock);
1480 return GST_PAD_PROBE_OK;
1483 /* get trailer size */
1484 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1485 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1489 /* check free space */
1490 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1492 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1493 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1494 sc->ferror_send = TRUE;
1496 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1497 msg.param.code = MM_ERROR_FILE_READ;
1499 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1504 return GST_PAD_PROBE_DROP; /* skip this buffer */
1507 if (free_space == 0) {
1508 /* check storage state */
1509 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1511 MMCAM_LOG_WARNING("storage state %d", storage_state);
1513 if (storage_state == STORAGE_STATE_REMOVED ||
1514 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1515 MMCAM_LOG_ERROR("storage was removed!");
1517 _MMCAMCORDER_LOCK(hcamcorder);
1519 if (sc->ferror_send == FALSE) {
1520 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1522 sc->ferror_send = TRUE;
1524 _MMCAMCORDER_UNLOCK(hcamcorder);
1526 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1527 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1529 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1531 _MMCAMCORDER_UNLOCK(hcamcorder);
1532 MMCAM_LOG_WARNING("error was already sent");
1535 return GST_PAD_PROBE_DROP;
1539 /* get queued buffer size */
1540 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1541 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1543 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1544 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1546 queued_buffer = aq_size + vq_size;
1548 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1549 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1550 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1551 free_space, trailer_size, buffer_size, queued_buffer);
1553 if (!sc->isMaxsizePausing) {
1554 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1555 sc->isMaxsizePausing = TRUE;
1557 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1558 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1561 return GST_PAD_PROBE_DROP;
1564 g_mutex_lock(&videoinfo->size_check_lock);
1566 /* check max size of recorded file */
1567 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1568 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1569 GstState pipeline_state = GST_STATE_VOID_PENDING;
1570 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1572 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1573 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1574 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1576 if (!sc->isMaxsizePausing) {
1577 sc->isMaxsizePausing = TRUE;
1578 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1579 if (pipeline_state == GST_STATE_PLAYING)
1580 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1582 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1583 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1586 g_mutex_unlock(&videoinfo->size_check_lock);
1588 return GST_PAD_PROBE_DROP;
1591 videoinfo->filesize += (guint64)buffer_size;
1593 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1594 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1596 g_mutex_unlock(&videoinfo->size_check_lock);
1598 return GST_PAD_PROBE_OK;
1602 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1604 guint64 trailer_size = 0;
1605 guint64 rec_pipe_time = 0;
1606 unsigned int remained_time = 0;
1608 GstClockTime b_time;
1610 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1611 _MMCamcorderMsgItem msg;
1612 _MMCamcorderSubContext *sc = NULL;
1613 _MMCamcorderVideoInfo *videoinfo = NULL;
1615 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1617 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1618 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1620 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1621 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1622 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1624 videoinfo = sc->info_video;
1626 b_time = GST_BUFFER_PTS(buffer);
1628 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1630 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1631 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1635 /* check max time */
1636 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1637 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1638 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1640 if (!sc->isMaxtimePausing) {
1641 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1643 sc->isMaxtimePausing = TRUE;
1645 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1646 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1647 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1648 msg.param.recording_status.remained_time = 0;
1649 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1651 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1652 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1655 return GST_PAD_PROBE_DROP;
1658 /* calculate remained time can be recorded */
1659 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1660 remained_time = videoinfo->max_time - rec_pipe_time;
1661 } else if (videoinfo->max_size > 0) {
1662 long double max_size = (long double)videoinfo->max_size;
1663 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1665 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1668 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1669 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1670 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1671 msg.param.recording_status.remained_time = remained_time;
1672 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1674 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1675 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1677 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1678 record_motion_rate, videoinfo->record_drop_count);
1680 /* drop some frame if fast motion */
1681 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1682 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1683 MMCAM_LOG_VERBOSE("drop frame");
1684 return GST_PAD_PROBE_DROP;
1687 videoinfo->record_drop_count = 1;
1688 MMCAM_LOG_VERBOSE("pass frame");
1691 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1692 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1695 return GST_PAD_PROBE_OK;
1699 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1701 _MMCamcorderMsgItem msg;
1702 guint64 trailer_size = 0;
1703 guint64 rec_pipe_time = 0;
1704 _MMCamcorderSubContext *sc = NULL;
1705 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1706 _MMCamcorderVideoInfo *videoinfo = NULL;
1707 unsigned int remained_time = 0;
1708 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1710 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1711 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1712 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1714 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1715 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1716 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1718 videoinfo = sc->info_video;
1720 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1721 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1722 return GST_PAD_PROBE_OK;
1725 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1727 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1728 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1732 /* calculate remained time can be recorded */
1733 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1734 remained_time = videoinfo->max_time - rec_pipe_time;
1735 } else if (videoinfo->max_size > 0) {
1736 long double max_size = (long double)videoinfo->max_size;
1737 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1739 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1742 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1743 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1744 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1746 if (!sc->isMaxtimePausing) {
1747 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1749 sc->isMaxtimePausing = TRUE;
1751 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1752 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1753 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1754 msg.param.recording_status.remained_time = 0;
1755 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1757 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1758 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1761 return GST_PAD_PROBE_DROP;
1764 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1765 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1766 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1767 msg.param.recording_status.remained_time = remained_time;
1768 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1770 MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1771 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1773 return GST_PAD_PROBE_OK;
1777 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1779 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1780 double volume = 0.0;
1783 int err = MM_ERROR_UNKNOWN;
1784 char *err_name = NULL;
1785 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1788 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1789 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1791 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1792 MMCAM_AUDIO_VOLUME, &volume,
1793 MMCAM_AUDIO_FORMAT, &format,
1794 MMCAM_AUDIO_CHANNEL, &channel,
1796 if (err != MM_ERROR_NONE) {
1797 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1798 SAFE_FREE(err_name);
1799 return GST_PAD_PROBE_OK;
1802 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1804 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE)) {
1805 MMCAM_LOG_WARNING("map failed : buffer[%p]", buffer);
1806 return GST_PAD_PROBE_OK;
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) {
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);