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 /* _mmstreamrec_dbg_log("msg id:%x, msg_cb:%p, msg_data:%p, item:%p", item->id, hstreamrecorder->msg_cb, hstreamrecorder->msg_data, item); */
306 _MMSTREAMRECORDER_LOCK_MESSAGE_CALLBACK(hstreamrecorder);
308 if ((hstreamrecorder) && (hstreamrecorder->msg_cb))
309 hstreamrecorder->msg_cb(item->id, (MMMessageParamType *) (&(item->param)), hstreamrecorder->msg_cb_param);
311 _MMSTREAMRECORDER_UNLOCK_MESSAGE_CALLBACK(hstreamrecorder);
313 _MMSTREAMRECORDER_LOCK((MMHandleType) hstreamrecorder);
314 if (hstreamrecorder->msg_data)
315 hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
317 _MMSTREAMRECORDER_UNLOCK((MMHandleType) 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);
326 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);
764 case GST_MESSAGE_ERROR:
768 gst_message_parse_error(message, &err, &debug);
770 _mmstreamrec_dbg_err("GSTERR: %s", err->message);
771 _mmstreamrec_dbg_err("Error Debug: %s", debug);
773 _mmstreamrecorder_handle_gst_error((MMHandleType) hstreamrecorder, message, err);
779 case GST_MESSAGE_WARNING:
783 gst_message_parse_warning(message, &err, &debug);
785 _mmstreamrec_dbg_warn("GSTWARN: %s", err->message);
787 _mmstreamrecorder_handle_gst_warning((MMHandleType) hstreamrecorder, message, err);
793 case GST_MESSAGE_INFO:
794 _mmstreamrec_dbg_log("GST_MESSAGE_INFO");
796 case GST_MESSAGE_TAG:
797 _mmstreamrec_dbg_log("GST_MESSAGE_TAG");
799 case GST_MESSAGE_BUFFERING:
800 _mmstreamrec_dbg_log("GST_MESSAGE_BUFFERING");
802 case GST_MESSAGE_STATE_CHANGED:
804 const GValue *vnewstate;
806 GstElement *pipeline = NULL;
808 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
809 if ((sc) && (sc->encode_element)) {
810 if (sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst) {
811 pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
812 if (message->src == (GstObject *) pipeline) {
813 vnewstate = (GValue *) gst_structure_get_value(gst_message_get_structure(message), "new-state");
814 newstate = (GstState) vnewstate->data[0].v_int;
815 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_CHANGED[%s]", gst_element_state_get_name(newstate));
821 case GST_MESSAGE_STATE_DIRTY:
822 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_DIRTY");
824 case GST_MESSAGE_STEP_DONE:
825 _mmstreamrec_dbg_log("GST_MESSAGE_STEP_DONE");
827 case GST_MESSAGE_CLOCK_PROVIDE:
828 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_PROVIDE");
830 case GST_MESSAGE_CLOCK_LOST:
831 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_LOST");
833 case GST_MESSAGE_NEW_CLOCK:
836 gst_message_parse_new_clock(message, &l_clock);
837 _mmstreamrec_dbg_log("GST_MESSAGE_NEW_CLOCK : %s", (l_clock ? GST_OBJECT_NAME(l_clock) : "NULL"));
840 case GST_MESSAGE_STRUCTURE_CHANGE:
841 _mmstreamrec_dbg_log("GST_MESSAGE_STRUCTURE_CHANGE");
843 case GST_MESSAGE_STREAM_STATUS:
844 _mmstreamrec_dbg_log("GST_MESSAGE_STREAM_STATUS");
846 case GST_MESSAGE_APPLICATION:
847 _mmstreamrec_dbg_log("GST_MESSAGE_APPLICATION");
849 case GST_MESSAGE_ELEMENT:
850 _mmstreamrec_dbg_log("GST_MESSAGE_ELEMENT");
852 case GST_MESSAGE_SEGMENT_START:
853 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_START");
855 case GST_MESSAGE_SEGMENT_DONE:
856 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_DONE");
858 case GST_MESSAGE_DURATION:
859 _mmstreamrec_dbg_log("GST_MESSAGE_DURATION");
861 case GST_MESSAGE_LATENCY:
862 _mmstreamrec_dbg_log("GST_MESSAGE_LATENCY");
864 case GST_MESSAGE_ASYNC_START:
865 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_START");
867 case GST_MESSAGE_ASYNC_DONE:
868 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_DONE");
870 case GST_MESSAGE_ANY:
871 _mmstreamrec_dbg_log("GST_MESSAGE_ANY");
874 _mmstreamrec_dbg_log("not handled message type=(%d)", GST_MESSAGE_TYPE(message));
882 * This function is record video data probing function.
883 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
884 * this function will be called when data stream pass through the pad.
886 * @param[in] pad probing pad which calls this function.
887 * @param[in] buffer buffer which contains stream data.
888 * @param[in] u_data user data.
889 * @return This function returns true on success, or false value with error
893 GstPadProbeReturn __mmstreamrecorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
895 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
896 switch (GST_EVENT_TYPE(event)) {
897 case GST_EVENT_UNKNOWN:
898 /* upstream events */
901 case GST_EVENT_NAVIGATION:
902 case GST_EVENT_LATENCY:
903 /* downstream serialized events */
904 case GST_EVENT_SEGMENT:
906 case GST_EVENT_BUFFERSIZE:
907 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
910 _mmstreamrec_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
912 /* bidirectional events */
913 case GST_EVENT_FLUSH_START:
914 case GST_EVENT_FLUSH_STOP:
915 _mmstreamrec_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
918 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
922 return GST_PAD_PROBE_OK;
925 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
927 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
928 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
929 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
930 guint64 buffer_size = 0;
932 _MMStreamRecorderSubContext *sc = NULL;
933 _MMStreamRecorderAudioInfo *audioinfo = NULL;
935 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
936 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
937 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
939 mmf_return_val_if_fail(sc && sc->info_audio, GST_PAD_PROBE_OK);
940 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
942 audioinfo = sc->info_audio;
944 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
945 buffer_size = mapinfo.size;
946 gst_buffer_unmap(buffer, &mapinfo);
948 /*_mmstreamrec_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
950 if (audioinfo->audio_frame_count == 0) {
951 audioinfo->filesize += buffer_size;
952 audioinfo->audio_frame_count++;
953 return GST_PAD_PROBE_OK;
956 if (sc->ferror_send || sc->isMaxsizePausing) {
957 _mmstreamrec_dbg_warn("Recording is paused, drop frames");
958 return GST_PAD_PROBE_DROP;
961 audioinfo->filesize += buffer_size;
962 audioinfo->audio_frame_count++;
964 return GST_PAD_PROBE_OK;
967 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
969 static int count = 0;
973 guint64 free_space = 0;
974 guint64 buffer_size = 0;
975 guint64 trailer_size = 0;
976 guint64 queued_buffer = 0;
977 char *filename = NULL;
978 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
979 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
981 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
982 _MMStreamRecorderMsgItem msg;
983 _MMStreamRecorderSubContext *sc = NULL;
984 _MMStreamRecorderVideoInfo *videoinfo = NULL;
985 _MMStreamRecorderFileInfo *finfo = NULL;
987 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
988 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
990 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
991 mmf_return_val_if_fail(sc && sc->info_video && sc->info_file, TRUE);
992 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
994 videoinfo = sc->info_video;
995 finfo = sc->info_file;
997 /*_mmstreamrec_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
998 if (sc->ferror_send) {
999 _mmstreamrec_dbg_warn("file write error, drop frames");
1000 return GST_PAD_PROBE_DROP;
1002 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1003 buffer_size = mapinfo.size;
1004 gst_buffer_unmap(buffer, &mapinfo);
1006 videoinfo->video_frame_count++;
1007 if (videoinfo->video_frame_count <= (guint64) _MMSTREAMRECORDER_MINIMUM_FRAME) {
1008 /* _mmstreamrec_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ", info->video_frame_count); */
1009 videoinfo->filesize += buffer_size;
1010 return GST_PAD_PROBE_OK;
1013 /* get trailer size */
1014 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
1015 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1020 /* to minimizing free space check overhead */
1021 count = count % _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL;
1023 filename = finfo->filename;
1024 ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1026 /*_mmstreamrec_dbg_log("check free space for recording");*/
1029 case -2: /* file not exist */
1030 case -1: /* failed to get free space */
1031 _mmstreamrec_dbg_err("Error occured. [%d]", ret);
1032 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1033 sc->ferror_send = TRUE;
1034 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1036 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1038 msg.param.code = MM_ERROR_FILE_READ;
1040 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1045 return GST_PAD_PROBE_DROP; /* skip this buffer */
1047 default: /* succeeded to get free space */
1048 /* check free space for recording */
1049 /* get queued buffer size */
1050 if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst) {
1051 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1053 if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst) {
1054 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1057 queued_buffer = aq_size + vq_size;
1059 /* check free space */
1060 if (free_space < (_MMSTREAMRECORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1061 _mmstreamrec_dbg_warn("No more space for recording!!! Recording is paused.");
1062 _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);
1064 if (!sc->isMaxsizePausing) {
1065 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1066 sc->isMaxsizePausing = TRUE;
1068 msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1069 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1072 return GST_PAD_PROBE_DROP;
1078 videoinfo->filesize += (guint64) buffer_size;
1081 _mmstreamrec_dbg_log("filesize %lld Byte, ", info->filesize);
1084 return GST_PAD_PROBE_OK;
1087 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1089 guint64 trailer_size = 0;
1090 guint64 rec_pipe_time = 0;
1091 unsigned int remained_time = 0;
1093 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1094 GstClockTime b_time;
1096 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1097 _MMStreamRecorderMsgItem msg;
1098 _MMStreamRecorderSubContext *sc = NULL;
1099 _MMStreamRecorderVideoInfo *videoinfo = NULL;
1100 _MMStreamRecorderFileInfo *finfo = NULL;
1102 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1103 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1105 sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1106 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1107 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1108 mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1110 videoinfo = sc->info_video;
1111 finfo = sc->info_file;
1113 b_time = GST_BUFFER_TIMESTAMP(buffer);
1115 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1117 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
1118 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1123 /* check max time */
1124 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1125 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1127 if (!sc->isMaxtimePausing) {
1128 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1130 sc->isMaxtimePausing = TRUE;
1132 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1133 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1134 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1135 msg.param.recording_status.remained_time = 0;
1136 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1138 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1139 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1142 return GST_PAD_PROBE_DROP;
1145 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1146 remained_time = videoinfo->max_time - rec_pipe_time;
1148 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1149 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1150 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1151 msg.param.recording_status.remained_time = remained_time;
1152 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1155 _mmstreamrec_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1156 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1159 return GST_PAD_PROBE_OK;
1162 GstPadProbeReturn __mmstreamrecorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1164 _MMStreamRecorderMsgItem msg;
1165 guint64 trailer_size = 0;
1166 guint64 rec_pipe_time = 0;
1167 _MMStreamRecorderSubContext *sc = NULL;
1168 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1169 _MMStreamRecorderVideoInfo *videoinfo = NULL;
1170 _MMStreamRecorderFileInfo *finfo = NULL;
1171 unsigned int remained_time = 0;
1172 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1174 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1175 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1176 sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1178 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1179 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1180 mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1182 videoinfo = sc->info_video;
1183 finfo = sc->info_file;
1185 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1186 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1187 return GST_PAD_PROBE_OK;
1190 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1192 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
1193 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));
1251 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1253 static int count = 0;
1254 guint64 rec_pipe_time = 0;
1255 guint64 free_space = 0;
1256 guint64 buffer_size = 0;
1257 guint64 trailer_size = 0;
1258 char *filename = NULL;
1259 unsigned long long remained_time = 0;
1260 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1262 _MMStreamRecorderSubContext *sc = NULL;
1263 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1264 _MMStreamRecorderAudioInfo *audioinfo = NULL;
1265 _MMStreamRecorderFileInfo *finfo = NULL;
1266 _MMStreamRecorderMsgItem msg;
1268 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_DROP);
1269 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1271 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
1272 mmf_return_val_if_fail(sc && sc->info_audio && sc->info_file, FALSE);
1273 audioinfo = sc->info_audio;
1274 finfo = sc->info_file;
1276 if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
1277 _mmstreamrec_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]", sc->isMaxtimePausing, sc->isMaxsizePausing);
1278 return GST_PAD_PROBE_DROP;
1281 buffer_size = gst_buffer_get_size(buffer);
1283 if (audioinfo->filesize == 0) {
1284 if (finfo->fileformat == MM_FILE_FORMAT_WAV) {
1285 audioinfo->filesize += 44; /* wave header size */
1286 } else if (finfo->fileformat == MM_FILE_FORMAT_AMR) {
1287 audioinfo->filesize += 6; /* amr header size */
1290 audioinfo->filesize += buffer_size;
1291 return GST_PAD_PROBE_OK;
1294 if (sc->ferror_send) {
1295 _mmstreamrec_dbg_warn("file write error, drop frames");
1296 return GST_PAD_PROBE_DROP;
1299 /* get trailer size */
1300 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4 || finfo->fileformat == MM_FILE_FORMAT_AAC) {
1301 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1302 /*_mmstreamrec_dbg_log("trailer_size %d", trailer_size);*/
1304 trailer_size = 0; /* no trailer */
1307 filename = finfo->filename;
1309 /* to minimizing free space check overhead */
1310 count = count % _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL;
1312 gint free_space_ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1314 /*_mmstreamrec_dbg_log("check free space for recording");*/
1316 switch (free_space_ret) {
1317 case -2: /* file not exist */
1318 case -1: /* failed to get free space */
1319 _mmstreamrec_dbg_err("Error occured. [%d]", free_space_ret);
1320 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1321 sc->ferror_send = TRUE;
1322 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1323 if (free_space_ret == -2) {
1324 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1326 msg.param.code = MM_ERROR_FILE_READ;
1328 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1333 return GST_PAD_PROBE_DROP; /* skip this buffer */
1335 default: /* succeeded to get free space */
1336 /* check free space for recording */
1337 if (free_space < (guint64) (_MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) {
1338 _mmstreamrec_dbg_warn("No more space for recording!!!");
1339 _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]", free_space, audioinfo->filesize);
1341 if (audioinfo->bMuxing) {
1342 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1344 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1347 sc->isMaxsizePausing = TRUE;
1348 msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1349 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1351 return FALSE; /* skip this buffer */
1357 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1358 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1359 return GST_PAD_PROBE_DROP;
1362 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1364 if (audioinfo->max_time > 0 && audioinfo->max_time < (remained_time + rec_pipe_time))
1365 remained_time = audioinfo->max_time - rec_pipe_time;
1367 /*_mmstreamrec_dbg_log("remained time : %u", remained_time);*/
1369 /* check recording time limit and send recording status message */
1370 if (audioinfo->max_time > 0 && rec_pipe_time > audioinfo->max_time) {
1371 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, audioinfo->max_time);
1373 if (audioinfo->bMuxing) {
1374 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1376 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
1379 sc->isMaxtimePausing = TRUE;
1380 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1381 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1383 /* skip this buffer */
1384 return GST_PAD_PROBE_DROP;
1387 /* send message for recording time and recorded file size */
1388 if (audioinfo->b_commiting == FALSE) {
1389 audioinfo->filesize += buffer_size;
1391 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1392 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1393 msg.param.recording_status.filesize = (unsigned long long)((audioinfo->filesize + trailer_size) >> 10);
1394 msg.param.recording_status.remained_time = remained_time;
1395 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1397 return GST_PAD_PROBE_OK;
1399 /* skip this buffer if commit process has been started */
1400 return GST_PAD_PROBE_DROP;