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));
815 if (newstate == GST_STATE_PLAYING) {
816 if (hstreamrecorder->ini.generate_dot) {
817 GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), GST_DEBUG_GRAPH_SHOW_ALL, "streamrecorder_pipeline");
825 case GST_MESSAGE_STATE_DIRTY:
826 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_DIRTY");
828 case GST_MESSAGE_STEP_DONE:
829 _mmstreamrec_dbg_log("GST_MESSAGE_STEP_DONE");
831 case GST_MESSAGE_CLOCK_PROVIDE:
832 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_PROVIDE");
834 case GST_MESSAGE_CLOCK_LOST:
835 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_LOST");
837 case GST_MESSAGE_NEW_CLOCK:
840 gst_message_parse_new_clock(message, &l_clock);
841 _mmstreamrec_dbg_log("GST_MESSAGE_NEW_CLOCK : %s", (l_clock ? GST_OBJECT_NAME(l_clock) : "NULL"));
844 case GST_MESSAGE_STRUCTURE_CHANGE:
845 _mmstreamrec_dbg_log("GST_MESSAGE_STRUCTURE_CHANGE");
847 case GST_MESSAGE_STREAM_STATUS:
848 _mmstreamrec_dbg_log("GST_MESSAGE_STREAM_STATUS");
850 case GST_MESSAGE_APPLICATION:
851 _mmstreamrec_dbg_log("GST_MESSAGE_APPLICATION");
853 case GST_MESSAGE_ELEMENT:
854 _mmstreamrec_dbg_log("GST_MESSAGE_ELEMENT");
856 case GST_MESSAGE_SEGMENT_START:
857 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_START");
859 case GST_MESSAGE_SEGMENT_DONE:
860 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_DONE");
862 case GST_MESSAGE_DURATION:
863 _mmstreamrec_dbg_log("GST_MESSAGE_DURATION");
865 case GST_MESSAGE_LATENCY:
866 _mmstreamrec_dbg_log("GST_MESSAGE_LATENCY");
868 case GST_MESSAGE_ASYNC_START:
869 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_START");
871 case GST_MESSAGE_ASYNC_DONE:
872 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_DONE");
874 case GST_MESSAGE_ANY:
875 _mmstreamrec_dbg_log("GST_MESSAGE_ANY");
878 _mmstreamrec_dbg_log("not handled message type=(%d)", GST_MESSAGE_TYPE(message));
886 * This function is record video data probing function.
887 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
888 * this function will be called when data stream pass through the pad.
890 * @param[in] pad probing pad which calls this function.
891 * @param[in] buffer buffer which contains stream data.
892 * @param[in] u_data user data.
893 * @return This function returns true on success, or false value with error
897 GstPadProbeReturn __mmstreamrecorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
899 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
900 switch (GST_EVENT_TYPE(event)) {
901 case GST_EVENT_UNKNOWN:
902 /* upstream events */
905 case GST_EVENT_NAVIGATION:
906 case GST_EVENT_LATENCY:
907 /* downstream serialized events */
908 case GST_EVENT_SEGMENT:
910 case GST_EVENT_BUFFERSIZE:
911 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
914 _mmstreamrec_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
916 /* bidirectional events */
917 case GST_EVENT_FLUSH_START:
918 case GST_EVENT_FLUSH_STOP:
919 _mmstreamrec_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
922 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
926 return GST_PAD_PROBE_OK;
929 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
931 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
932 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
933 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
934 guint64 buffer_size = 0;
936 _MMStreamRecorderSubContext *sc = NULL;
937 _MMStreamRecorderAudioInfo *audioinfo = NULL;
939 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
940 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
941 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
943 mmf_return_val_if_fail(sc && sc->info_audio, GST_PAD_PROBE_OK);
944 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
946 audioinfo = sc->info_audio;
948 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
949 buffer_size = mapinfo.size;
950 gst_buffer_unmap(buffer, &mapinfo);
952 /*_mmstreamrec_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
954 if (audioinfo->audio_frame_count == 0) {
955 audioinfo->filesize += buffer_size;
956 audioinfo->audio_frame_count++;
957 return GST_PAD_PROBE_OK;
960 if (sc->ferror_send || sc->isMaxsizePausing) {
961 _mmstreamrec_dbg_warn("Recording is paused, drop frames");
962 return GST_PAD_PROBE_DROP;
965 audioinfo->filesize += buffer_size;
966 audioinfo->audio_frame_count++;
968 return GST_PAD_PROBE_OK;
971 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
973 static int count = 0;
977 guint64 free_space = 0;
978 guint64 buffer_size = 0;
979 guint64 trailer_size = 0;
980 guint64 queued_buffer = 0;
981 char *filename = NULL;
982 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
983 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
985 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
986 _MMStreamRecorderMsgItem msg;
987 _MMStreamRecorderSubContext *sc = NULL;
988 _MMStreamRecorderVideoInfo *videoinfo = NULL;
989 _MMStreamRecorderFileInfo *finfo = NULL;
991 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
992 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
994 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
995 mmf_return_val_if_fail(sc && sc->info_video && sc->info_file, TRUE);
996 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
998 videoinfo = sc->info_video;
999 finfo = sc->info_file;
1001 /*_mmstreamrec_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
1002 if (sc->ferror_send) {
1003 _mmstreamrec_dbg_warn("file write error, drop frames");
1004 return GST_PAD_PROBE_DROP;
1006 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1007 buffer_size = mapinfo.size;
1008 gst_buffer_unmap(buffer, &mapinfo);
1010 videoinfo->video_frame_count++;
1011 if (videoinfo->video_frame_count <= (guint64) _MMSTREAMRECORDER_MINIMUM_FRAME) {
1012 /* _mmstreamrec_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ", info->video_frame_count); */
1013 videoinfo->filesize += buffer_size;
1014 return GST_PAD_PROBE_OK;
1017 /* get trailer size */
1018 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1019 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1023 /* to minimizing free space check overhead */
1024 count = count % _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL;
1026 filename = finfo->filename;
1027 ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1029 /*_mmstreamrec_dbg_log("check free space for recording");*/
1032 case -2: /* file not exist */
1033 case -1: /* failed to get free space */
1034 _mmstreamrec_dbg_err("Error occured. [%d]", ret);
1035 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1036 sc->ferror_send = TRUE;
1037 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1039 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1041 msg.param.code = MM_ERROR_FILE_READ;
1043 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1048 return GST_PAD_PROBE_DROP; /* skip this buffer */
1050 default: /* succeeded to get free space */
1051 /* check free space for recording */
1052 /* get queued buffer size */
1053 if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst)
1054 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1056 if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst)
1057 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1059 queued_buffer = aq_size + vq_size;
1061 /* check free space */
1062 if (free_space < (_MMSTREAMRECORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1063 _mmstreamrec_dbg_warn("No more space for recording!!! Recording is paused.");
1064 _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);
1066 if (!sc->isMaxsizePausing) {
1067 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1068 sc->isMaxsizePausing = TRUE;
1070 msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1071 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1074 return GST_PAD_PROBE_DROP;
1080 videoinfo->filesize += (guint64) buffer_size;
1083 _mmstreamrec_dbg_log("filesize %lld Byte, ", info->filesize);
1086 return GST_PAD_PROBE_OK;
1089 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1091 guint64 trailer_size = 0;
1092 guint64 rec_pipe_time = 0;
1093 unsigned int remained_time = 0;
1095 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1096 GstClockTime b_time;
1098 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1099 _MMStreamRecorderMsgItem msg;
1100 _MMStreamRecorderSubContext *sc = NULL;
1101 _MMStreamRecorderVideoInfo *videoinfo = NULL;
1102 _MMStreamRecorderFileInfo *finfo = NULL;
1104 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1105 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1107 sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1108 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1109 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1110 mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1112 videoinfo = sc->info_video;
1113 finfo = sc->info_file;
1115 b_time = GST_BUFFER_TIMESTAMP(buffer);
1117 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1119 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1120 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1124 /* check max time */
1125 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1126 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1128 if (!sc->isMaxtimePausing) {
1129 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1131 sc->isMaxtimePausing = TRUE;
1133 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1134 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1135 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1136 msg.param.recording_status.remained_time = 0;
1137 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1139 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1140 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1143 return GST_PAD_PROBE_DROP;
1146 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1147 remained_time = videoinfo->max_time - rec_pipe_time;
1149 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1150 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1151 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1152 msg.param.recording_status.remained_time = remained_time;
1153 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1156 _mmstreamrec_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1157 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1160 return GST_PAD_PROBE_OK;
1163 GstPadProbeReturn __mmstreamrecorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1165 _MMStreamRecorderMsgItem msg;
1166 guint64 trailer_size = 0;
1167 guint64 rec_pipe_time = 0;
1168 _MMStreamRecorderSubContext *sc = NULL;
1169 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1170 _MMStreamRecorderVideoInfo *videoinfo = NULL;
1171 _MMStreamRecorderFileInfo *finfo = NULL;
1172 unsigned int remained_time = 0;
1173 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1175 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1176 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1177 sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1179 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1180 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1181 mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1183 videoinfo = sc->info_video;
1184 finfo = sc->info_file;
1186 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1187 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1188 return GST_PAD_PROBE_OK;
1191 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1193 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
1194 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1198 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1199 remained_time = videoinfo->max_time - rec_pipe_time;
1201 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1202 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1204 if (!sc->isMaxtimePausing) {
1205 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1207 sc->isMaxtimePausing = TRUE;
1209 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1210 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1211 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1212 msg.param.recording_status.remained_time = 0;
1213 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1215 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1216 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1219 return GST_PAD_PROBE_DROP;
1222 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1223 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1224 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1225 msg.param.recording_status.remained_time = remained_time;
1226 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1229 _mmstreamrec_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1230 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1233 return GST_PAD_PROBE_OK;
1236 void __mmstreamrecorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle)
1238 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
1240 _mmstreamrec_dbg_log("ENTER(%s)", GST_PAD_NAME(pad));
1241 /* FIXME : the name of audio sink pad of wavparse, oggmux doesn't have 'audio'. How could I handle the name? */
1242 if ((strstr(GST_PAD_NAME(pad), "audio")) || (strstr(GST_PAD_NAME(pad), "sink")))
1243 MMSTREAMRECORDER_ADD_BUFFER_PROBE(pad, _MMSTREAMRECORDER_HANDLER_AUDIOREC, __mmstreamrecorder_audio_dataprobe_record, hstreamrecorder);
1245 _mmstreamrec_dbg_warn("Unknow pad is added, check it : [%s]", GST_PAD_NAME(pad));
1250 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1252 static int count = 0;
1253 guint64 rec_pipe_time = 0;
1254 guint64 free_space = 0;
1255 guint64 buffer_size = 0;
1256 guint64 trailer_size = 0;
1257 char *filename = NULL;
1258 unsigned long long remained_time = 0;
1259 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1261 _MMStreamRecorderSubContext *sc = NULL;
1262 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1263 _MMStreamRecorderAudioInfo *audioinfo = NULL;
1264 _MMStreamRecorderFileInfo *finfo = NULL;
1265 _MMStreamRecorderMsgItem msg;
1267 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_DROP);
1268 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1270 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
1271 mmf_return_val_if_fail(sc && sc->info_audio && sc->info_file, FALSE);
1272 audioinfo = sc->info_audio;
1273 finfo = sc->info_file;
1275 if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
1276 _mmstreamrec_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]", sc->isMaxtimePausing, sc->isMaxsizePausing);
1277 return GST_PAD_PROBE_DROP;
1280 buffer_size = gst_buffer_get_size(buffer);
1282 if (audioinfo->filesize == 0) {
1283 if (finfo->fileformat == MM_FILE_FORMAT_WAV)
1284 audioinfo->filesize += 44; /* wave header size */
1285 else if (finfo->fileformat == MM_FILE_FORMAT_AMR)
1286 audioinfo->filesize += 6; /* amr header size */
1288 audioinfo->filesize += buffer_size;
1289 return GST_PAD_PROBE_OK;
1292 if (sc->ferror_send) {
1293 _mmstreamrec_dbg_warn("file write error, drop frames");
1294 return GST_PAD_PROBE_DROP;
1297 /* get trailer size */
1298 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4 || finfo->fileformat == MM_FILE_FORMAT_AAC) {
1299 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1300 /*_mmstreamrec_dbg_log("trailer_size %d", trailer_size);*/
1302 trailer_size = 0; /* no trailer */
1305 filename = finfo->filename;
1307 /* to minimizing free space check overhead */
1308 count = count % _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL;
1310 gint free_space_ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1312 /*_mmstreamrec_dbg_log("check free space for recording");*/
1314 switch (free_space_ret) {
1315 case -2: /* file not exist */
1316 case -1: /* failed to get free space */
1317 _mmstreamrec_dbg_err("Error occured. [%d]", free_space_ret);
1318 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1319 sc->ferror_send = TRUE;
1320 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1321 if (free_space_ret == -2)
1322 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1324 msg.param.code = MM_ERROR_FILE_READ;
1326 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1331 return GST_PAD_PROBE_DROP; /* skip this buffer */
1333 default: /* succeeded to get free space */
1334 /* check free space for recording */
1335 if (free_space < (guint64) (_MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) {
1336 _mmstreamrec_dbg_warn("No more space for recording!!!");
1337 _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]", free_space, audioinfo->filesize);
1339 if (audioinfo->bMuxing)
1340 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1342 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1344 sc->isMaxsizePausing = TRUE;
1345 msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1346 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1348 return FALSE; /* skip this buffer */
1354 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1355 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1356 return GST_PAD_PROBE_DROP;
1359 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1361 if (audioinfo->max_time > 0 && audioinfo->max_time < (remained_time + rec_pipe_time))
1362 remained_time = audioinfo->max_time - rec_pipe_time;
1364 /*_mmstreamrec_dbg_log("remained time : %u", remained_time);*/
1366 /* check recording time limit and send recording status message */
1367 if (audioinfo->max_time > 0 && rec_pipe_time > audioinfo->max_time) {
1368 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, audioinfo->max_time);
1370 if (audioinfo->bMuxing)
1371 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1373 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1375 sc->isMaxtimePausing = TRUE;
1376 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1377 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1379 /* skip this buffer */
1380 return GST_PAD_PROBE_DROP;
1383 /* send message for recording time and recorded file size */
1384 if (audioinfo->b_commiting == FALSE) {
1385 audioinfo->filesize += buffer_size;
1387 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1388 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1389 msg.param.recording_status.filesize = (unsigned long long)((audioinfo->filesize + trailer_size) >> 10);
1390 msg.param.recording_status.remained_time = remained_time;
1391 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1393 return GST_PAD_PROBE_OK;
1395 /* skip this buffer if commit process has been started */
1396 return GST_PAD_PROBE_DROP;