4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hyuntae Kim <ht1211.kim@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 =======================================================================================*/
27 #include <sys/vfs.h> /* struct statfs */
29 #include "mm_streamrecorder_internal.h"
30 #include "mm_streamrecorder_gstdispatch.h"
31 #include "mm_streamrecorder_gstcommon.h"
32 #include "mm_streamrecorder_util.h"
33 #include "mm_streamrecorder_recorder.h"
35 /*-----------------------------------------------------------------------
36 | GLOBAL VARIABLE DEFINITIONS for internal |
37 -----------------------------------------------------------------------*/
39 #define _MMSTREAMRECORDER_MINIMUM_FRAME 5
40 #define _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL 5
41 #define _MMSTREAMRECORDER_MINIMUM_SPACE (512*1024) /* byte */
42 #define _MMSTREAMRECORDER_MMS_MARGIN_SPACE (512) /* byte */
43 #define _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL 10
44 #define _MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE (100*1024)
46 /*-----------------------------------------------------------------------
47 | LOCAL VARIABLE DEFINITIONS for internal |
48 -----------------------------------------------------------------------*/
50 /*---------------------------------------------------------------------------
51 | LOCAL FUNCTION PROTOTYPES: |
52 ---------------------------------------------------------------------------*/
53 /* STATIC INTERNAL FUNCTION */
55 /*===========================================================================================
57 | FUNCTION DEFINITIONS |
58 ========================================================================================== */
59 /*---------------------------------------------------------------------------
60 | GLOBAL FUNCTION DEFINITIONS: |
61 ---------------------------------------------------------------------------*/
62 void _mmstreamrecorder_remove_buffer_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
64 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
66 MMStreamRecorderHandlerItem *item = NULL;
68 mmf_return_if_fail(hstreamrecorder);
70 if (!hstreamrecorder->buffer_probes) {
71 _mmstreamrec_dbg_warn("list for buffer probe is NULL");
75 _mmstreamrec_dbg_log("start - category : 0x%x", category);
77 list = hstreamrecorder->buffer_probes;
81 _mmstreamrec_dbg_err("Remove buffer probe faild, the item is NULL");
82 list = g_list_next(list);
86 if (item->category & category) {
87 if (item->object && GST_IS_PAD(item->object)) {
88 _mmstreamrec_dbg_log("Remove buffer probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
89 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
91 _mmstreamrec_dbg_warn("Remove buffer probe faild, the pad is null or not pad, just remove item from list and free it");
94 list = g_list_next(list);
95 hstreamrecorder->buffer_probes = g_list_remove(hstreamrecorder->buffer_probes, item);
98 _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
99 list = g_list_next(list);
103 if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
104 g_list_free(hstreamrecorder->buffer_probes);
105 hstreamrecorder->buffer_probes = NULL;
108 _mmstreamrec_dbg_log("done");
113 void _mmstreamrecorder_remove_event_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
115 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
117 MMStreamRecorderHandlerItem *item = NULL;
119 mmf_return_if_fail(hstreamrecorder);
121 if (!hstreamrecorder->event_probes) {
122 _mmstreamrec_dbg_warn("list for event probe is NULL");
126 _mmstreamrec_dbg_log("start - category : 0x%x", category);
128 list = hstreamrecorder->event_probes;
132 _mmstreamrec_dbg_err("Remove event probe faild, the item is NULL");
133 list = g_list_next(list);
137 if (item->category & category) {
138 if (item->object && GST_IS_PAD(item->object)) {
139 _mmstreamrec_dbg_log("Remove event probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
140 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
142 _mmstreamrec_dbg_warn("Remove event probe faild, the pad is null or not pad, just remove item from list and free it");
145 list = g_list_next(list);
146 hstreamrecorder->event_probes = g_list_remove(hstreamrecorder->event_probes, item);
149 _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
150 list = g_list_next(list);
154 if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
155 g_list_free(hstreamrecorder->event_probes);
156 hstreamrecorder->event_probes = NULL;
159 _mmstreamrec_dbg_log("done");
164 void _mmstreamrecorder_remove_data_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
166 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
168 MMStreamRecorderHandlerItem *item = NULL;
170 mmf_return_if_fail(hstreamrecorder);
172 if (!hstreamrecorder->data_probes) {
173 _mmstreamrec_dbg_warn("list for data probe is NULL");
177 _mmstreamrec_dbg_log("start - category : 0x%x", category);
179 list = hstreamrecorder->data_probes;
183 _mmstreamrec_dbg_err("Remove data probe faild, the item is NULL");
184 list = g_list_next(list);
188 if (item->category & category) {
189 if (item->object && GST_IS_PAD(item->object)) {
190 _mmstreamrec_dbg_log("Remove data probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
191 gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
193 _mmstreamrec_dbg_warn("Remove data probe faild, the pad is null or not pad, just remove item from list and free it");
196 list = g_list_next(list);
197 hstreamrecorder->data_probes = g_list_remove(hstreamrecorder->data_probes, item);
200 _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
201 list = g_list_next(list);
205 if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
206 g_list_free(hstreamrecorder->data_probes);
207 hstreamrecorder->data_probes = NULL;
210 _mmstreamrec_dbg_log("done");
215 void _mmstreamrecorder_disconnect_signal(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
217 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
219 MMStreamRecorderHandlerItem *item = NULL;
221 mmf_return_if_fail(hstreamrecorder);
223 if (!hstreamrecorder->signals) {
224 _mmstreamrec_dbg_warn("list for signal is NULL");
228 _mmstreamrec_dbg_log("start - category : 0x%x", category);
230 list = hstreamrecorder->signals;
234 _mmstreamrec_dbg_err("Fail to Disconnecting signal, the item is NULL");
235 list = g_list_next(list);
239 if (item->category & category) {
240 if (item->object && GST_IS_ELEMENT(item->object)) {
241 if (g_signal_handler_is_connected(item->object, item->handler_id)) {
242 _mmstreamrec_dbg_log("Disconnect signal from [%s] : [ID : %lu], [Category : %x]", GST_OBJECT_NAME(item->object), item->handler_id, item->category);
243 g_signal_handler_disconnect(item->object, item->handler_id);
245 _mmstreamrec_dbg_warn("Signal was not connected, cannot disconnect it : [%s] [ID : %lu], [Category : %x]", GST_OBJECT_NAME(item->object), item->handler_id, item->category);
248 _mmstreamrec_dbg_err("Fail to Disconnecting signal, the element is null or not element, just remove item from list and free it");
251 list = g_list_next(list);
252 hstreamrecorder->signals = g_list_remove(hstreamrecorder->signals, item);
255 _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
256 list = g_list_next(list);
260 if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
261 g_list_free(hstreamrecorder->signals);
262 hstreamrecorder->signals = NULL;
265 _mmstreamrec_dbg_log("done");
270 void _mmstreamrecorder_element_release_noti(gpointer data, GObject *where_the_object_was)
273 _MMStreamRecorderSubContext *sc = (_MMStreamRecorderSubContext *) data;
275 mmf_return_if_fail(sc);
277 mmf_return_if_fail(sc->encode_element);
279 for (i = 0; i < _MMSTREAMRECORDER_ENCODE_PIPELINE_ELEMENT_NUM; i++) {
280 if (sc->encode_element[i].gst && (G_OBJECT(sc->encode_element[i].gst) == where_the_object_was)) {
281 _mmstreamrec_dbg_warn("The encode element[%d][%p] is finalized", sc->encode_element[i].id, sc->encode_element[i].gst);
282 sc->encode_element[i].gst = NULL;
283 sc->encode_element[i].id = _MMSTREAMRECORDER_ENCODE_NONE;
288 _mmstreamrec_dbg_warn("there is no matching element %p", where_the_object_was);
293 gboolean _mmstreamrecorder_msg_callback(void *data)
295 _MMStreamRecorderMsgItem *item = (_MMStreamRecorderMsgItem *) data;
296 mmf_streamrecorder_t *hstreamrecorder = NULL;
297 mmf_return_val_if_fail(item, FALSE);
299 hstreamrecorder = MMF_STREAMRECORDER(item->handle);
300 if (hstreamrecorder == NULL) {
301 _mmstreamrec_dbg_warn("msg id:0x%x, item:%p, handle is NULL", item->id, item);
302 goto MSG_CALLBACK_DONE;
305 _MMSTREAMRECORDER_LOCK((MMHandleType) hstreamrecorder);
306 if (hstreamrecorder->msg_data)
307 hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
309 _MMSTREAMRECORDER_UNLOCK((MMHandleType) hstreamrecorder);
311 /* _mmstreamrec_dbg_log("msg id:%x, msg_cb:%p, msg_data:%p, item:%p", item->id, hstreamrecorder->msg_cb, hstreamrecorder->msg_data, item); */
312 _MMSTREAMRECORDER_LOCK_MESSAGE_CALLBACK(hstreamrecorder);
314 if ((hstreamrecorder) && (hstreamrecorder->msg_cb))
315 hstreamrecorder->msg_cb(item->id, (MMMessageParamType *) (&(item->param)), hstreamrecorder->msg_cb_param);
317 _MMSTREAMRECORDER_UNLOCK_MESSAGE_CALLBACK(hstreamrecorder);
320 /* release allocated memory */
321 if (item->id == MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED ||
322 item->id == MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED) {
323 MMStreamRecordingReport *report = (MMStreamRecordingReport *)item->param.data;
325 SAFE_FREE(report->recording_filename);
327 item->param.data = NULL;
332 /* For not being called again */
336 void _mmstreamrecorder_remove_all_handlers(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
338 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
340 _mmstreamrec_dbg_log("ENTER");
342 if (hstreamrecorder->signals)
343 _mmstreamrecorder_disconnect_signal((MMHandleType) hstreamrecorder, category);
344 if (hstreamrecorder->data_probes)
345 _mmstreamrecorder_remove_data_probe((MMHandleType) hstreamrecorder, category);
346 if (hstreamrecorder->event_probes)
347 _mmstreamrecorder_remove_event_probe((MMHandleType) hstreamrecorder, category);
348 if (hstreamrecorder->buffer_probes)
349 _mmstreamrecorder_remove_buffer_probe((MMHandleType) hstreamrecorder, category);
351 _mmstreamrec_dbg_log("LEAVE");
354 gboolean _mmstreamrecorder_send_message(MMHandleType handle, _MMStreamRecorderMsgItem *data)
356 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
357 _MMStreamRecorderMsgItem *item = NULL;
359 mmf_return_val_if_fail(hstreamrecorder, FALSE);
360 mmf_return_val_if_fail(data, FALSE);
362 /* _mmstreamrec_dbg_err("ENTER"); */
364 /* _mmstreamrec_dbg_err("data->id = %x",data->id); */
367 case MM_MESSAGE_STREAMRECORDER_STATE_CHANGED:
368 data->param.union_type = MM_MSG_UNION_STATE;
370 case MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS:
371 data->param.union_type = MM_MSG_UNION_RECORDING_STATUS;
373 case MM_MESSAGE_STREAMRECORDER_CONSUME_COMPLETE: /* 0x801 */
374 data->param.union_type = MM_MSG_UNION_CONSUME_RECORDER_BUFFER;
376 case MM_MESSAGE_STREAMRECORDER_TIME_LIMIT:
377 case MM_MESSAGE_STREAMRECORDER_MAX_SIZE:
378 case MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE:
379 case MM_MESSAGE_STREAMRECORDER_ERROR:
380 case MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED:
381 case MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED:
382 case MM_MESSAGE_READY_TO_RESUME:
384 data->param.union_type = MM_MSG_UNION_CODE;
388 item = g_malloc(sizeof(_MMStreamRecorderMsgItem));
391 memcpy(item, data, sizeof(_MMStreamRecorderMsgItem));
392 item->handle = handle;
394 _MMSTREAMRECORDER_LOCK(handle);
395 hstreamrecorder->msg_data = g_list_append(hstreamrecorder->msg_data, item);
396 /* _mmstreamrec_dbg_log("item[%p]", item); */
398 /* Use DEFAULT priority */
399 g_idle_add_full(G_PRIORITY_DEFAULT, _mmstreamrecorder_msg_callback, item, NULL);
401 _MMSTREAMRECORDER_UNLOCK(handle);
406 gboolean _mmstreamrecorder_remove_message_all(MMHandleType handle)
408 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
409 _MMStreamRecorderMsgItem *item = NULL;
413 mmf_return_val_if_fail(hstreamrecorder, FALSE);
415 _MMSTREAMRECORDER_LOCK(handle);
417 if (hstreamrecorder->msg_data) {
418 list = hstreamrecorder->msg_data;
422 list = g_list_next(list);
425 ret = g_idle_remove_by_data(item);
426 _mmstreamrec_dbg_log("Remove item[%p]. ret[%d]", item, ret);
428 hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
434 g_list_free(hstreamrecorder->msg_data);
435 hstreamrecorder->msg_data = NULL;
439 _MMSTREAMRECORDER_UNLOCK(handle);
444 gboolean _mmstreamrecorder_handle_gst_error(MMHandleType handle, GstMessage *message, GError *error)
446 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
447 /* _MMstreamrecorderMsgItem msg; */
448 gchar *msg_src_element;
449 _MMStreamRecorderSubContext *sc = NULL;
451 return_val_if_fail(hstreamrecorder, FALSE);
452 return_val_if_fail(error, FALSE);
453 sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
454 mmf_return_val_if_fail(sc, FALSE);
456 _mmstreamrec_dbg_log("");
458 /* filtering filesink related errors */
459 if ((error->code == GST_RESOURCE_ERROR_WRITE || error->code == GST_RESOURCE_ERROR_SEEK)) {
460 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
461 sc->ferror_send = TRUE;
462 /* msg.param.code = __mmstreamrecorder_gst_handle_resource_error(handle, error->code, message); */
465 _mmstreamrec_dbg_warn("Skip error");
470 if (error->domain == GST_CORE_ERROR) {
471 /* msg.param.code = __mmstreamrecorder_gst_handle_core_error(handle, error->code, message); */
472 } else if (error->domain == GST_LIBRARY_ERROR) {
473 /* msg.param.code = __mmstreamrecorder_gst_handle_library_error(handle, error->code, message); */
474 } else if (error->domain == GST_RESOURCE_ERROR) {
475 /* msg.param.code = __mmstreamrecorder_gst_handle_resource_error(handle, error->code, message); */
476 } else if (error->domain == GST_STREAM_ERROR) {
477 /* msg.param.code = __mmstreamrecorder_gst_handle_stream_error(handle, error->code, message); */
479 _mmstreamrec_dbg_warn("This error domain is not defined.");
481 /* we treat system error as an internal error */
482 /* msg.param.code = MM_ERROR_streamrecorder_INTERNAL; */
486 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
487 /* _mmstreamrec_dbg_err("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
488 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg.param.code); */
490 /* _mmstreamrec_dbg_err("Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
491 g_quark_to_string (error->domain), error->message, error->code, msg.param.code); */
494 #ifdef _MMSTREAMRECORDER_SKIP_GST_FLOW_ERROR
495 /* Check whether send this error to application */
496 /* if (msg.param.code == MM_ERROR_streamrecorder_GST_FLOW_ERROR) {
497 _mmstreamrec_dbg_log("We got the error. But skip it.");
500 #endif /* _MMstreamrecorder_SKIP_GST_FLOW_ERROR */
502 /* post error to application */
503 sc->error_occurs = TRUE;
504 /* msg.id = MM_MESSAGE_streamrecorder_ERROR;
505 _mmstreamrecorder_send_message(handle, &msg); */
510 gint _mmstreamrecorder_gst_handle_core_error(MMHandleType handle, int code, GstMessage *message)
512 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
513 _MMStreamRecorderSubContext *sc = NULL;
514 GstElement *element = NULL;
516 _mmstreamrec_dbg_log("");
518 mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
520 sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
521 mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
523 /* Specific plugin - video encoder plugin */
524 element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
526 if (GST_ELEMENT_CAST(message->src) == element) {
527 if (code == GST_CORE_ERROR_NEGOTIATION)
528 return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
530 return MM_ERROR_STREAMRECORDER_ENCODER;
535 case GST_CORE_ERROR_STATE_CHANGE:
536 return MM_ERROR_STREAMRECORDER_GST_STATECHANGE;
537 case GST_CORE_ERROR_NEGOTIATION:
538 return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
539 case GST_CORE_ERROR_MISSING_PLUGIN:
540 case GST_CORE_ERROR_SEEK:
541 case GST_CORE_ERROR_NOT_IMPLEMENTED:
542 case GST_CORE_ERROR_FAILED:
543 case GST_CORE_ERROR_TOO_LAZY:
544 case GST_CORE_ERROR_PAD:
545 case GST_CORE_ERROR_THREAD:
546 case GST_CORE_ERROR_EVENT:
547 case GST_CORE_ERROR_CAPS:
548 case GST_CORE_ERROR_TAG:
549 case GST_CORE_ERROR_CLOCK:
550 case GST_CORE_ERROR_DISABLED:
552 return MM_ERROR_STREAMRECORDER_GST_CORE;
557 gint _mmstreamrecorder_gst_handle_library_error(MMHandleType handle, int code, GstMessage *message)
559 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
560 return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
562 _mmstreamrec_dbg_log("");
564 /* Specific plugin - NONE */
568 case GST_LIBRARY_ERROR_FAILED:
569 case GST_LIBRARY_ERROR_TOO_LAZY:
570 case GST_LIBRARY_ERROR_INIT:
571 case GST_LIBRARY_ERROR_SHUTDOWN:
572 case GST_LIBRARY_ERROR_SETTINGS:
573 case GST_LIBRARY_ERROR_ENCODE:
575 _mmstreamrec_dbg_err("Library error(%d)", code);
576 return MM_ERROR_STREAMRECORDER_GST_LIBRARY;
580 gint _mmstreamrecorder_gst_handle_resource_error(MMHandleType handle, int code, GstMessage *message)
582 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
583 _MMStreamRecorderSubContext *sc = NULL;
584 GstElement *element = NULL;
586 mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
588 sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
589 mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
591 _mmstreamrec_dbg_log("");
593 /* Specific plugin */
596 element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
597 if (GST_ELEMENT_CAST(message->src) == element) {
598 if (code == GST_RESOURCE_ERROR_FAILED) {
599 _mmstreamrec_dbg_err("Encoder [Resource error]");
600 return MM_ERROR_STREAMRECORDER_ENCODER_BUFFER;
602 _mmstreamrec_dbg_err("Encoder [General(%d)]", code);
603 return MM_ERROR_STREAMRECORDER_ENCODER;
609 case GST_RESOURCE_ERROR_WRITE:
610 _mmstreamrec_dbg_err("File write error");
611 return MM_ERROR_FILE_WRITE;
612 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
613 _mmstreamrec_dbg_err("No left space");
614 return MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
615 case GST_RESOURCE_ERROR_OPEN_WRITE:
616 _mmstreamrec_dbg_err("Out of storage");
617 return MM_ERROR_OUT_OF_STORAGE;
618 case GST_RESOURCE_ERROR_SEEK:
619 _mmstreamrec_dbg_err("File read(seek)");
620 return MM_ERROR_FILE_READ;
621 case GST_RESOURCE_ERROR_NOT_FOUND:
622 case GST_RESOURCE_ERROR_FAILED:
623 case GST_RESOURCE_ERROR_TOO_LAZY:
624 case GST_RESOURCE_ERROR_BUSY:
625 case GST_RESOURCE_ERROR_OPEN_READ:
626 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
627 case GST_RESOURCE_ERROR_CLOSE:
628 case GST_RESOURCE_ERROR_READ:
629 case GST_RESOURCE_ERROR_SYNC:
630 case GST_RESOURCE_ERROR_SETTINGS:
632 _mmstreamrec_dbg_err("Resource error(%d)", code);
633 return MM_ERROR_STREAMRECORDER_GST_RESOURCE;
637 gint _mmstreamrecorder_gst_handle_stream_error(MMHandleType handle, int code, GstMessage *message)
639 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
640 _MMStreamRecorderSubContext *sc = NULL;
641 GstElement *element = NULL;
643 mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
645 sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
646 mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
648 _mmstreamrec_dbg_log("");
650 /* Specific plugin */
652 element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
653 if (GST_ELEMENT_CAST(message->src) == element) {
655 case GST_STREAM_ERROR_WRONG_TYPE:
656 _mmstreamrec_dbg_err("Video encoder [wrong stream type]");
657 return MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE;
658 case GST_STREAM_ERROR_ENCODE:
659 _mmstreamrec_dbg_err("Video encoder [encode error]");
660 return MM_ERROR_STREAMRECORDER_ENCODER_WORKING;
661 case GST_STREAM_ERROR_FAILED:
662 _mmstreamrec_dbg_err("Video encoder [stream failed]");
663 return MM_ERROR_STREAMRECORDER_ENCODER_WORKING;
665 _mmstreamrec_dbg_err("Video encoder [General(%d)]", code);
666 return MM_ERROR_STREAMRECORDER_ENCODER;
672 case GST_STREAM_ERROR_FORMAT:
673 _mmstreamrec_dbg_err("General [negotiation error(%d)]", code);
674 return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
675 case GST_STREAM_ERROR_FAILED:
676 _mmstreamrec_dbg_err("General [flow error(%d)]", code);
677 return MM_ERROR_STREAMRECORDER_GST_FLOW_ERROR;
678 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
679 case GST_STREAM_ERROR_DECODE:
680 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
681 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
682 case GST_STREAM_ERROR_TOO_LAZY:
683 case GST_STREAM_ERROR_ENCODE:
684 case GST_STREAM_ERROR_DEMUX:
685 case GST_STREAM_ERROR_MUX:
686 case GST_STREAM_ERROR_DECRYPT:
687 case GST_STREAM_ERROR_DECRYPT_NOKEY:
688 case GST_STREAM_ERROR_WRONG_TYPE:
690 _mmstreamrec_dbg_err("General [error(%d)]", code);
691 return MM_ERROR_STREAMRECORDER_GST_STREAM;
695 gboolean _mmstreamrecorder_handle_gst_warning(MMHandleType handle, GstMessage *message, GError *error)
697 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
701 return_val_if_fail(hstreamrecorder, FALSE);
702 return_val_if_fail(error, FALSE);
704 _mmstreamrec_dbg_log("");
706 gst_message_parse_warning(message, &err, &debug);
708 if (error->domain == GST_CORE_ERROR) {
709 _mmstreamrec_dbg_warn("GST warning: GST_CORE domain");
710 } else if (error->domain == GST_LIBRARY_ERROR) {
711 _mmstreamrec_dbg_warn("GST warning: GST_LIBRARY domain");
712 } else if (error->domain == GST_RESOURCE_ERROR) {
713 _mmstreamrec_dbg_warn("GST warning: GST_RESOURCE domain");
714 /* _mmstreamrecorder_gst_handle_resource_warning(handle, message, error); */
715 } else if (error->domain == GST_STREAM_ERROR) {
716 _mmstreamrec_dbg_warn("GST warning: GST_STREAM domain");
718 _mmstreamrec_dbg_warn("This error domain(%d) is not defined.", error->domain);
726 _mmstreamrec_dbg_err("Debug: %s", debug);
734 gboolean _mmstreamrecorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpointer data)
736 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(data);
737 /* _MMstreamrecorderMsgItem msg; */
738 _MMStreamRecorderSubContext *sc = NULL;
740 mmf_return_val_if_fail(hstreamrecorder, FALSE);
741 mmf_return_val_if_fail(message, FALSE);
742 /* _mmstreamrec_dbg_log("message type=(%d)", GST_MESSAGE_TYPE(message)); */
744 switch (GST_MESSAGE_TYPE(message)) {
745 case GST_MESSAGE_UNKNOWN:
746 _mmstreamrec_dbg_log("GST_MESSAGE_UNKNOWN");
748 case GST_MESSAGE_EOS:
750 _mmstreamrec_dbg_log("Got EOS from element \"%s\".", GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
752 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
753 mmf_return_val_if_fail(sc, TRUE);
755 mmf_return_val_if_fail(sc->info_video, TRUE);
756 if (sc->info_video->b_commiting)
757 _mmstreamrecorder_video_handle_eos((MMHandleType) hstreamrecorder);
763 case GST_MESSAGE_ERROR:
767 gst_message_parse_error(message, &err, &debug);
769 _mmstreamrec_dbg_err("GSTERR: %s", err->message);
770 _mmstreamrec_dbg_err("Error Debug: %s", debug);
772 _mmstreamrecorder_handle_gst_error((MMHandleType) hstreamrecorder, message, err);
778 case GST_MESSAGE_WARNING:
782 gst_message_parse_warning(message, &err, &debug);
784 _mmstreamrec_dbg_warn("GSTWARN: %s", err->message);
786 _mmstreamrecorder_handle_gst_warning((MMHandleType) hstreamrecorder, message, err);
792 case GST_MESSAGE_INFO:
793 _mmstreamrec_dbg_log("GST_MESSAGE_INFO");
795 case GST_MESSAGE_TAG:
796 _mmstreamrec_dbg_log("GST_MESSAGE_TAG");
798 case GST_MESSAGE_BUFFERING:
799 _mmstreamrec_dbg_log("GST_MESSAGE_BUFFERING");
801 case GST_MESSAGE_STATE_CHANGED:
803 const GValue *vnewstate;
805 GstElement *pipeline = NULL;
807 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
808 if ((sc) && (sc->encode_element)) {
809 if (sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst) {
810 pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
811 if (message->src == (GstObject *) pipeline) {
812 vnewstate = (GValue *) gst_structure_get_value(gst_message_get_structure(message), "new-state");
813 newstate = (GstState) vnewstate->data[0].v_int;
814 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_CHANGED[%s]", gst_element_state_get_name(newstate));
820 case GST_MESSAGE_STATE_DIRTY:
821 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_DIRTY");
823 case GST_MESSAGE_STEP_DONE:
824 _mmstreamrec_dbg_log("GST_MESSAGE_STEP_DONE");
826 case GST_MESSAGE_CLOCK_PROVIDE:
827 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_PROVIDE");
829 case GST_MESSAGE_CLOCK_LOST:
830 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_LOST");
832 case GST_MESSAGE_NEW_CLOCK:
835 gst_message_parse_new_clock(message, &l_clock);
836 _mmstreamrec_dbg_log("GST_MESSAGE_NEW_CLOCK : %s", (l_clock ? GST_OBJECT_NAME(l_clock) : "NULL"));
839 case GST_MESSAGE_STRUCTURE_CHANGE:
840 _mmstreamrec_dbg_log("GST_MESSAGE_STRUCTURE_CHANGE");
842 case GST_MESSAGE_STREAM_STATUS:
843 _mmstreamrec_dbg_log("GST_MESSAGE_STREAM_STATUS");
845 case GST_MESSAGE_APPLICATION:
846 _mmstreamrec_dbg_log("GST_MESSAGE_APPLICATION");
848 case GST_MESSAGE_ELEMENT:
849 _mmstreamrec_dbg_log("GST_MESSAGE_ELEMENT");
851 case GST_MESSAGE_SEGMENT_START:
852 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_START");
854 case GST_MESSAGE_SEGMENT_DONE:
855 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_DONE");
857 case GST_MESSAGE_DURATION:
858 _mmstreamrec_dbg_log("GST_MESSAGE_DURATION");
860 case GST_MESSAGE_LATENCY:
861 _mmstreamrec_dbg_log("GST_MESSAGE_LATENCY");
863 case GST_MESSAGE_ASYNC_START:
864 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_START");
866 case GST_MESSAGE_ASYNC_DONE:
867 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_DONE");
869 case GST_MESSAGE_ANY:
870 _mmstreamrec_dbg_log("GST_MESSAGE_ANY");
873 _mmstreamrec_dbg_log("not handled message type=(%d)", GST_MESSAGE_TYPE(message));
881 * This function is record video data probing function.
882 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
883 * this function will be called when data stream pass through the pad.
885 * @param[in] pad probing pad which calls this function.
886 * @param[in] buffer buffer which contains stream data.
887 * @param[in] u_data user data.
888 * @return This function returns true on success, or false value with error
892 GstPadProbeReturn __mmstreamrecorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
894 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
895 switch (GST_EVENT_TYPE(event)) {
896 case GST_EVENT_UNKNOWN:
897 /* upstream events */
900 case GST_EVENT_NAVIGATION:
901 case GST_EVENT_LATENCY:
902 /* downstream serialized events */
903 case GST_EVENT_SEGMENT:
905 case GST_EVENT_BUFFERSIZE:
906 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
909 _mmstreamrec_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
911 /* bidirectional events */
912 case GST_EVENT_FLUSH_START:
913 case GST_EVENT_FLUSH_STOP:
914 _mmstreamrec_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
917 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
921 return GST_PAD_PROBE_OK;
924 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
926 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
927 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
928 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
929 guint64 buffer_size = 0;
931 _MMStreamRecorderSubContext *sc = NULL;
932 _MMStreamRecorderAudioInfo *audioinfo = NULL;
934 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
935 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
936 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
938 mmf_return_val_if_fail(sc && sc->info_audio, GST_PAD_PROBE_OK);
939 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
941 audioinfo = sc->info_audio;
943 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
944 buffer_size = mapinfo.size;
945 gst_buffer_unmap(buffer, &mapinfo);
947 /*_mmstreamrec_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
949 if (audioinfo->audio_frame_count == 0) {
950 audioinfo->filesize += buffer_size;
951 audioinfo->audio_frame_count++;
952 return GST_PAD_PROBE_OK;
955 if (sc->ferror_send || sc->isMaxsizePausing) {
956 _mmstreamrec_dbg_warn("Recording is paused, drop frames");
957 return GST_PAD_PROBE_DROP;
960 audioinfo->filesize += buffer_size;
961 audioinfo->audio_frame_count++;
963 return GST_PAD_PROBE_OK;
966 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
968 static int count = 0;
972 guint64 free_space = 0;
973 guint64 buffer_size = 0;
974 guint64 trailer_size = 0;
975 guint64 queued_buffer = 0;
976 char *filename = NULL;
977 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
978 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
980 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
981 _MMStreamRecorderMsgItem msg;
982 _MMStreamRecorderSubContext *sc = NULL;
983 _MMStreamRecorderVideoInfo *videoinfo = NULL;
984 _MMStreamRecorderFileInfo *finfo = NULL;
986 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
987 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
989 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
990 mmf_return_val_if_fail(sc && sc->info_video && sc->info_file, TRUE);
991 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
993 videoinfo = sc->info_video;
994 finfo = sc->info_file;
996 /*_mmstreamrec_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
997 if (sc->ferror_send) {
998 _mmstreamrec_dbg_warn("file write error, drop frames");
999 return GST_PAD_PROBE_DROP;
1001 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1002 buffer_size = mapinfo.size;
1003 gst_buffer_unmap(buffer, &mapinfo);
1005 videoinfo->video_frame_count++;
1006 if (videoinfo->video_frame_count <= (guint64) _MMSTREAMRECORDER_MINIMUM_FRAME) {
1007 /* _mmstreamrec_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ", info->video_frame_count); */
1008 videoinfo->filesize += buffer_size;
1009 return GST_PAD_PROBE_OK;
1012 /* get trailer size */
1013 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1014 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1018 /* to minimizing free space check overhead */
1019 count = count % _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL;
1021 filename = finfo->filename;
1022 ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1024 /*_mmstreamrec_dbg_log("check free space for recording");*/
1027 case -2: /* file not exist */
1028 case -1: /* failed to get free space */
1029 _mmstreamrec_dbg_err("Error occured. [%d]", ret);
1030 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1031 sc->ferror_send = TRUE;
1032 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1034 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1036 msg.param.code = MM_ERROR_FILE_READ;
1038 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1043 return GST_PAD_PROBE_DROP; /* skip this buffer */
1045 default: /* succeeded to get free space */
1046 /* check free space for recording */
1047 /* get queued buffer size */
1048 if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst)
1049 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1051 if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst)
1052 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1054 queued_buffer = aq_size + vq_size;
1056 /* check free space */
1057 if (free_space < (_MMSTREAMRECORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1058 _mmstreamrec_dbg_warn("No more space for recording!!! Recording is paused.");
1059 _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", free_space, trailer_size, buffer_size, queued_buffer);
1061 if (!sc->isMaxsizePausing) {
1062 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1063 sc->isMaxsizePausing = TRUE;
1065 msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1066 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1069 return GST_PAD_PROBE_DROP;
1075 videoinfo->filesize += (guint64) buffer_size;
1078 _mmstreamrec_dbg_log("filesize %lld Byte, ", info->filesize);
1081 return GST_PAD_PROBE_OK;
1084 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1086 guint64 trailer_size = 0;
1087 guint64 rec_pipe_time = 0;
1088 unsigned int remained_time = 0;
1090 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1091 GstClockTime b_time;
1093 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1094 _MMStreamRecorderMsgItem msg;
1095 _MMStreamRecorderSubContext *sc = NULL;
1096 _MMStreamRecorderVideoInfo *videoinfo = NULL;
1097 _MMStreamRecorderFileInfo *finfo = NULL;
1099 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1100 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1102 sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1103 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1104 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1105 mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1107 videoinfo = sc->info_video;
1108 finfo = sc->info_file;
1110 b_time = GST_BUFFER_TIMESTAMP(buffer);
1112 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1114 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1115 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1119 /* check max time */
1120 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1121 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1123 if (!sc->isMaxtimePausing) {
1124 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1126 sc->isMaxtimePausing = TRUE;
1128 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1129 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1130 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1131 msg.param.recording_status.remained_time = 0;
1132 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1134 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1135 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1138 return GST_PAD_PROBE_DROP;
1141 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1142 remained_time = videoinfo->max_time - rec_pipe_time;
1144 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1145 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1146 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1147 msg.param.recording_status.remained_time = remained_time;
1148 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1151 _mmstreamrec_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1152 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1155 return GST_PAD_PROBE_OK;
1158 GstPadProbeReturn __mmstreamrecorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1160 _MMStreamRecorderMsgItem msg;
1161 guint64 trailer_size = 0;
1162 guint64 rec_pipe_time = 0;
1163 _MMStreamRecorderSubContext *sc = NULL;
1164 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1165 _MMStreamRecorderVideoInfo *videoinfo = NULL;
1166 _MMStreamRecorderFileInfo *finfo = NULL;
1167 unsigned int remained_time = 0;
1168 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1170 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1171 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1172 sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1174 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1175 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1176 mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1178 videoinfo = sc->info_video;
1179 finfo = sc->info_file;
1181 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1182 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1183 return GST_PAD_PROBE_OK;
1186 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1188 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1189 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1193 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1194 remained_time = videoinfo->max_time - rec_pipe_time;
1196 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1197 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1199 if (!sc->isMaxtimePausing) {
1200 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1202 sc->isMaxtimePausing = TRUE;
1204 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1205 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1206 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1207 msg.param.recording_status.remained_time = 0;
1208 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1210 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1211 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1214 return GST_PAD_PROBE_DROP;
1217 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1218 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1219 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1220 msg.param.recording_status.remained_time = remained_time;
1221 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1224 _mmstreamrec_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1225 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1228 return GST_PAD_PROBE_OK;
1231 void __mmstreamrecorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle)
1233 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
1235 _mmstreamrec_dbg_log("ENTER(%s)", GST_PAD_NAME(pad));
1236 /* FIXME : the name of audio sink pad of wavparse, oggmux doesn't have 'audio'. How could I handle the name? */
1237 if ((strstr(GST_PAD_NAME(pad), "audio")) || (strstr(GST_PAD_NAME(pad), "sink")))
1238 MMSTREAMRECORDER_ADD_BUFFER_PROBE(pad, _MMSTREAMRECORDER_HANDLER_AUDIOREC, __mmstreamrecorder_audio_dataprobe_record, hstreamrecorder);
1240 _mmstreamrec_dbg_warn("Unknow pad is added, check it : [%s]", GST_PAD_NAME(pad));
1245 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1247 static int count = 0;
1248 guint64 rec_pipe_time = 0;
1249 guint64 free_space = 0;
1250 guint64 buffer_size = 0;
1251 guint64 trailer_size = 0;
1252 char *filename = NULL;
1253 unsigned long long remained_time = 0;
1254 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1256 _MMStreamRecorderSubContext *sc = NULL;
1257 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1258 _MMStreamRecorderAudioInfo *audioinfo = NULL;
1259 _MMStreamRecorderFileInfo *finfo = NULL;
1260 _MMStreamRecorderMsgItem msg;
1262 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_DROP);
1263 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1265 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
1266 mmf_return_val_if_fail(sc && sc->info_audio && sc->info_file, FALSE);
1267 audioinfo = sc->info_audio;
1268 finfo = sc->info_file;
1270 if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
1271 _mmstreamrec_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]", sc->isMaxtimePausing, sc->isMaxsizePausing);
1272 return GST_PAD_PROBE_DROP;
1275 buffer_size = gst_buffer_get_size(buffer);
1277 if (audioinfo->filesize == 0) {
1278 if (finfo->fileformat == MM_FILE_FORMAT_WAV)
1279 audioinfo->filesize += 44; /* wave header size */
1280 else if (finfo->fileformat == MM_FILE_FORMAT_AMR)
1281 audioinfo->filesize += 6; /* amr header size */
1283 audioinfo->filesize += buffer_size;
1284 return GST_PAD_PROBE_OK;
1287 if (sc->ferror_send) {
1288 _mmstreamrec_dbg_warn("file write error, drop frames");
1289 return GST_PAD_PROBE_DROP;
1292 /* get trailer size */
1293 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4 || finfo->fileformat == MM_FILE_FORMAT_AAC) {
1294 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1295 /*_mmstreamrec_dbg_log("trailer_size %d", trailer_size);*/
1297 trailer_size = 0; /* no trailer */
1300 filename = finfo->filename;
1302 /* to minimizing free space check overhead */
1303 count = count % _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL;
1305 gint free_space_ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1307 /*_mmstreamrec_dbg_log("check free space for recording");*/
1309 switch (free_space_ret) {
1310 case -2: /* file not exist */
1311 case -1: /* failed to get free space */
1312 _mmstreamrec_dbg_err("Error occured. [%d]", free_space_ret);
1313 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1314 sc->ferror_send = TRUE;
1315 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1316 if (free_space_ret == -2)
1317 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1319 msg.param.code = MM_ERROR_FILE_READ;
1321 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1326 return GST_PAD_PROBE_DROP; /* skip this buffer */
1328 default: /* succeeded to get free space */
1329 /* check free space for recording */
1330 if (free_space < (guint64) (_MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) {
1331 _mmstreamrec_dbg_warn("No more space for recording!!!");
1332 _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]", free_space, audioinfo->filesize);
1334 if (audioinfo->bMuxing)
1335 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1337 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1339 sc->isMaxsizePausing = TRUE;
1340 msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1341 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1343 return FALSE; /* skip this buffer */
1349 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1350 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1351 return GST_PAD_PROBE_DROP;
1354 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1356 if (audioinfo->max_time > 0 && audioinfo->max_time < (remained_time + rec_pipe_time))
1357 remained_time = audioinfo->max_time - rec_pipe_time;
1359 /*_mmstreamrec_dbg_log("remained time : %u", remained_time);*/
1361 /* check recording time limit and send recording status message */
1362 if (audioinfo->max_time > 0 && rec_pipe_time > audioinfo->max_time) {
1363 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, audioinfo->max_time);
1365 if (audioinfo->bMuxing)
1366 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1368 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1370 sc->isMaxtimePausing = TRUE;
1371 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1372 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1374 /* skip this buffer */
1375 return GST_PAD_PROBE_DROP;
1378 /* send message for recording time and recorded file size */
1379 if (audioinfo->b_commiting == FALSE) {
1380 audioinfo->filesize += buffer_size;
1382 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1383 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1384 msg.param.recording_status.filesize = (unsigned long long)((audioinfo->filesize + trailer_size) >> 10);
1385 msg.param.recording_status.remained_time = remained_time;
1386 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1388 return GST_PAD_PROBE_OK;
1390 /* skip this buffer if commit process has been started */
1391 return GST_PAD_PROBE_DROP;