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 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1466 buffer_size = mapinfo.size;
1467 gst_buffer_unmap(buffer, &mapinfo);
1469 videoinfo->video_frame_count++;
1470 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1471 MMCAM_LOG_DEBUG("Pass minimum frame[%"G_GUINT64_FORMAT"]", videoinfo->video_frame_count);
1472 g_mutex_lock(&videoinfo->size_check_lock);
1473 videoinfo->filesize += buffer_size;
1474 g_mutex_unlock(&videoinfo->size_check_lock);
1475 return GST_PAD_PROBE_OK;
1478 /* get trailer size */
1479 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1480 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1484 /* check free space */
1485 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1487 MMCAM_LOG_ERROR("Error occurred. [%d]", ret);
1488 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1489 sc->ferror_send = TRUE;
1491 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1492 msg.param.code = MM_ERROR_FILE_READ;
1494 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1499 return GST_PAD_PROBE_DROP; /* skip this buffer */
1502 if (free_space == 0) {
1503 /* check storage state */
1504 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1506 MMCAM_LOG_WARNING("storage state %d", storage_state);
1508 if (storage_state == STORAGE_STATE_REMOVED ||
1509 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1510 MMCAM_LOG_ERROR("storage was removed!");
1512 _MMCAMCORDER_LOCK(hcamcorder);
1514 if (sc->ferror_send == FALSE) {
1515 MMCAM_LOG_ERROR("OUT_OF_STORAGE error");
1517 sc->ferror_send = TRUE;
1519 _MMCAMCORDER_UNLOCK(hcamcorder);
1521 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1522 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1524 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1526 _MMCAMCORDER_UNLOCK(hcamcorder);
1527 MMCAM_LOG_WARNING("error was already sent");
1530 return GST_PAD_PROBE_DROP;
1534 /* get queued buffer size */
1535 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1536 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1538 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1539 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1541 queued_buffer = aq_size + vq_size;
1543 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1544 MMCAM_LOG_WARNING("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1545 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1546 free_space, trailer_size, buffer_size, queued_buffer);
1548 if (!sc->isMaxsizePausing) {
1549 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1550 sc->isMaxsizePausing = TRUE;
1552 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1553 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1556 return GST_PAD_PROBE_DROP;
1559 g_mutex_lock(&videoinfo->size_check_lock);
1561 /* check max size of recorded file */
1562 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1563 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1564 GstState pipeline_state = GST_STATE_VOID_PENDING;
1565 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1567 MMCAM_LOG_WARNING("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1568 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1569 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1571 if (!sc->isMaxsizePausing) {
1572 sc->isMaxsizePausing = TRUE;
1573 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1574 if (pipeline_state == GST_STATE_PLAYING)
1575 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1577 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1578 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1581 g_mutex_unlock(&videoinfo->size_check_lock);
1583 return GST_PAD_PROBE_DROP;
1586 videoinfo->filesize += (guint64)buffer_size;
1588 MMCAM_LOG_DEBUG("video rec[%"GST_TIME_FORMAT"], size[%"G_GUINT64_FORMAT"(trailer:%"G_GUINT64_FORMAT")]",
1589 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size, trailer_size);
1591 g_mutex_unlock(&videoinfo->size_check_lock);
1593 return GST_PAD_PROBE_OK;
1597 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1599 guint64 trailer_size = 0;
1600 guint64 rec_pipe_time = 0;
1601 unsigned int remained_time = 0;
1603 GstClockTime b_time;
1605 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1606 _MMCamcorderMsgItem msg;
1607 _MMCamcorderSubContext *sc = NULL;
1608 _MMCamcorderVideoInfo *videoinfo = NULL;
1610 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1612 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1613 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1615 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1616 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1617 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1619 videoinfo = sc->info_video;
1621 b_time = GST_BUFFER_PTS(buffer);
1623 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1625 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1626 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1630 /* check max time */
1631 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1632 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1633 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1635 if (!sc->isMaxtimePausing) {
1636 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1638 sc->isMaxtimePausing = TRUE;
1640 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1641 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1642 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1643 msg.param.recording_status.remained_time = 0;
1644 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1646 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1647 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1650 return GST_PAD_PROBE_DROP;
1653 /* calculate remained time can be recorded */
1654 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1655 remained_time = videoinfo->max_time - rec_pipe_time;
1656 } else if (videoinfo->max_size > 0) {
1657 long double max_size = (long double)videoinfo->max_size;
1658 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1660 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1663 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1664 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1665 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1666 msg.param.recording_status.remained_time = remained_time;
1667 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1669 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1670 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1672 MMCAM_LOG_VERBOSE("record_motion_rate[%u], videoinfo->record_drop_count[%u]",
1673 record_motion_rate, videoinfo->record_drop_count);
1675 /* drop some frame if fast motion */
1676 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1677 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1678 MMCAM_LOG_VERBOSE("drop frame");
1679 return GST_PAD_PROBE_DROP;
1682 videoinfo->record_drop_count = 1;
1683 MMCAM_LOG_VERBOSE("pass frame");
1686 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1687 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1690 return GST_PAD_PROBE_OK;
1694 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1696 _MMCamcorderMsgItem msg;
1697 guint64 trailer_size = 0;
1698 guint64 rec_pipe_time = 0;
1699 _MMCamcorderSubContext *sc = NULL;
1700 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1701 _MMCamcorderVideoInfo *videoinfo = NULL;
1702 unsigned int remained_time = 0;
1703 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1705 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1706 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1707 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1709 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1710 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1711 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1713 videoinfo = sc->info_video;
1715 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1716 MMCAM_LOG_ERROR("Buffer timestamp is invalid, check it");
1717 return GST_PAD_PROBE_OK;
1720 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1722 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1723 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1727 /* calculate remained time can be recorded */
1728 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1729 remained_time = videoinfo->max_time - rec_pipe_time;
1730 } else if (videoinfo->max_size > 0) {
1731 long double max_size = (long double)videoinfo->max_size;
1732 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1734 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1737 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1738 MMCAM_LOG_WARNING("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1739 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1741 if (!sc->isMaxtimePausing) {
1742 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1744 sc->isMaxtimePausing = TRUE;
1746 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1747 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1748 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1749 msg.param.recording_status.remained_time = 0;
1750 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1752 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1753 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1756 return GST_PAD_PROBE_DROP;
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 = remained_time;
1763 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1765 MMCAM_LOG_DEBUG("audio data probe[%" GST_TIME_FORMAT "], size[%"G_GUINT64_FORMAT"]",
1766 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), videoinfo->filesize + trailer_size);
1768 return GST_PAD_PROBE_OK;
1772 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1774 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1775 double volume = 0.0;
1778 int err = MM_ERROR_UNKNOWN;
1779 char *err_name = NULL;
1780 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1783 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1784 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1786 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1787 MMCAM_AUDIO_VOLUME, &volume,
1788 MMCAM_AUDIO_FORMAT, &format,
1789 MMCAM_AUDIO_CHANNEL, &channel,
1791 if (err != MM_ERROR_NONE) {
1792 MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
1793 SAFE_FREE(err_name);
1797 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1799 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1801 /* Set audio stream NULL */
1803 memset(mapinfo.data, 0, mapinfo.size);
1805 MMCAM_LOG_DEBUG("audio stream[%"GST_TIME_FORMAT"] - cb[%p], fmt[%d], ch[%d], size[%"G_GSIZE_FORMAT"]",
1806 GST_TIME_ARGS(GST_BUFFER_PTS(buffer)), hcamcorder->astream_cb, format, channel, mapinfo.size);
1808 /* CALL audio stream callback */
1809 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1810 MMCamcorderAudioStreamDataType stream;
1812 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1813 MMCAM_LOG_WARNING("Not ready for stream callback");
1814 gst_buffer_unmap(buffer, &mapinfo);
1815 return GST_PAD_PROBE_OK;
1818 stream.data = (void *)mapinfo.data;
1819 stream.format = format;
1820 stream.channel = channel;
1821 stream.length = mapinfo.size;
1822 stream.timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer)));
1824 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1826 if (hcamcorder->astream_cb)
1827 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1829 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1832 gst_buffer_unmap(buffer, &mapinfo);
1834 return GST_PAD_PROBE_OK;
1838 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1840 gboolean bret = FALSE;
1842 switch (fileformat) {
1843 case MM_FILE_FORMAT_3GP:
1844 case MM_FILE_FORMAT_MP4:
1845 bret = __mmcamcorder_add_metadata_mp4(handle);
1848 MMCAM_LOG_WARNING("Unsupported fileformat to insert location info (%d)", fileformat);
1856 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1860 guint64 udta_size = 0;
1861 gint64 current_pos = 0;
1862 gint64 moov_pos = 0;
1863 gint64 udta_pos = 0;
1864 gdouble longitude = 0;
1865 gdouble latitude = 0;
1866 gdouble altitude = 0;
1868 int orientation = 0;
1870 char *err_name = NULL;
1871 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1872 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1873 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1875 _MMCamcorderVideoInfo *info = NULL;
1876 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1877 _MMCamcorderSubContext *sc = NULL;
1879 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1880 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1882 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1883 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1887 info = sc->info_video;
1889 f = fopen64(info->filename, "rb+");
1891 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1892 MMCAM_LOG_ERROR("file open failed [%s]", err_msg);
1896 mm_camcorder_get_attributes(handle, &err_name,
1897 MMCAM_TAG_LATITUDE, &latitude,
1898 MMCAM_TAG_LONGITUDE, &longitude,
1899 MMCAM_TAG_ALTITUDE, &altitude,
1900 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1901 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1904 MMCAM_LOG_WARNING("Get tag attrs fail. (%s:%x)", err_name, err);
1905 SAFE_FREE(err_name);
1908 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1909 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1910 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1911 geo_info.longitude = longitude *10000;
1912 geo_info.latitude = latitude *10000;
1913 geo_info.altitude = altitude *10000;
1914 /* find udta container.
1915 if, there are udta container, write loci box after that
1916 else, make udta container and write loci box. */
1917 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1920 MMCAM_LOG_INFO("find udta container");
1923 if (fseek(f, -8L, SEEK_CUR) != 0)
1926 udta_pos = ftello(f);
1930 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1932 MMCAM_LOG_INFO("recorded file fread %zu", nread);
1934 udta_size = _mmcamcorder_get_container_size(buf);
1936 /* goto end of udta and write 'loci' box */
1937 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1941 if (!_mmcamcorder_write_loci(f, location_info)) {
1942 MMCAM_LOG_ERROR("failed to write loci");
1946 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1947 MMCAM_LOG_ERROR("failed to write geodata");
1952 current_pos = ftello(f);
1953 if (current_pos < 0)
1956 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1959 MMCAM_LOG_INFO("No udta container");
1960 if (fseek(f, 0, SEEK_END) != 0)
1963 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1964 MMCAM_LOG_ERROR("failed to write udta");
1969 /* find moov container.
1970 update moov container size. */
1971 if ((current_pos = ftello(f)) < 0)
1974 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1975 gint64 internal_pos = ftello(f);
1977 MMCAM_LOG_INFO("found moov container");
1978 if (fseek(f, -8L, SEEK_CUR) != 0)
1981 moov_pos = ftello(f);
1985 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
1988 /* add orientation info */
1989 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1990 MMCAM_LOG_ERROR("fseeko failed : errno %d", errno);
1994 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
1995 MMCAM_LOG_ERROR("failed to find [trak] tag");
1999 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
2000 MMCAM_LOG_ERROR("failed to find [tkhd] tag");
2004 MMCAM_LOG_INFO("found [tkhd] tag");
2006 /* seek to start position of composition matrix */
2007 if (fseek(f, OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
2008 /* update composition matrix for orientation */
2009 _mmcamcorder_update_composition_matrix(f, orientation);
2011 MMCAM_LOG_ERROR("fseek failed : errno %d", errno);
2015 MMCAM_LOG_ERROR("No 'moov' container");
2027 MMCAM_LOG_ERROR("ftell() returns negative value.");
2033 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2035 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2036 _MMCamcorderSubContext *sc = NULL;
2038 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2040 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2041 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2043 /* check video source element */
2044 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2045 MMCAM_LOG_WARNING("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2046 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2047 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2048 G_CALLBACK(__mmcamcorder_video_stream_cb),
2050 return MM_ERROR_NONE;
2052 MMCAM_LOG_ERROR("videosrc element is not created yet");
2053 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2058 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2060 int ret = MM_ERROR_NONE;
2062 char *temp_filename = NULL;
2064 _MMCamcorderVideoInfo *info = NULL;
2065 _MMCamcorderSubContext *sc = NULL;
2066 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2068 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2070 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2071 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2072 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2074 info = sc->info_video;
2076 MMCAM_LOG_WARNING("start");
2078 /* create encoding pipeline */
2079 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2080 if (ret != MM_ERROR_NONE)
2081 goto _ERR_PREPARE_RECORD;
2083 SAFE_G_FREE(info->filename);
2085 mm_camcorder_get_attributes(handle, NULL,
2086 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2088 if (temp_filename) {
2089 info->filename = g_strdup(temp_filename);
2090 if (!info->filename) {
2091 MMCAM_LOG_ERROR("strdup[src:%p] was failed", temp_filename);
2092 goto _ERR_PREPARE_RECORD;
2095 MMCAM_LOG_INFO("Record file name [%s]", info->filename);
2096 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2098 MMCAM_LOG_INFO("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2099 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2102 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2104 /* Adjust display FPS */
2105 sc->display_interval = 0;
2106 sc->previous_slot_time = 0;
2108 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2109 if (ret != MM_ERROR_NONE)
2110 goto _ERR_PREPARE_RECORD;
2112 MMCAM_LOG_WARNING("done");
2116 _ERR_PREPARE_RECORD:
2117 /* Remove recorder pipeline and recording file which size maybe zero */
2118 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2119 if (info && info->filename) {
2120 MMCAM_LOG_INFO("file delete(%s)", info->filename);
2121 unlink(info->filename);