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/video/cameracontrol.h>
26 #include <gst/app/gstappsrc.h>
27 #include "mm_camcorder_internal.h"
28 #include "mm_camcorder_videorec.h"
30 /*---------------------------------------------------------------------------------------
31 | GLOBAL VARIABLE DEFINITIONS for internal |
32 ---------------------------------------------------------------------------------------*/
33 #define _MMCAMCORDER_LOCATION_INFO /* for add gps information */
34 #define MAX_ERROR_MESSAGE_LEN 128
36 /*---------------------------------------------------------------------------------------
37 | LOCAL VARIABLE DEFINITIONS for internal |
38 ---------------------------------------------------------------------------------------*/
39 #define _MMCAMCORDER_MINIMUM_FRAME 5
40 #define _MMCAMCORDER_RETRIAL_COUNT 10
41 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* ms */
42 #define _OFFSET_COMPOSITION_MATRIX 40L
43 #define _GOP_GEN_INTERVAL 1000000000 /*nano seconds*/
44 #define _MMCAMCORDER_VIDEO_MINIMUM_SPACE (_MMCAMCORDER_MINIMUM_SPACE << 1) /* byte */
46 /*---------------------------------------------------------------------------------------
47 | LOCAL FUNCTION PROTOTYPES: |
48 ---------------------------------------------------------------------------------------*/
49 /* STATIC INTERNAL FUNCTION */
50 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
51 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
52 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
53 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
54 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
55 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
56 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat);
57 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
59 /*=======================================================================================
60 | FUNCTION DEFINITIONS |
61 =======================================================================================*/
62 /*---------------------------------------------------------------------------------------
63 | GLOBAL FUNCTION DEFINITIONS: |
64 ---------------------------------------------------------------------------------------*/
65 static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
67 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
68 _MMCamcorderSubContext *sc = NULL;
70 GstBuffer *buffer = gst_sample_get_buffer(sample);
71 mmf_return_val_if_fail(buffer, FALSE);
72 mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
73 mmf_return_val_if_fail(hcamcorder, FALSE);
75 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
76 mmf_return_val_if_fail(sc, FALSE);
79 _mmcam_dbg_log("ENTER - push_encoding_buffer %d, buffer %p, MALLOCDATA %p, size %d",
80 sc->info_video->push_encoding_buffer, buffer, GST_BUFFER_MALLOCDATA(buffer), GST_BUFFER_SIZE(buffer));
83 /* push buffer in appsrc to encode */
84 if (sc->info_video->push_encoding_buffer == PUSH_ENCODING_BUFFER_RUN &&
85 sc->info_video->record_dual_stream &&
86 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst) {
87 GstFlowReturn ret = 0;
88 GstClock *pipe_clock = NULL;
90 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst) {
91 if (sc->info_video->is_firstframe) {
92 sc->info_video->is_firstframe = FALSE;
93 pipe_clock = GST_ELEMENT_CLOCK(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst);
95 gst_object_ref(pipe_clock);
96 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer) - (gst_clock_get_time(pipe_clock) - GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst)->base_time);
97 gst_object_unref(pipe_clock);
101 if (sc->info_video->is_firstframe) {
102 sc->info_video->is_firstframe = FALSE;
103 sc->info_video->base_video_ts = GST_BUFFER_PTS(buffer);
107 GST_BUFFER_PTS(buffer) = GST_BUFFER_PTS(buffer) - sc->info_video->base_video_ts;
108 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
110 ret = gst_app_src_push_buffer((GstAppSrc *)sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, buffer);
111 if (ret != GST_FLOW_OK && ret != GST_FLOW_FLUSHING) {
112 _mmcam_dbg_err("gst_app_src_push_buffer failed [0x%x]", ret);
113 gst_buffer_unref(buffer);
117 /*_mmcam_dbg_log("push buffer result : 0x%x", ret);*/
119 _mmcam_dbg_warn("unref video buffer immediately - push encoding buffer %d",
120 sc->info_video->push_encoding_buffer);
122 gst_buffer_unref(buffer);
130 int _mmcamcorder_create_recorder_pipeline(MMHandleType handle)
133 int err = MM_ERROR_NONE;
134 const char* gst_element_rsink_name = NULL;
137 GstPad *srcpad = NULL;
138 GstPad *sinkpad = NULL;
140 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
141 _MMCamcorderSubContext *sc = NULL;
143 type_element *RecordsinkElement = NULL;
145 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
147 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
148 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
149 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
151 _mmcam_dbg_warn("start");
153 err = _mmcamcorder_check_videocodec_fileformat_compatibility(handle);
154 if (err != MM_ERROR_NONE)
158 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
159 _mmcam_dbg_log("pipeline is exist so need to remove pipeline _MMCAMCORDER_ENCODE_MAIN_PIPE = %p",
160 sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
161 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
164 _MMCAMCORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
166 /* get audio disable */
167 mm_camcorder_get_attributes(handle, NULL,
168 MMCAM_AUDIO_DISABLE, &sc->audio_disable,
171 _mmcam_dbg_log("MMCAM_AUDIO_DISABLE %d, is_modified_rate %d",
172 sc->audio_disable, sc->is_modified_rate);
174 sc->audio_disable |= sc->is_modified_rate;
176 if (sc->audio_disable == FALSE) {
177 /* create audiosrc bin */
178 err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder);
179 if (err != MM_ERROR_NONE)
183 err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO);
184 if (err != MM_ERROR_NONE)
187 if (sc->audio_disable == FALSE) {
188 gst_bin_add(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
189 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
192 /* add element and encodesink bin to encode main pipeline */
193 gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
194 sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
195 sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
196 sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
199 /* Link each element : appsrc - capsfilter - encodesink bin */
200 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
201 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
202 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
204 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
205 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0");
206 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
208 if (sc->audio_disable == FALSE) {
209 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
210 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
211 _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
214 _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main,
215 CONFIGURE_CATEGORY_MAIN_RECORD,
218 _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name);
220 if (!gst_element_rsink_name) {
221 _mmcam_dbg_err("failed to get recordsink name");
222 err = MM_ERROR_CAMCORDER_INTERNAL;
223 goto pipeline_creation_error;
226 /* set data probe function */
228 /* register message cb */
230 /* set data probe functions */
231 if (sc->audio_disable == FALSE) {
232 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink");
233 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
234 __mmcamcorder_audioque_dataprobe, hcamcorder);
235 gst_object_unref(sinkpad);
239 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src");
240 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
241 __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder);
242 gst_object_unref(srcpad);
245 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) {
246 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src");
247 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
248 __mmcamcorder_eventprobe_monitor, hcamcorder);
249 gst_object_unref(srcpad);
254 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) {
255 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src");
256 MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
257 __mmcamcorder_eventprobe_monitor, hcamcorder);
258 gst_object_unref(srcpad);
262 if (sc->audio_disable) {
263 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink");
264 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
265 __mmcamcorder_video_dataprobe_audio_disable, hcamcorder);
266 gst_object_unref(sinkpad);
270 if (!strcmp(gst_element_rsink_name, "filesink")) {
271 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC].gst, "src");
272 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
273 __mmcamcorder_video_dataprobe_record, hcamcorder);
274 gst_object_unref(srcpad);
277 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC].gst, "src");
278 MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC,
279 __mmcamcorder_audio_dataprobe_check, hcamcorder);
280 gst_object_unref(srcpad);
284 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "sink");
285 MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
286 __mmcamcorder_muxed_dataprobe, hcamcorder);
287 MMCAMCORDER_ADD_EVENT_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC,
288 __mmcamcorder_eventprobe_monitor, hcamcorder);
289 gst_object_unref(sinkpad);
292 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
294 /* register pipeline message callback */
295 hcamcorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder);
297 /* set sync handler */
298 gst_bus_set_sync_handler(bus, _mmcamcorder_encode_pipeline_bus_sync_callback, (gpointer)hcamcorder, NULL);
300 gst_object_unref(bus);
303 return MM_ERROR_NONE;
305 pipeline_creation_error:
306 for (i = _MMCAMCORDER_AUDIOSRC_BIN ; i <= _MMCAMCORDER_ENCSINK_SINK ; i++)
307 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, i);
309 _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCODE_MAIN_PIPE);
314 int _mmcamcorder_remove_audio_pipeline(MMHandleType handle)
316 GstPad *srcpad = NULL;
317 GstPad *sinkpad = NULL;
318 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
319 _MMCamcorderSubContext *sc = NULL;
321 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
323 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
324 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
325 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
329 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) {
330 srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src");
331 sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0");
332 _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
334 /* release audiosrc bin */
335 gst_bin_remove(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
336 sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst);
339 To avoid conflicting between old elements and newly created elements,
340 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
341 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
342 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
343 It's because the pipeline of audio recording destroys at the same time,
344 and '_mmcamcorder_element_release_noti' will perfom removing handle.
346 _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_VOL);
348 _mmcam_dbg_log("Audio pipeline removed");
351 return MM_ERROR_NONE;
355 int _mmcamcorder_remove_encode_pipeline(MMHandleType handle)
357 GstPad *reqpad = NULL;
358 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
359 _MMCamcorderSubContext *sc = NULL;
360 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
361 int ret = MM_ERROR_NONE;
362 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
364 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
366 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
367 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
368 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
372 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst != NULL) {
373 /* release request pad */
374 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio");
376 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
377 gst_object_unref(reqpad);
381 reqpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video");
383 gst_element_release_request_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad);
384 gst_object_unref(reqpad);
388 /* release encode main pipeline */
389 gst_object_unref(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst);
392 To avoid conflicting between old elements and newly created elements,
393 I clean element handles here. Real elements object will be finalized as the 'unref' process goes on.
394 This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements.
395 So I clean handles first, make them unref later. Audio recording, however, isn't needed this process.
396 It's because the pipeline of audio recording destroys at the same time,
397 and '_mmcamcorder_element_release_noti' will perfom removing handle.
399 /* _mmcamcorder_remove_element_handle(handle, (void *)sc->encode_element,
400 _MMCAMCORDER_ENCODE_MAIN_PIPE, _MMCAMCORDER_ENCSINK_SINK); */
402 _mmcam_dbg_warn("Encoder pipeline removed");
404 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
405 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
407 _mmcam_dbg_warn("lock resource - cb calling %d", hcamcorder->is_release_cb_calling);
409 if (hcamcorder->is_release_cb_calling == FALSE) {
410 /* release resource */
411 ret = mm_resource_manager_mark_for_release(hcamcorder->resource_manager,
412 hcamcorder->video_encoder_resource);
413 if (ret == MM_RESOURCE_MANAGER_ERROR_NONE)
414 hcamcorder->video_encoder_resource = NULL;
416 _mmcam_dbg_warn("mark resource for release 0x%x", ret);
418 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
420 _mmcam_dbg_warn("commit resource release 0x%x", ret);
423 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
425 _mmcam_dbg_warn("unlock resource");
426 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
429 return MM_ERROR_NONE;
433 int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle)
435 int ret = MM_ERROR_NONE;
436 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
437 _MMCamcorderSubContext *sc = NULL;
441 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
442 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
443 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
445 _mmcam_dbg_log("start");
447 if (!sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst) {
448 _mmcam_dbg_warn("pipeline is not existed.");
449 return MM_ERROR_NONE;
452 _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC);
454 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
455 if (ret != MM_ERROR_NONE) {
456 _mmcam_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
460 bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst));
462 /* remove audio pipeline first */
463 ret = _mmcamcorder_remove_audio_pipeline(handle);
464 if (ret != MM_ERROR_NONE) {
465 _mmcam_dbg_err("Fail to remove audio pipeline");
469 ret = _mmcamcorder_remove_encode_pipeline(handle);
470 if (ret != MM_ERROR_NONE) {
471 _mmcam_dbg_err("Fail to remove encoder pipeline");
475 /* Remove pipeline message callback */
476 if (hcamcorder->encode_pipeline_cb_event_id != 0) {
477 g_source_remove(hcamcorder->encode_pipeline_cb_event_id);
478 hcamcorder->encode_pipeline_cb_event_id = 0;
481 /* Remove remained message */
483 GstMessage *gst_msg = NULL;
484 while ((gst_msg = gst_bus_pop(bus)) != NULL) {
485 _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder);
486 gst_message_unref(gst_msg);
489 gst_object_unref(bus);
493 _mmcam_dbg_log("done");
499 int _mmcamcorder_video_command(MMHandleType handle, int command)
504 int ret = MM_ERROR_NONE;
505 double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
506 char *err_name = NULL;
507 char *target_filename = NULL;
508 GstCameraControl *CameraControl = NULL;
509 GstCameraControlChannel *CameraControlChannel = NULL;
510 const GList *controls = NULL;
511 const GList *item = NULL;
514 GstElement *pipeline = NULL;
516 _MMCamcorderVideoInfo *info = NULL;
517 _MMCamcorderSubContext *sc = NULL;
518 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
520 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
522 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
523 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
524 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
525 mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
527 info = sc->info_video;
529 _mmcam_dbg_log("Command(%d)", command);
531 pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
534 case _MMCamcorder_CMD_RECORD:
536 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) {
540 gboolean storage_validity = FALSE;
543 int root_directory_length = 0;
546 _mmcam_dbg_log("Record Start - dual stream %d", info->support_dual_stream);
548 #ifdef _MMCAMCORDER_MM_RM_SUPPORT
549 _MMCAMCORDER_LOCK_RESOURCE(hcamcorder);
551 /* prepare resource manager for H/W encoder */
552 if (hcamcorder->video_encoder_resource == NULL) {
553 ret = mm_resource_manager_mark_for_acquire(hcamcorder->resource_manager,
554 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER,
555 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
556 &hcamcorder->video_encoder_resource);
557 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
558 _mmcam_dbg_err("could not prepare for encoder resource");
559 ret = MM_ERROR_RESOURCE_INTERNAL;
560 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
561 goto _ERR_CAMCORDER_VIDEO_COMMAND;
564 _mmcam_dbg_log("encoder already acquired");
567 /* acquire resources */
568 ret = mm_resource_manager_commit(hcamcorder->resource_manager);
569 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
570 _mmcam_dbg_err("could not acquire resources");
571 ret = MM_ERROR_RESOURCE_INTERNAL;
572 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
573 goto _ERR_CAMCORDER_VIDEO_COMMAND;
576 _MMCAMCORDER_UNLOCK_RESOURCE(hcamcorder);
577 #endif /* _MMCAMCORDER_MM_RM_SUPPORT */
579 /* init record_dual_stream */
580 info->record_dual_stream = FALSE;
582 ret = mm_camcorder_get_attributes(handle, &err_name,
583 MMCAM_CAMERA_FPS, &fps,
584 MMCAM_CAMERA_WIDTH, &(info->preview_width),
585 MMCAM_CAMERA_HEIGHT, &(info->preview_height),
586 MMCAM_VIDEO_WIDTH, &(info->video_width),
587 MMCAM_VIDEO_HEIGHT, &(info->video_height),
588 MMCAM_FILE_FORMAT, &fileformat,
589 MMCAM_TARGET_FILENAME, &target_filename, &size,
590 MMCAM_TARGET_MAX_SIZE, &imax_size,
591 MMCAM_TARGET_TIME_LIMIT, &imax_time,
592 MMCAM_FILE_FORMAT, &(info->fileformat),
593 MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate,
594 MMCAM_ROOT_DIRECTORY, &hcamcorder->root_directory, &root_directory_length,
596 if (ret != MM_ERROR_NONE) {
597 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret);
599 goto _ERR_CAMCORDER_VIDEO_COMMAND;
602 if (!target_filename && !hcamcorder->mstream_cb) {
603 _mmcam_dbg_err("filename is not set and muxed stream cb is NULL");
604 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
605 goto _ERR_CAMCORDER_VIDEO_COMMAND;
610 info->max_size = 0; /* do not check */
612 info->max_size = ((guint64)imax_size) << 10; /* to byte */
616 info->max_time = 0; /* do not check */
618 info->max_time = (guint64)((double)imax_time * (double)1000 * motion_rate); /* to millisecond */
620 ret = _mmcamcorder_get_storage_validity(hcamcorder, target_filename,
621 _MMCAMCORDER_VIDEO_MINIMUM_SPACE, &storage_validity);
622 if (ret != MM_ERROR_NONE) {
623 _mmcam_dbg_err("storage validation failed[0x%x]:%d", ret, storage_validity);
627 _mmcamcorder_adjust_recording_max_size(target_filename, &info->max_size);
629 g_mutex_lock(&hcamcorder->task_thread_lock);
630 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
631 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
632 /* Play record start sound */
633 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_START, FALSE);
635 g_mutex_unlock(&hcamcorder->task_thread_lock);
637 _mmcam_dbg_warn("video size [%dx%d]", info->video_width, info->video_height);
639 if (info->video_width == 0 || info->video_height == 0) {
640 _mmcam_dbg_warn("video size is invalid [%dx%d] use preview size [%dx%d]",
641 info->video_width, info->video_height, info->preview_width, info->preview_height);
642 info->video_width = info->preview_width;
643 info->video_height = info->preview_height;
646 if (info->support_dual_stream) {
647 _mmcam_dbg_warn("DUAL STREAM MODE");
649 info->record_dual_stream = TRUE;
651 /* No need to restart preview */
652 info->restart_preview = FALSE;
654 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-width", info->video_width);
655 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video-height", info->video_height);
656 } else if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
657 info->preview_width == info->video_width &&
658 info->preview_height == info->video_height) {
659 _mmcam_dbg_log("H264 preview mode and same resolution");
661 /* No need to restart preview */
662 info->restart_preview = FALSE;
664 /* always need to restart preview */
665 info->restart_preview = TRUE;
668 /* set recording hint */
669 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", TRUE);
671 if (info->restart_preview) {
672 /* stop preview and set new size */
673 _mmcam_dbg_log("restart preview");
675 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
676 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
677 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
679 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
681 /* check decoder recreation */
682 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
683 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
684 ret = MM_ERROR_CAMCORDER_INTERNAL;
685 goto _ERR_CAMCORDER_VIDEO_COMMAND;
688 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
689 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
690 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
692 if (ret != MM_ERROR_NONE)
693 goto _ERR_CAMCORDER_VIDEO_COMMAND;
695 if (!_mmcamcorder_set_camera_resolution(handle, info->video_width, info->video_height)) {
696 ret = MM_ERROR_CAMCORDER_INTERNAL;
697 goto _ERR_CAMCORDER_VIDEO_COMMAND;
700 /* Start preview again with new setting */
701 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
702 if (ret != MM_ERROR_NONE)
703 goto _ERR_CAMCORDER_VIDEO_COMMAND;
705 if (motion_rate < 1.0) {
706 _mmcam_dbg_warn("wait for stabilization of frame");
710 _mmcam_dbg_log("no need to restart preview");
713 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
714 CONFIGURE_CATEGORY_MAIN_RECORD,
718 _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
719 CONFIGURE_CATEGORY_MAIN_RECORD,
720 "PassFirstVideoFrame",
721 &(sc->pass_first_vframe));
723 _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]",
724 sc->drop_vframe, sc->pass_first_vframe);
726 info->record_drop_count = (guint)motion_rate;
727 info->record_motion_rate = motion_rate;
728 if (sc->is_modified_rate)
729 info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate);
731 info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE;
733 _mmcam_dbg_warn("recording fps %d, motion rate %f, timestamp_ratio %f",
734 fps, info->record_motion_rate, info->record_timestamp_ratio);
736 /* set push buffer flag */
737 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_INIT;
738 info->base_video_ts = 0;
740 /* connect video stream cb signal */
741 /*130826 Connect video stream cb for handling fast record frame cb*/
742 if (info->record_dual_stream) {
743 if (_mmcamcorder_connect_video_stream_cb_signal((MMHandleType)hcamcorder) != MM_ERROR_NONE)
744 goto _ERR_CAMCORDER_VIDEO_COMMAND;
747 /* start video stream */
748 if (info->record_dual_stream) {
749 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
751 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
753 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_START");
754 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_START);
756 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
758 _mmcam_dbg_err("could not get camera control");
762 /* check pre-created encode pipeline */
763 g_mutex_lock(&hcamcorder->task_thread_lock);
764 if (sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst == NULL &&
765 hcamcorder->task_thread_state == _MMCAMCORDER_TASK_THREAD_STATE_NONE) {
766 /* create encoding pipeline */
767 ret = _mmcamcorder_video_prepare_record((MMHandleType)hcamcorder);
768 if (ret != MM_ERROR_NONE) {
769 g_mutex_unlock(&hcamcorder->task_thread_lock);
770 goto _ERR_CAMCORDER_VIDEO_COMMAND;
773 g_mutex_unlock(&hcamcorder->task_thread_lock);
775 /* check recording start sound */
776 _mmcamcorder_sound_solo_play_wait(handle);
778 /**< To fix video recording hanging
779 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time()
780 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25,
781 basetime wouldn't change if you set (GstClockTime)0.
782 3. Move set start time position below PAUSED of pipeline.
785 gst_element_set_start_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), (GstClockTime)1);
786 gst_element_set_start_time(GST_ELEMENT(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst), (GstClockTime)1);
789 info->video_frame_count = 0;
790 info->is_firstframe = TRUE;
791 info->audio_frame_count = 0;
793 sc->ferror_send = FALSE;
794 sc->ferror_count = 0;
795 hcamcorder->error_occurs = FALSE;
796 sc->bget_eos = FALSE;
797 sc->muxed_stream_offset = 0;
799 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
800 if (ret != MM_ERROR_NONE) {
801 /* stop video stream */
802 if (info->record_dual_stream) {
803 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
805 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
807 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
808 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
810 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
812 _mmcam_dbg_err("failed to get camera control");
816 /* Remove recorder pipeline and recording file which size maybe zero */
817 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
818 if (info->filename) {
819 _mmcam_dbg_log("file delete(%s)", info->filename);
820 unlink(info->filename);
822 goto _ERR_CAMCORDER_VIDEO_COMMAND;
825 /*set the camera control to create the GOP so that video record will get a new key frame*/
826 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
827 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
828 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
829 controls = gst_camera_control_list_channels(CameraControl);
830 if (controls != NULL) {
831 for (item = controls ; item && item->data ; item = item->next) {
832 CameraControlChannel = item->data;
833 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
834 if (!strcmp(CameraControlChannel->label, "new-gop")) {
835 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
841 _mmcam_dbg_warn("failed to find new-gop control channel");
844 _mmcam_dbg_warn("Can't cast Video source into camera control or not H264 prevew format[%d]",
845 sc->info_image->preview_format);
850 if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ENCODED_H264 &&
851 GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) {
852 /* generate and I-frame on resuming */
853 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
854 controls = gst_camera_control_list_channels(CameraControl);
855 if (controls != NULL) {
856 for (item = controls ; item && item->data ; item = item->next) {
857 CameraControlChannel = item->data;
858 _mmcam_dbg_log("CameraControlChannel->label %s", CameraControlChannel->label);
859 if (!strcmp(CameraControlChannel->label, "new-gop")) {
860 /* gst_camera_control_set_value(CameraControl, CameraControlChannel, 1); */
866 _mmcam_dbg_warn("failed to find new-gop control channel");
870 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE);
872 _mmcam_dbg_log("Object property settings done");
876 case _MMCamcorder_CMD_PAUSE:
878 if (info->b_commiting) {
879 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
880 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
883 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
884 if (sc->audio_disable) {
885 /* check only video frame */
886 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
888 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
889 _mmcam_dbg_err("Pause fail, frame count %"G_GUINT64_FORMAT, info->video_frame_count);
890 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
892 _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %"G_GUINT64_FORMAT, count, info->video_frame_count);
895 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
897 /* check both of video and audio frame */
898 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
900 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
901 _mmcam_dbg_err("Pause fail, frame count VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
902 info->video_frame_count, info->audio_frame_count);
903 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
905 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"]",
906 count, info->video_frame_count, info->audio_frame_count);
909 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
913 /* block encodebin */
914 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
917 case _MMCamcorder_CMD_CANCEL:
919 if (info->b_commiting) {
920 _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command);
921 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
924 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
926 if (hcamcorder->capture_in_recording == FALSE) {
928 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
929 _mmcam_dbg_err("Failed to Wait capture data");
930 hcamcorder->capture_in_recording = FALSE;
933 _mmcam_dbg_warn("Waiting for capture data - retrial [%d]", count);
936 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
939 /* block push buffer */
940 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
942 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
943 if (ret != MM_ERROR_NONE)
944 goto _ERR_CAMCORDER_VIDEO_COMMAND;
946 /* set recording hint */
947 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
949 /* stop video stream */
950 if (info->record_dual_stream) {
951 CameraControl = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
953 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
955 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
956 gst_camera_control_set_record_command(CameraControl, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
958 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
960 _mmcam_dbg_err("failed to get camera control");
964 if (info->restart_preview) {
965 /* restart preview */
966 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
967 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
968 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
970 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY);
972 /* check decoder recreation */
973 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
974 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
975 ret = MM_ERROR_CAMCORDER_INTERNAL;
978 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
979 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
980 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
982 if (ret != MM_ERROR_NONE)
983 goto _ERR_CAMCORDER_VIDEO_COMMAND;
985 /* reset restart_preview for inset window layout */
986 info->restart_preview = FALSE;
988 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
989 ret = MM_ERROR_CAMCORDER_INTERNAL;
990 goto _ERR_CAMCORDER_VIDEO_COMMAND;
993 ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
994 if (ret != MM_ERROR_NONE)
995 goto _ERR_CAMCORDER_VIDEO_COMMAND;
998 /* remove target file */
999 if (info->filename) {
1000 _mmcam_dbg_log("file delete(%s)", info->filename);
1001 unlink(info->filename);
1004 sc->isMaxsizePausing = FALSE;
1005 sc->isMaxtimePausing = FALSE;
1007 sc->display_interval = 0;
1008 sc->previous_slot_time = 0;
1009 info->video_frame_count = 0;
1010 info->audio_frame_count = 0;
1012 hcamcorder->capture_in_recording = FALSE;
1015 case _MMCamcorder_CMD_COMMIT:
1019 if (info->b_commiting) {
1020 _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command);
1021 return MM_ERROR_CAMCORDER_CMD_IS_RUNNING;
1023 _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start");
1024 info->b_commiting = TRUE;
1025 sc->bget_eos = FALSE;
1028 for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) {
1029 if (sc->audio_disable) {
1030 /* check only video frame */
1031 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1032 hcamcorder->capture_in_recording == FALSE) {
1034 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1035 _mmcam_dbg_err("Commit fail, frame count is %"G_GUINT64_FORMAT", capturing %d",
1036 info->video_frame_count, hcamcorder->capture_in_recording);
1038 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) {
1039 _mmcam_dbg_warn("video frames are enough. keep going...");
1041 info->b_commiting = FALSE;
1042 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1045 _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %"G_GUINT64_FORMAT", capturing %d",
1046 count, info->video_frame_count, hcamcorder->capture_in_recording);
1049 /* check both of video and audio frame */
1050 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME &&
1051 info->audio_frame_count &&
1052 hcamcorder->capture_in_recording == FALSE) {
1054 } else if (count == _MMCAMCORDER_RETRIAL_COUNT) {
1055 _mmcam_dbg_err("Commit fail, VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1056 info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1058 if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) {
1059 _mmcam_dbg_warn("video/audio frames are enough. keep going...");
1061 info->b_commiting = FALSE;
1062 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1065 return MM_ERROR_CAMCORDER_INVALID_CONDITION;
1067 _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%"G_GUINT64_FORMAT"], AUDIO [%"G_GUINT64_FORMAT"], capturing %d",
1068 count, info->video_frame_count, info->audio_frame_count, hcamcorder->capture_in_recording);
1072 if (hcamcorder->capture_in_recording) {
1073 gint64 end_time = g_get_monotonic_time() + (200 * G_TIME_SPAN_MILLISECOND);
1074 if (!_MMCAMCORDER_CMD_WAIT_UNTIL(handle, end_time))
1075 _mmcam_dbg_warn("timeout");
1077 usleep(_MMCAMCORDER_FRAME_WAIT_TIME);
1081 /* block push buffer */
1082 info->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
1083 _mmcam_dbg_log("block push buffer to appsrc");
1085 _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1086 if (free_space < _MMCAMCORDER_MINIMUM_SPACE) {
1087 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT out of storage [%" G_GUINT64_FORMAT "]", free_space);
1088 ret = MM_ERROR_OUT_OF_STORAGE;
1089 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1092 if (sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst != NULL) {
1093 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, gst_event_new_eos())) {
1094 _mmcam_dbg_warn("VIDEO: send eos to appsrc done");
1096 _mmcam_dbg_err("VIDEO: send EOS failed");
1097 info->b_commiting = FALSE;
1098 ret = MM_ERROR_CAMCORDER_INTERNAL;
1099 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1102 _mmcam_dbg_err("No video stream source");
1103 info->b_commiting = FALSE;
1104 ret = MM_ERROR_CAMCORDER_INTERNAL;
1105 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1108 if (sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) {
1109 if (gst_element_send_event(sc->encode_element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos())) {
1110 _mmcam_dbg_warn("AUDIO: send eos to audiosrc done");
1112 _mmcam_dbg_err("AUDIO: send EOS failed");
1113 info->b_commiting = FALSE;
1114 ret = MM_ERROR_CAMCORDER_INTERNAL;
1115 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1118 _mmcam_dbg_log("No audio stream");
1122 sc->display_interval = 0;
1123 sc->previous_slot_time = 0;
1126 _mmcam_dbg_log("Start to wait EOS");
1127 ret = _mmcamcorder_get_eos_message(handle);
1128 if (ret != MM_ERROR_NONE) {
1129 info->b_commiting = FALSE;
1130 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1134 hcamcorder->capture_in_recording = FALSE;
1138 ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
1139 goto _ERR_CAMCORDER_VIDEO_COMMAND;
1142 return MM_ERROR_NONE;
1144 _ERR_CAMCORDER_VIDEO_COMMAND:
1145 if (command == _MMCamcorder_CMD_RECORD)
1146 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1152 int _mmcamcorder_video_handle_eos(MMHandleType handle)
1154 int ret = MM_ERROR_NONE;
1156 guint64 file_size = 0;
1158 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1159 _MMCamcorderSubContext *sc = NULL;
1160 _MMCamcorderVideoInfo *info = NULL;
1161 _MMCamcorderMsgItem msg;
1162 MMCamRecordingReport *report = NULL;
1164 mmf_return_val_if_fail(hcamcorder, FALSE);
1166 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1167 mmf_return_val_if_fail(sc, FALSE);
1168 mmf_return_val_if_fail(sc->info_video, FALSE);
1170 info = sc->info_video;
1174 /* Play record stop sound */
1175 _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_SAMPLE_SOUND_NAME_REC_STOP, FALSE);
1177 /* remove blocking part */
1178 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
1180 mm_camcorder_get_attributes(handle, NULL,
1181 MMCAM_RECORDER_TAG_ENABLE, &enabletag,
1184 ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
1185 if (ret != MM_ERROR_NONE)
1186 _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret);
1188 /* set recording hint */
1189 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "recording-hint", FALSE);
1191 /* stop video stream */
1192 if (info->record_dual_stream) {
1193 GstCameraControl *control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
1195 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE);
1197 _mmcam_dbg_log("GST_CAMERA_CONTROL_RECORD_COMMAND_STOP");
1198 gst_camera_control_set_record_command(control, GST_CAMERA_CONTROL_RECORD_COMMAND_STOP);
1200 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE);
1202 _mmcam_dbg_err("failed to get camera control");
1206 if (enabletag && !(sc->ferror_send)) {
1207 ret = __mmcamcorder_add_metadata((MMHandleType)hcamcorder, info->fileformat);
1208 _mmcam_dbg_log("Writing location information [%s] !!", ret ? "SUCCEEDED" : "FAILED");
1211 /* Check file size */
1212 if (info->max_size > 0) {
1213 _mmcamcorder_get_file_size(info->filename, &file_size);
1214 _mmcam_dbg_log("MAX size %"G_GUINT64_FORMAT" byte - created filesize %"G_GUINT64_FORMAT" byte",
1215 info->max_size, file_size);
1217 if (file_size > info->max_size) {
1218 _MMCamcorderMsgItem message;
1219 _mmcam_dbg_err("File size is greater than max size !!");
1220 message.id = MM_MESSAGE_CAMCORDER_ERROR;
1221 message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER;
1222 _mmcamcorder_send_message((MMHandleType)hcamcorder, &message);
1226 if (info->restart_preview) {
1228 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE);
1229 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", TRUE);
1230 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", TRUE);
1232 _mmcam_dbg_log("Set state of pipeline as READY");
1233 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY);
1235 /* check decoder recreation */
1236 if (!_mmcamcorder_recreate_decoder_for_encoded_preview(handle)) {
1237 _mmcam_dbg_err("_mmcamcorder_recreate_decoder_for_encoded_preview failed");
1238 ret = MM_ERROR_CAMCORDER_INTERNAL;
1242 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE);
1243 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
1244 MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "keep-camera-preview", FALSE);
1246 if (ret != MM_ERROR_NONE) {
1247 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1248 msg.param.code = ret;
1249 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1250 _mmcam_dbg_err("Failed to set state READY[%x]", ret);
1253 /* reset restart_preview for inset window layout */
1254 info->restart_preview = FALSE;
1256 /* recover preview size */
1257 if (!_mmcamcorder_set_camera_resolution(handle, info->preview_width, info->preview_height)) {
1258 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1259 msg.param.code = MM_ERROR_CAMCORDER_INTERNAL;
1260 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1261 _mmcam_dbg_err("Failed to set camera resolution %dx%d",
1262 info->preview_width, info->preview_height);
1265 ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING);
1266 /* Do not return when error is occurred.
1267 Recording file was created successfully, but starting pipeline failed */
1268 if (ret != MM_ERROR_NONE) {
1269 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1270 msg.param.code = ret;
1271 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1272 _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret);
1275 _mmcam_dbg_log("No need to restart preview");
1278 /* Send recording report to application */
1279 msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED;
1280 report = (MMCamRecordingReport *)g_malloc(sizeof(MMCamRecordingReport));
1282 _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename);
1284 report->recording_filename = g_strdup(info->filename);
1285 msg.param.data = report;
1287 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1291 sc->pipeline_time = 0;
1293 sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
1294 sc->isMaxtimePausing = FALSE;
1295 hcamcorder->error_occurs = FALSE;
1297 info->video_frame_count = 0;
1298 info->audio_frame_count = 0;
1300 info->b_commiting = FALSE;
1302 /* check recording stop sound */
1303 _mmcamcorder_sound_solo_play_wait(handle);
1305 _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end");
1311 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1313 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1314 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1316 _MMCamcorderSubContext *sc = NULL;
1317 _MMCamcorderVideoInfo *videoinfo = NULL;
1318 _MMCamcorderMsgItem msg;
1319 guint64 buffer_size = 0;
1320 guint64 trailer_size = 0;
1321 guint64 max_size = 0;
1323 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1324 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1325 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1327 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1328 videoinfo = sc->info_video;
1330 /* get buffer size */
1331 if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
1332 _mmcam_dbg_warn("map failed : buffer %p", buffer);
1333 return GST_PAD_PROBE_OK;
1336 buffer_size = mapinfo.size;
1337 gst_buffer_unmap(buffer, &mapinfo);
1339 /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1341 g_mutex_lock(&videoinfo->size_check_lock);
1343 if (videoinfo->audio_frame_count == 0) {
1344 videoinfo->filesize += buffer_size;
1345 videoinfo->audio_frame_count++;
1346 g_mutex_unlock(&videoinfo->size_check_lock);
1347 return GST_PAD_PROBE_OK;
1350 if (sc->ferror_send || sc->isMaxsizePausing) {
1351 _mmcam_dbg_warn("Recording is paused, drop frames");
1352 g_mutex_unlock(&videoinfo->size_check_lock);
1353 return GST_PAD_PROBE_DROP;
1356 /* get trailer size */
1357 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1358 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1362 /* check max size of recorded file */
1363 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1364 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1365 GstState pipeline_state = GST_STATE_VOID_PENDING;
1366 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1367 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1368 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1369 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1370 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1372 if (!sc->isMaxsizePausing) {
1373 sc->isMaxsizePausing = TRUE;
1374 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1375 if (pipeline_state == GST_STATE_PLAYING)
1376 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1378 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1379 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1382 g_mutex_unlock(&videoinfo->size_check_lock);
1387 videoinfo->filesize += buffer_size;
1388 videoinfo->audio_frame_count++;
1390 g_mutex_unlock(&videoinfo->size_check_lock);
1392 return GST_PAD_PROBE_OK;
1396 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1401 guint64 free_space = 0;
1402 guint64 buffer_size = 0;
1403 guint64 trailer_size = 0;
1404 guint64 queued_buffer = 0;
1405 guint64 max_size = 0;
1406 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1408 storage_state_e storage_state = STORAGE_STATE_UNMOUNTABLE;
1410 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1411 _MMCamcorderMsgItem msg;
1412 _MMCamcorderSubContext *sc = NULL;
1413 _MMCamcorderVideoInfo *videoinfo = NULL;
1415 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1416 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1418 sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
1419 mmf_return_val_if_fail(sc && sc->info_video, GST_PAD_PROBE_OK);
1420 videoinfo = sc->info_video;
1422 /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1423 if (sc->ferror_send) {
1424 _mmcam_dbg_warn("file write error, drop frames");
1425 return GST_PAD_PROBE_DROP;
1428 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1429 buffer_size = mapinfo.size;
1430 gst_buffer_unmap(buffer, &mapinfo);
1432 videoinfo->video_frame_count++;
1433 if (videoinfo->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) {
1434 /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ",
1435 info->video_frame_count); */
1436 g_mutex_lock(&videoinfo->size_check_lock);
1437 videoinfo->filesize += buffer_size;
1438 g_mutex_unlock(&videoinfo->size_check_lock);
1439 return GST_PAD_PROBE_OK;
1442 /* get trailer size */
1443 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1444 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1448 /* check free space */
1449 ret = _mmcamcorder_get_freespace(hcamcorder->storage_info.type, &free_space);
1451 _mmcam_dbg_err("Error occured. [%d]", ret);
1452 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1453 sc->ferror_send = TRUE;
1455 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1456 msg.param.code = MM_ERROR_FILE_READ;
1458 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1463 return GST_PAD_PROBE_DROP; /* skip this buffer */
1466 if (free_space == 0) {
1467 /* check storage state */
1468 storage_get_state(hcamcorder->storage_info.id, &storage_state);
1470 _mmcam_dbg_warn("storage state %d", storage_state);
1472 if (storage_state == STORAGE_STATE_REMOVED ||
1473 storage_state == STORAGE_STATE_UNMOUNTABLE) {
1474 _mmcam_dbg_err("storage was removed!");
1476 _MMCAMCORDER_LOCK(hcamcorder);
1478 if (sc->ferror_send == FALSE) {
1479 _mmcam_dbg_err("OUT_OF_STORAGE error");
1481 sc->ferror_send = TRUE;
1483 _MMCAMCORDER_UNLOCK(hcamcorder);
1485 msg.id = MM_MESSAGE_CAMCORDER_ERROR;
1486 msg.param.code = MM_ERROR_OUT_OF_STORAGE;
1488 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1490 _MMCAMCORDER_UNLOCK(hcamcorder);
1491 _mmcam_dbg_warn("error was already sent");
1494 return GST_PAD_PROBE_DROP;
1498 /* get queued buffer size */
1499 if (sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst)
1500 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1502 if (sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst)
1503 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1505 queued_buffer = aq_size + vq_size;
1507 if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1508 _mmcam_dbg_warn("No more space for recording!!! Recording is paused.");
1509 _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \
1510 " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \
1511 free_space, trailer_size, buffer_size, queued_buffer);
1513 if (!sc->isMaxsizePausing) {
1514 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1515 sc->isMaxsizePausing = TRUE;
1517 msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE;
1518 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1521 return GST_PAD_PROBE_DROP;
1524 g_mutex_lock(&videoinfo->size_check_lock);
1526 /* check max size of recorded file */
1527 max_size = videoinfo->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE;
1528 if (videoinfo->max_size > 0 && videoinfo->max_size < max_size) {
1529 GstState pipeline_state = GST_STATE_VOID_PENDING;
1530 GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst;
1531 _mmcam_dbg_warn("Max size!!! Recording is paused.");
1532 _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \
1533 " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]",
1534 videoinfo->max_size, videoinfo->filesize, buffer_size, trailer_size);
1536 if (!sc->isMaxsizePausing) {
1537 sc->isMaxsizePausing = TRUE;
1538 gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ;
1539 if (pipeline_state == GST_STATE_PLAYING)
1540 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1542 msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE;
1543 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1546 g_mutex_unlock(&videoinfo->size_check_lock);
1548 return GST_PAD_PROBE_DROP;
1551 videoinfo->filesize += (guint64)buffer_size;
1554 _mmcam_dbg_log("filesize %lld Byte, ", videoinfo->filesize);
1557 g_mutex_unlock(&videoinfo->size_check_lock);
1559 return GST_PAD_PROBE_OK;
1563 static GstPadProbeReturn __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1565 guint64 trailer_size = 0;
1566 guint64 rec_pipe_time = 0;
1567 unsigned int remained_time = 0;
1569 GstClockTime b_time;
1571 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1572 _MMCamcorderMsgItem msg;
1573 _MMCamcorderSubContext *sc = NULL;
1574 _MMCamcorderVideoInfo *videoinfo = NULL;
1576 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1578 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1579 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1581 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1582 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1583 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1585 videoinfo = sc->info_video;
1587 b_time = GST_BUFFER_PTS(buffer);
1589 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1591 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1592 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1596 /* check max time */
1597 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1598 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1599 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1601 if (!sc->isMaxtimePausing) {
1602 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1604 sc->isMaxtimePausing = TRUE;
1606 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1607 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1608 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1609 msg.param.recording_status.remained_time = 0;
1610 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1612 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1613 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1616 return GST_PAD_PROBE_DROP;
1619 /* calculate remained time can be recorded */
1620 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1621 remained_time = videoinfo->max_time - rec_pipe_time;
1622 } else if (videoinfo->max_size > 0) {
1623 long double max_size = (long double)videoinfo->max_size;
1624 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1626 remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1629 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1630 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1631 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1632 msg.param.recording_status.remained_time = remained_time;
1633 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1636 _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1637 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1640 if (videoinfo->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1641 guint record_motion_rate = (guint)videoinfo->record_motion_rate;
1644 _mmcam_dbg_log("record_motion_rate %d, videoinfo->record_drop_count %d",
1645 record_motion_rate, videoinfo->record_drop_count);
1648 /* drop some frame if fast motion */
1649 if (videoinfo->record_motion_rate > _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) {
1650 if (record_motion_rate != (videoinfo->record_drop_count++)) {
1652 _mmcam_dbg_warn("drop frame");
1654 return GST_PAD_PROBE_DROP;
1657 videoinfo->record_drop_count = 1;
1659 _mmcam_dbg_warn("pass frame");
1663 GST_BUFFER_PTS(buffer) = b_time * (videoinfo->record_timestamp_ratio);
1664 GST_BUFFER_DTS(buffer) = GST_BUFFER_PTS(buffer);
1667 return GST_PAD_PROBE_OK;
1671 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1673 _MMCamcorderMsgItem msg;
1674 guint64 trailer_size = 0;
1675 guint64 rec_pipe_time = 0;
1676 _MMCamcorderSubContext *sc = NULL;
1677 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1678 _MMCamcorderVideoInfo *videoinfo = NULL;
1679 unsigned int remained_time = 0;
1680 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1682 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1683 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_OK);
1684 sc = MMF_CAMCORDER_SUBCONTEXT(u_data);
1686 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1687 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1688 mmf_return_val_if_fail(sc->element, GST_PAD_PROBE_OK);
1690 videoinfo = sc->info_video;
1692 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1693 _mmcam_dbg_err("Buffer timestamp is invalid, check it");
1694 return GST_PAD_PROBE_OK;
1697 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer));
1699 if (videoinfo->fileformat == MM_FILE_FORMAT_3GP || videoinfo->fileformat == MM_FILE_FORMAT_MP4)
1700 MMCAMCORDER_G_OBJECT_GET(sc->encode_element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1704 /* calculate remained time can be recorded */
1705 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time)) {
1706 remained_time = videoinfo->max_time - rec_pipe_time;
1707 } else if (videoinfo->max_size > 0) {
1708 long double max_size = (long double)videoinfo->max_size;
1709 long double current_size = (long double)(videoinfo->filesize + trailer_size);
1711 remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time;
1714 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1715 _mmcam_dbg_warn("Time current [%" G_GUINT64_FORMAT "], Max [%" G_GUINT64_FORMAT "], motion rate [%lf]", \
1716 rec_pipe_time, videoinfo->max_time, videoinfo->record_motion_rate);
1718 if (!sc->isMaxtimePausing) {
1719 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1721 sc->isMaxtimePausing = TRUE;
1723 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1724 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1725 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1726 msg.param.recording_status.remained_time = 0;
1727 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1729 msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT;
1730 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1733 return GST_PAD_PROBE_DROP;
1736 msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS;
1737 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1738 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1739 msg.param.recording_status.remained_time = remained_time;
1740 _mmcamcorder_send_message((MMHandleType)hcamcorder, &msg);
1743 _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1744 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1747 return GST_PAD_PROBE_OK;
1751 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1753 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
1754 double volume = 0.0;
1757 int err = MM_ERROR_UNKNOWN;
1758 char *err_name = NULL;
1759 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1762 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1763 mmf_return_val_if_fail(hcamcorder, GST_PAD_PROBE_DROP);
1765 /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));*/
1766 err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name,
1767 MMCAM_AUDIO_VOLUME, &volume,
1768 MMCAM_AUDIO_FORMAT, &format,
1769 MMCAM_AUDIO_CHANNEL, &channel,
1771 if (err != MM_ERROR_NONE) {
1772 _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
1773 SAFE_FREE(err_name);
1777 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
1779 gst_buffer_map(buffer, &mapinfo, GST_MAP_READWRITE);
1781 /* Set audio stream NULL */
1783 memset(mapinfo.data, 0, mapinfo.size);
1785 /* CALL audio stream callback */
1786 if (hcamcorder->astream_cb && buffer && mapinfo.data && mapinfo.size > 0) {
1787 MMCamcorderAudioStreamDataType stream;
1789 if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) {
1790 _mmcam_dbg_warn("Not ready for stream callback");
1791 gst_buffer_unmap(buffer, &mapinfo);
1792 return GST_PAD_PROBE_OK;
1795 /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]",
1796 GST_BUFFER_DATA(buffer), width, height, format);*/
1798 stream.data = (void *)mapinfo.data;
1799 stream.format = format;
1800 stream.channel = channel;
1801 stream.length = mapinfo.size;
1802 stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer)/1000000); /* nano -> milli second */
1804 _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder);
1806 if (hcamcorder->astream_cb)
1807 hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param);
1809 _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder);
1812 gst_buffer_unmap(buffer, &mapinfo);
1813 return GST_PAD_PROBE_OK;
1817 static gboolean __mmcamcorder_add_metadata(MMHandleType handle, int fileformat)
1819 gboolean bret = FALSE;
1821 switch (fileformat) {
1822 case MM_FILE_FORMAT_3GP:
1823 case MM_FILE_FORMAT_MP4:
1824 bret = __mmcamcorder_add_metadata_mp4(handle);
1827 _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat);
1835 static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle)
1839 guint64 udta_size = 0;
1840 gint64 current_pos = 0;
1841 gint64 moov_pos = 0;
1842 gint64 udta_pos = 0;
1843 gdouble longitude = 0;
1844 gdouble latitude = 0;
1845 gdouble altitude = 0;
1847 int orientation = 0;
1849 char *err_name = NULL;
1850 char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',};
1851 _MMCamcorderLocationInfo location_info = {0, 0, 0};
1852 _MMCamcorderLocationInfo geo_info = {0, 0, 0};
1854 _MMCamcorderVideoInfo *info = NULL;
1855 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
1856 _MMCamcorderSubContext *sc = NULL;
1858 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1859 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
1861 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1862 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
1866 info = sc->info_video;
1868 f = fopen64(info->filename, "rb+");
1870 strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN);
1871 _mmcam_dbg_err("file open failed [%s]", err_msg);
1875 mm_camcorder_get_attributes(handle, &err_name,
1876 MMCAM_TAG_LATITUDE, &latitude,
1877 MMCAM_TAG_LONGITUDE, &longitude,
1878 MMCAM_TAG_ALTITUDE, &altitude,
1879 MMCAM_TAG_VIDEO_ORIENTATION, &orientation,
1880 MMCAM_TAG_GPS_ENABLE, &gps_enable,
1883 _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err);
1884 SAFE_FREE(err_name);
1887 location_info.longitude = _mmcamcorder_double_to_fix(longitude);
1888 location_info.latitude = _mmcamcorder_double_to_fix(latitude);
1889 location_info.altitude = _mmcamcorder_double_to_fix(altitude);
1890 geo_info.longitude = longitude *10000;
1891 geo_info.latitude = latitude *10000;
1892 geo_info.altitude = altitude *10000;
1893 /* find udta container.
1894 if, there are udta container, write loci box after that
1895 else, make udta container and write loci box. */
1896 if (_mmcamcorder_find_fourcc(f, MMCAM_FOURCC('u', 'd', 't', 'a'), TRUE)) {
1899 _mmcam_dbg_log("find udta container");
1902 if (fseek(f, -8L, SEEK_CUR) != 0)
1905 udta_pos = ftello(f);
1909 nread = fread(&buf, sizeof(char), sizeof(buf), f);
1911 _mmcam_dbg_log("recorded file fread %zu", nread);
1913 udta_size = _mmcamcorder_get_container_size(buf);
1915 /* goto end of udta and write 'loci' box */
1916 if (fseek(f, (udta_size-4L), SEEK_CUR) != 0)
1920 if (!_mmcamcorder_write_loci(f, location_info)) {
1921 _mmcam_dbg_err("failed to write loci");
1925 if (!_mmcamcorder_write_geodata(f, geo_info)) {
1926 _mmcam_dbg_err("failed to write geodata");
1931 current_pos = ftello(f);
1932 if (current_pos < 0)
1935 if (!_mmcamcorder_update_size(f, udta_pos, current_pos))
1938 _mmcam_dbg_log("No udta container");
1939 if (fseek(f, 0, SEEK_END) != 0)
1942 if (!_mmcamcorder_write_udta(f, gps_enable, location_info, geo_info)) {
1943 _mmcam_dbg_err("failed to write udta");
1948 /* find moov container.
1949 update moov container size. */
1950 if ((current_pos = ftello(f)) < 0)
1953 if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
1954 gint64 internal_pos = ftello(f);
1956 _mmcam_dbg_log("found moov container");
1957 if (fseek(f, -8L, SEEK_CUR) != 0)
1960 moov_pos = ftello(f);
1964 if (!_mmcamcorder_update_size(f, moov_pos, current_pos))
1967 /* add orientation info */
1968 if (fseeko(f, internal_pos, SEEK_SET) < 0) {
1969 _mmcam_dbg_err("fseeko failed : errno %d", errno);
1973 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'r', 'a', 'k'), FALSE)) {
1974 _mmcam_dbg_err("failed to find [trak] tag");
1978 if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t', 'k', 'h', 'd'), FALSE)) {
1979 _mmcam_dbg_err("failed to find [tkhd] tag");
1983 _mmcam_dbg_log("found [tkhd] tag");
1985 /* seek to start position of composition matrix */
1986 if (fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR) == 0) {
1987 /* update composition matrix for orientation */
1988 _mmcamcorder_update_composition_matrix(f, orientation);
1990 _mmcam_dbg_err("fseek failed : errno %d", errno);
1994 _mmcam_dbg_err("No 'moov' container");
2006 _mmcam_dbg_err("ftell() returns negative value.");
2012 int _mmcamcorder_connect_video_stream_cb_signal(MMHandleType handle)
2014 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2015 _MMCamcorderSubContext *sc = NULL;
2017 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2019 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2020 mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2022 /* check video source element */
2023 if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
2024 _mmcam_dbg_warn("connect video stream cb signal to _MMCAMCORDER_VIDEOSRC_SRC");
2025 MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
2026 _MMCAMCORDER_HANDLER_VIDEOREC, "video-stream-cb",
2027 G_CALLBACK(__mmcamcorder_video_stream_cb),
2029 return MM_ERROR_NONE;
2031 _mmcam_dbg_err("videosrc element is not created yet");
2032 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
2037 int _mmcamcorder_video_prepare_record(MMHandleType handle)
2039 int ret = MM_ERROR_NONE;
2041 char *temp_filename = NULL;
2043 _MMCamcorderVideoInfo *info = NULL;
2044 _MMCamcorderSubContext *sc = NULL;
2045 mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
2047 mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2049 sc = MMF_CAMCORDER_SUBCONTEXT(handle);
2050 mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2051 mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
2053 info = sc->info_video;
2055 _mmcam_dbg_warn("start");
2057 /* create encoding pipeline */
2058 ret = _mmcamcorder_create_recorder_pipeline((MMHandleType)hcamcorder);
2059 if (ret != MM_ERROR_NONE)
2060 goto _ERR_PREPARE_RECORD;
2062 SAFE_G_FREE(info->filename);
2064 mm_camcorder_get_attributes(handle, NULL,
2065 MMCAM_TARGET_FILENAME, &temp_filename, &size,
2067 if (temp_filename) {
2068 info->filename = g_strdup(temp_filename);
2069 if (!info->filename) {
2070 _mmcam_dbg_err("strdup[src:%p] was failed", temp_filename);
2071 goto _ERR_PREPARE_RECORD;
2074 _mmcam_dbg_log("Record file name [%s]", info->filename);
2075 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename);
2077 _mmcam_dbg_log("Recorded data will be written in [%s]", _MMCamcorder_FILENAME_NULL);
2078 MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", _MMCamcorder_FILENAME_NULL);
2081 MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0);
2083 /* Adjust display FPS */
2084 sc->display_interval = 0;
2085 sc->previous_slot_time = 0;
2087 ret = _mmcamcorder_gst_set_state(handle, sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PAUSED);
2088 if (ret != MM_ERROR_NONE)
2089 goto _ERR_PREPARE_RECORD;
2091 _mmcam_dbg_warn("done");
2095 _ERR_PREPARE_RECORD:
2096 /* Remove recorder pipeline and recording file which size maybe zero */
2097 _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder);
2098 if (info && info->filename) {
2099 _mmcam_dbg_log("file delete(%s)", info->filename);
2100 unlink(info->filename);