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 mmf_return_val_if_fail(hstreamrecorder, FALSE);
302 /* _mmstreamrec_dbg_log("msg id:%x, msg_cb:%p, msg_data:%p, item:%p", item->id, hstreamrecorder->msg_cb, hstreamrecorder->msg_data, item); */
303 _MMSTREAMRECORDER_LOCK_MESSAGE_CALLBACK(hstreamrecorder);
305 if ((hstreamrecorder) && (hstreamrecorder->msg_cb))
306 hstreamrecorder->msg_cb(item->id, (MMMessageParamType *) (&(item->param)), hstreamrecorder->msg_cb_param);
308 _MMSTREAMRECORDER_UNLOCK_MESSAGE_CALLBACK(hstreamrecorder);
310 _MMSTREAMRECORDER_LOCK((MMHandleType) hstreamrecorder);
311 if (hstreamrecorder->msg_data)
312 hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
316 _MMSTREAMRECORDER_UNLOCK((MMHandleType) hstreamrecorder);
317 /* For not being called again */
321 void _mmstreamrecorder_remove_all_handlers(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
323 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
325 _mmstreamrec_dbg_log("ENTER");
327 if (hstreamrecorder->signals)
328 _mmstreamrecorder_disconnect_signal((MMHandleType) hstreamrecorder, category);
329 if (hstreamrecorder->data_probes)
330 _mmstreamrecorder_remove_data_probe((MMHandleType) hstreamrecorder, category);
331 if (hstreamrecorder->event_probes)
332 _mmstreamrecorder_remove_event_probe((MMHandleType) hstreamrecorder, category);
333 if (hstreamrecorder->buffer_probes)
334 _mmstreamrecorder_remove_buffer_probe((MMHandleType) hstreamrecorder, category);
336 _mmstreamrec_dbg_log("LEAVE");
339 gboolean _mmstreamrecorder_send_message(MMHandleType handle, _MMStreamRecorderMsgItem *data)
341 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
342 _MMStreamRecorderMsgItem *item = NULL;
344 mmf_return_val_if_fail(hstreamrecorder, FALSE);
345 mmf_return_val_if_fail(data, FALSE);
347 /* _mmstreamrec_dbg_err("ENTER"); */
349 /* _mmstreamrec_dbg_err("data->id = %x",data->id); */
352 case MM_MESSAGE_STREAMRECORDER_STATE_CHANGED:
353 data->param.union_type = MM_MSG_UNION_STATE;
355 case MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS:
356 data->param.union_type = MM_MSG_UNION_RECORDING_STATUS;
358 case MM_MESSAGE_STREAMRECORDER_CONSUME_COMPLETE: /* 0x801 */
359 data->param.union_type = MM_MSG_UNION_CONSUME_RECORDER_BUFFER;
361 case MM_MESSAGE_STREAMRECORDER_TIME_LIMIT:
362 case MM_MESSAGE_STREAMRECORDER_MAX_SIZE:
363 case MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE:
364 case MM_MESSAGE_STREAMRECORDER_ERROR:
365 case MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED:
366 case MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED:
367 case MM_MESSAGE_READY_TO_RESUME:
369 data->param.union_type = MM_MSG_UNION_CODE;
373 item = g_malloc(sizeof(_MMStreamRecorderMsgItem));
376 memcpy(item, data, sizeof(_MMStreamRecorderMsgItem));
377 item->handle = handle;
379 _MMSTREAMRECORDER_LOCK(handle);
380 hstreamrecorder->msg_data = g_list_append(hstreamrecorder->msg_data, item);
381 /* _mmstreamrec_dbg_log("item[%p]", item); */
383 /* Use DEFAULT priority */
384 g_idle_add_full(G_PRIORITY_DEFAULT, _mmstreamrecorder_msg_callback, item, NULL);
386 _MMSTREAMRECORDER_UNLOCK(handle);
391 gboolean _mmstreamrecorder_remove_message_all(MMHandleType handle)
393 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
394 _MMStreamRecorderMsgItem *item = NULL;
398 mmf_return_val_if_fail(hstreamrecorder, FALSE);
400 _MMSTREAMRECORDER_LOCK(handle);
402 if (hstreamrecorder->msg_data) {
403 list = hstreamrecorder->msg_data;
407 list = g_list_next(list);
410 ret = g_idle_remove_by_data(item);
411 _mmstreamrec_dbg_log("Remove item[%p]. ret[%d]", item, ret);
413 hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
419 g_list_free(hstreamrecorder->msg_data);
420 hstreamrecorder->msg_data = NULL;
423 /* remove idle function for playing capture sound */
425 ret = g_idle_remove_by_data(hstreamrecorder);
426 _mmstreamrec_dbg_log("remove idle function for playing capture sound. ret[%d]", ret);
429 _MMSTREAMRECORDER_UNLOCK(handle);
434 gboolean _mmstreamrecorder_handle_gst_error(MMHandleType handle, GstMessage *message, GError *error)
436 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
437 /* _MMstreamrecorderMsgItem msg; */
438 gchar *msg_src_element;
439 _MMStreamRecorderSubContext *sc = NULL;
441 return_val_if_fail(hstreamrecorder, FALSE);
442 return_val_if_fail(error, FALSE);
443 sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
444 mmf_return_val_if_fail(sc, FALSE);
446 _mmstreamrec_dbg_log("");
448 /* filtering filesink related errors */
449 if ((error->code == GST_RESOURCE_ERROR_WRITE || error->code == GST_RESOURCE_ERROR_SEEK)) {
450 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
451 sc->ferror_send = TRUE;
452 /* msg.param.code = __mmstreamrecorder_gst_handle_resource_error(handle, error->code, message); */
455 _mmstreamrec_dbg_warn("Skip error");
460 if (error->domain == GST_CORE_ERROR) {
461 /* msg.param.code = __mmstreamrecorder_gst_handle_core_error(handle, error->code, message); */
462 } else if (error->domain == GST_LIBRARY_ERROR) {
463 /* msg.param.code = __mmstreamrecorder_gst_handle_library_error(handle, error->code, message); */
464 } else if (error->domain == GST_RESOURCE_ERROR) {
465 /* msg.param.code = __mmstreamrecorder_gst_handle_resource_error(handle, error->code, message); */
466 } else if (error->domain == GST_STREAM_ERROR) {
467 /* msg.param.code = __mmstreamrecorder_gst_handle_stream_error(handle, error->code, message); */
469 _mmstreamrec_dbg_warn("This error domain is not defined.");
471 /* we treat system error as an internal error */
472 /* msg.param.code = MM_ERROR_streamrecorder_INTERNAL; */
476 msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
477 /* _mmstreamrec_dbg_err("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
478 msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg.param.code); */
480 /* _mmstreamrec_dbg_err("Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
481 g_quark_to_string (error->domain), error->message, error->code, msg.param.code); */
484 #ifdef _MMSTREAMRECORDER_SKIP_GST_FLOW_ERROR
485 /* Check whether send this error to application */
486 /* if (msg.param.code == MM_ERROR_streamrecorder_GST_FLOW_ERROR) {
487 _mmstreamrec_dbg_log("We got the error. But skip it.");
490 #endif /* _MMstreamrecorder_SKIP_GST_FLOW_ERROR */
492 /* post error to application */
493 sc->error_occurs = TRUE;
494 /* msg.id = MM_MESSAGE_streamrecorder_ERROR;
495 _mmstreamrecorder_send_message(handle, &msg); */
500 gint _mmstreamrecorder_gst_handle_core_error(MMHandleType handle, int code, GstMessage *message)
502 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
503 _MMStreamRecorderSubContext *sc = NULL;
504 GstElement *element = NULL;
506 _mmstreamrec_dbg_log("");
508 mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
510 sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
511 mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
513 /* Specific plugin - video encoder plugin */
514 element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
516 if (GST_ELEMENT_CAST(message->src) == element) {
517 if (code == GST_CORE_ERROR_NEGOTIATION)
518 return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
520 return MM_ERROR_STREAMRECORDER_ENCODER;
525 case GST_CORE_ERROR_STATE_CHANGE:
526 return MM_ERROR_STREAMRECORDER_GST_STATECHANGE;
527 case GST_CORE_ERROR_NEGOTIATION:
528 return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
529 case GST_CORE_ERROR_MISSING_PLUGIN:
530 case GST_CORE_ERROR_SEEK:
531 case GST_CORE_ERROR_NOT_IMPLEMENTED:
532 case GST_CORE_ERROR_FAILED:
533 case GST_CORE_ERROR_TOO_LAZY:
534 case GST_CORE_ERROR_PAD:
535 case GST_CORE_ERROR_THREAD:
536 case GST_CORE_ERROR_EVENT:
537 case GST_CORE_ERROR_CAPS:
538 case GST_CORE_ERROR_TAG:
539 case GST_CORE_ERROR_CLOCK:
540 case GST_CORE_ERROR_DISABLED:
542 return MM_ERROR_STREAMRECORDER_GST_CORE;
547 gint _mmstreamrecorder_gst_handle_library_error(MMHandleType handle, int code, GstMessage *message)
549 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
550 return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
552 _mmstreamrec_dbg_log("");
554 /* Specific plugin - NONE */
558 case GST_LIBRARY_ERROR_FAILED:
559 case GST_LIBRARY_ERROR_TOO_LAZY:
560 case GST_LIBRARY_ERROR_INIT:
561 case GST_LIBRARY_ERROR_SHUTDOWN:
562 case GST_LIBRARY_ERROR_SETTINGS:
563 case GST_LIBRARY_ERROR_ENCODE:
565 _mmstreamrec_dbg_err("Library error(%d)", code);
566 return MM_ERROR_STREAMRECORDER_GST_LIBRARY;
570 gint _mmstreamrecorder_gst_handle_resource_error(MMHandleType handle, int code, GstMessage *message)
572 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
573 _MMStreamRecorderSubContext *sc = NULL;
574 GstElement *element = NULL;
576 mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
578 sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
579 mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
581 _mmstreamrec_dbg_log("");
583 /* Specific plugin */
586 element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
587 if (GST_ELEMENT_CAST(message->src) == element) {
588 if (code == GST_RESOURCE_ERROR_FAILED) {
589 _mmstreamrec_dbg_err("Encoder [Resource error]");
590 return MM_ERROR_STREAMRECORDER_ENCODER_BUFFER;
592 _mmstreamrec_dbg_err("Encoder [General(%d)]", code);
593 return MM_ERROR_STREAMRECORDER_ENCODER;
599 case GST_RESOURCE_ERROR_WRITE:
600 _mmstreamrec_dbg_err("File write error");
601 return MM_ERROR_FILE_WRITE;
602 case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
603 _mmstreamrec_dbg_err("No left space");
604 return MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
605 case GST_RESOURCE_ERROR_OPEN_WRITE:
606 _mmstreamrec_dbg_err("Out of storage");
607 return MM_ERROR_OUT_OF_STORAGE;
608 case GST_RESOURCE_ERROR_SEEK:
609 _mmstreamrec_dbg_err("File read(seek)");
610 return MM_ERROR_FILE_READ;
611 case GST_RESOURCE_ERROR_NOT_FOUND:
612 case GST_RESOURCE_ERROR_FAILED:
613 case GST_RESOURCE_ERROR_TOO_LAZY:
614 case GST_RESOURCE_ERROR_BUSY:
615 case GST_RESOURCE_ERROR_OPEN_READ:
616 case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
617 case GST_RESOURCE_ERROR_CLOSE:
618 case GST_RESOURCE_ERROR_READ:
619 case GST_RESOURCE_ERROR_SYNC:
620 case GST_RESOURCE_ERROR_SETTINGS:
622 _mmstreamrec_dbg_err("Resource error(%d)", code);
623 return MM_ERROR_STREAMRECORDER_GST_RESOURCE;
627 gint _mmstreamrecorder_gst_handle_stream_error(MMHandleType handle, int code, GstMessage *message)
629 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
630 _MMStreamRecorderSubContext *sc = NULL;
631 GstElement *element = NULL;
633 mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
635 sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
636 mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
638 _mmstreamrec_dbg_log("");
640 /* Specific plugin */
642 element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
643 if (GST_ELEMENT_CAST(message->src) == element) {
645 case GST_STREAM_ERROR_WRONG_TYPE:
646 _mmstreamrec_dbg_err("Video encoder [wrong stream type]");
647 return MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE;
648 case GST_STREAM_ERROR_ENCODE:
649 _mmstreamrec_dbg_err("Video encoder [encode error]");
650 return MM_ERROR_STREAMRECORDER_ENCODER_WORKING;
651 case GST_STREAM_ERROR_FAILED:
652 _mmstreamrec_dbg_err("Video encoder [stream failed]");
653 return MM_ERROR_STREAMRECORDER_ENCODER_WORKING;
655 _mmstreamrec_dbg_err("Video encoder [General(%d)]", code);
656 return MM_ERROR_STREAMRECORDER_ENCODER;
662 case GST_STREAM_ERROR_FORMAT:
663 _mmstreamrec_dbg_err("General [negotiation error(%d)]", code);
664 return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
665 case GST_STREAM_ERROR_FAILED:
666 _mmstreamrec_dbg_err("General [flow error(%d)]", code);
667 return MM_ERROR_STREAMRECORDER_GST_FLOW_ERROR;
668 case GST_STREAM_ERROR_TYPE_NOT_FOUND:
669 case GST_STREAM_ERROR_DECODE:
670 case GST_STREAM_ERROR_CODEC_NOT_FOUND:
671 case GST_STREAM_ERROR_NOT_IMPLEMENTED:
672 case GST_STREAM_ERROR_TOO_LAZY:
673 case GST_STREAM_ERROR_ENCODE:
674 case GST_STREAM_ERROR_DEMUX:
675 case GST_STREAM_ERROR_MUX:
676 case GST_STREAM_ERROR_DECRYPT:
677 case GST_STREAM_ERROR_DECRYPT_NOKEY:
678 case GST_STREAM_ERROR_WRONG_TYPE:
680 _mmstreamrec_dbg_err("General [error(%d)]", code);
681 return MM_ERROR_STREAMRECORDER_GST_STREAM;
685 gboolean _mmstreamrecorder_handle_gst_warning(MMHandleType handle, GstMessage *message, GError *error)
687 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
691 return_val_if_fail(hstreamrecorder, FALSE);
692 return_val_if_fail(error, FALSE);
694 _mmstreamrec_dbg_log("");
696 gst_message_parse_warning(message, &err, &debug);
698 if (error->domain == GST_CORE_ERROR) {
699 _mmstreamrec_dbg_warn("GST warning: GST_CORE domain");
700 } else if (error->domain == GST_LIBRARY_ERROR) {
701 _mmstreamrec_dbg_warn("GST warning: GST_LIBRARY domain");
702 } else if (error->domain == GST_RESOURCE_ERROR) {
703 _mmstreamrec_dbg_warn("GST warning: GST_RESOURCE domain");
704 /* _mmstreamrecorder_gst_handle_resource_warning(handle, message, error); */
705 } else if (error->domain == GST_STREAM_ERROR) {
706 _mmstreamrec_dbg_warn("GST warning: GST_STREAM domain");
708 _mmstreamrec_dbg_warn("This error domain(%d) is not defined.", error->domain);
716 _mmstreamrec_dbg_err("Debug: %s", debug);
724 gboolean _mmstreamrecorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpointer data)
726 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(data);
727 /* _MMstreamrecorderMsgItem msg; */
728 _MMStreamRecorderSubContext *sc = NULL;
730 mmf_return_val_if_fail(hstreamrecorder, FALSE);
731 mmf_return_val_if_fail(message, FALSE);
732 /* _mmstreamrec_dbg_log("message type=(%d)", GST_MESSAGE_TYPE(message)); */
734 switch (GST_MESSAGE_TYPE(message)) {
735 case GST_MESSAGE_UNKNOWN:
736 _mmstreamrec_dbg_log("GST_MESSAGE_UNKNOWN");
738 case GST_MESSAGE_EOS:
740 _mmstreamrec_dbg_log("Got EOS from element \"%s\".", GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
742 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
743 mmf_return_val_if_fail(sc, TRUE);
745 /*if (hstreamrecorder->type != MM_STREAMRECORDER_MODE_AUDIO) { */
746 mmf_return_val_if_fail(sc->info_video, TRUE);
747 if (sc->info_video->b_commiting) {
748 _mmstreamrecorder_video_handle_eos((MMHandleType) hstreamrecorder);
751 mmf_return_val_if_fail(sc->info_audio, TRUE);
752 if (sc->info_audio->b_commiting) {
753 _mmstreamrecorder_audio_handle_eos((MMHandleType)hstreamrecorder);
761 case GST_MESSAGE_ERROR:
765 gst_message_parse_error(message, &err, &debug);
767 _mmstreamrec_dbg_err("GSTERR: %s", err->message);
768 _mmstreamrec_dbg_err("Error Debug: %s", debug);
770 _mmstreamrecorder_handle_gst_error((MMHandleType) hstreamrecorder, message, err);
776 case GST_MESSAGE_WARNING:
780 gst_message_parse_warning(message, &err, &debug);
782 _mmstreamrec_dbg_warn("GSTWARN: %s", err->message);
784 _mmstreamrecorder_handle_gst_warning((MMHandleType) hstreamrecorder, message, err);
790 case GST_MESSAGE_INFO:
791 _mmstreamrec_dbg_log("GST_MESSAGE_INFO");
793 case GST_MESSAGE_TAG:
794 _mmstreamrec_dbg_log("GST_MESSAGE_TAG");
796 case GST_MESSAGE_BUFFERING:
797 _mmstreamrec_dbg_log("GST_MESSAGE_BUFFERING");
799 case GST_MESSAGE_STATE_CHANGED:
801 const GValue *vnewstate;
803 GstElement *pipeline = NULL;
805 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
806 if ((sc) && (sc->encode_element)) {
807 if (sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst) {
808 pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
809 if (message->src == (GstObject *) pipeline) {
810 vnewstate = (GValue *) gst_structure_get_value(gst_message_get_structure(message), "new-state");
811 newstate = (GstState) vnewstate->data[0].v_int;
812 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_CHANGED[%s]", gst_element_state_get_name(newstate));
818 case GST_MESSAGE_STATE_DIRTY:
819 _mmstreamrec_dbg_log("GST_MESSAGE_STATE_DIRTY");
821 case GST_MESSAGE_STEP_DONE:
822 _mmstreamrec_dbg_log("GST_MESSAGE_STEP_DONE");
824 case GST_MESSAGE_CLOCK_PROVIDE:
825 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_PROVIDE");
827 case GST_MESSAGE_CLOCK_LOST:
828 _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_LOST");
830 case GST_MESSAGE_NEW_CLOCK:
833 gst_message_parse_new_clock(message, &l_clock);
834 _mmstreamrec_dbg_log("GST_MESSAGE_NEW_CLOCK : %s", (l_clock ? GST_OBJECT_NAME(l_clock) : "NULL"));
837 case GST_MESSAGE_STRUCTURE_CHANGE:
838 _mmstreamrec_dbg_log("GST_MESSAGE_STRUCTURE_CHANGE");
840 case GST_MESSAGE_STREAM_STATUS:
841 _mmstreamrec_dbg_log("GST_MESSAGE_STREAM_STATUS");
843 case GST_MESSAGE_APPLICATION:
844 _mmstreamrec_dbg_log("GST_MESSAGE_APPLICATION");
846 case GST_MESSAGE_ELEMENT:
847 _mmstreamrec_dbg_log("GST_MESSAGE_ELEMENT");
849 case GST_MESSAGE_SEGMENT_START:
850 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_START");
852 case GST_MESSAGE_SEGMENT_DONE:
853 _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_DONE");
855 case GST_MESSAGE_DURATION:
856 _mmstreamrec_dbg_log("GST_MESSAGE_DURATION");
858 case GST_MESSAGE_LATENCY:
859 _mmstreamrec_dbg_log("GST_MESSAGE_LATENCY");
861 case GST_MESSAGE_ASYNC_START:
862 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_START");
864 case GST_MESSAGE_ASYNC_DONE:
865 _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_DONE");
867 case GST_MESSAGE_ANY:
868 _mmstreamrec_dbg_log("GST_MESSAGE_ANY");
871 _mmstreamrec_dbg_log("not handled message type=(%d)", GST_MESSAGE_TYPE(message));
879 * This function is record video data probing function.
880 * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
881 * this function will be called when data stream pass through the pad.
883 * @param[in] pad probing pad which calls this function.
884 * @param[in] buffer buffer which contains stream data.
885 * @param[in] u_data user data.
886 * @return This function returns true on success, or false value with error
890 GstPadProbeReturn __mmstreamrecorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
892 GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
893 switch (GST_EVENT_TYPE(event)) {
894 case GST_EVENT_UNKNOWN:
895 /* upstream events */
898 case GST_EVENT_NAVIGATION:
899 case GST_EVENT_LATENCY:
900 /* downstream serialized events */
901 case GST_EVENT_SEGMENT:
903 case GST_EVENT_BUFFERSIZE:
904 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
907 _mmstreamrec_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
909 /* bidirectional events */
910 case GST_EVENT_FLUSH_START:
911 case GST_EVENT_FLUSH_STOP:
912 _mmstreamrec_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
915 _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
919 return GST_PAD_PROBE_OK;
922 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
924 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
925 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
926 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
927 guint64 buffer_size = 0;
929 _MMStreamRecorderSubContext *sc = NULL;
930 _MMStreamRecorderAudioInfo *audioinfo = NULL;
932 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
933 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
934 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
936 mmf_return_val_if_fail(sc && sc->info_audio, GST_PAD_PROBE_OK);
937 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
939 audioinfo = sc->info_audio;
941 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
942 buffer_size = mapinfo.size;
943 gst_buffer_unmap(buffer, &mapinfo);
945 /*_mmstreamrec_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
947 if (audioinfo->audio_frame_count == 0) {
948 audioinfo->filesize += buffer_size;
949 audioinfo->audio_frame_count++;
950 return GST_PAD_PROBE_OK;
953 if (sc->ferror_send || sc->isMaxsizePausing) {
954 _mmstreamrec_dbg_warn("Recording is paused, drop frames");
955 return GST_PAD_PROBE_DROP;
958 audioinfo->filesize += buffer_size;
959 audioinfo->audio_frame_count++;
961 return GST_PAD_PROBE_OK;
964 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
966 static int count = 0;
970 guint64 free_space = 0;
971 guint64 buffer_size = 0;
972 guint64 trailer_size = 0;
973 guint64 queued_buffer = 0;
974 char *filename = NULL;
975 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
976 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
978 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
979 _MMStreamRecorderMsgItem msg;
980 _MMStreamRecorderSubContext *sc = NULL;
981 _MMStreamRecorderVideoInfo *videoinfo = NULL;
982 _MMStreamRecorderFileInfo *finfo = NULL;
984 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
985 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
987 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
988 mmf_return_val_if_fail(sc && sc->info_video && sc->info_file, TRUE);
989 memset(&mapinfo, 0x0, sizeof(GstMapInfo));
991 videoinfo = sc->info_video;
992 finfo = sc->info_file;
994 /*_mmstreamrec_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
995 if (sc->ferror_send) {
996 _mmstreamrec_dbg_warn("file write error, drop frames");
997 return GST_PAD_PROBE_DROP;
999 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
1000 buffer_size = mapinfo.size;
1001 gst_buffer_unmap(buffer, &mapinfo);
1003 videoinfo->video_frame_count++;
1004 if (videoinfo->video_frame_count <= (guint64) _MMSTREAMRECORDER_MINIMUM_FRAME) {
1005 /* _mmstreamrec_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ", info->video_frame_count); */
1006 videoinfo->filesize += buffer_size;
1007 return GST_PAD_PROBE_OK;
1010 /* get trailer size */
1011 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
1012 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1017 /* to minimizing free space check overhead */
1018 count = count % _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL;
1020 filename = finfo->filename;
1021 ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1023 /*_mmstreamrec_dbg_log("check free space for recording");*/
1026 case -2: /* file not exist */
1027 case -1: /* failed to get free space */
1028 _mmstreamrec_dbg_err("Error occured. [%d]", ret);
1029 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1030 sc->ferror_send = TRUE;
1031 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1033 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1035 msg.param.code = MM_ERROR_FILE_READ;
1037 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1042 return GST_PAD_PROBE_DROP; /* skip this buffer */
1044 default: /* succeeded to get free space */
1045 /* check free space for recording */
1046 /* get queued buffer size */
1047 if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst) {
1048 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
1050 if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst) {
1051 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
1054 queued_buffer = aq_size + vq_size;
1056 /* check free space */
1057 if (free_space < (_MMSTREAMRECORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
1058 _mmstreamrec_dbg_warn("No more space for recording!!! Recording is paused.");
1059 _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", free_space, trailer_size, buffer_size, queued_buffer);
1061 if (!sc->isMaxsizePausing) {
1062 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1063 sc->isMaxsizePausing = TRUE;
1065 msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
1066 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1069 return GST_PAD_PROBE_DROP;
1075 videoinfo->filesize += (guint64) buffer_size;
1078 _mmstreamrec_dbg_log("filesize %lld Byte, ", info->filesize);
1081 return GST_PAD_PROBE_OK;
1084 GstPadProbeReturn __mmstreamrecorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1086 guint64 trailer_size = 0;
1087 guint64 rec_pipe_time = 0;
1088 unsigned int remained_time = 0;
1090 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1091 GstClockTime b_time;
1093 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1094 _MMStreamRecorderMsgItem msg;
1095 _MMStreamRecorderSubContext *sc = NULL;
1096 _MMStreamRecorderVideoInfo *videoinfo = NULL;
1097 _MMStreamRecorderFileInfo *finfo = NULL;
1099 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1100 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1102 sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1103 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1104 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1105 mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1107 videoinfo = sc->info_video;
1108 finfo = sc->info_file;
1110 b_time = GST_BUFFER_TIMESTAMP(buffer);
1112 rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
1114 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
1115 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1120 /* check max time */
1121 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1122 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1124 if (!sc->isMaxtimePausing) {
1125 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1127 sc->isMaxtimePausing = TRUE;
1129 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1130 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1131 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1132 msg.param.recording_status.remained_time = 0;
1133 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1135 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1136 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1139 return GST_PAD_PROBE_DROP;
1142 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1143 remained_time = videoinfo->max_time - rec_pipe_time;
1145 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1146 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1147 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1148 msg.param.recording_status.remained_time = remained_time;
1149 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1152 _mmstreamrec_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
1153 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1156 return GST_PAD_PROBE_OK;
1159 GstPadProbeReturn __mmstreamrecorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1161 _MMStreamRecorderMsgItem msg;
1162 guint64 trailer_size = 0;
1163 guint64 rec_pipe_time = 0;
1164 _MMStreamRecorderSubContext *sc = NULL;
1165 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1166 _MMStreamRecorderVideoInfo *videoinfo = NULL;
1167 _MMStreamRecorderFileInfo *finfo = NULL;
1168 unsigned int remained_time = 0;
1169 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1171 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1172 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
1173 sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
1175 mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
1176 mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
1177 mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
1179 videoinfo = sc->info_video;
1180 finfo = sc->info_file;
1182 if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
1183 _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
1184 return GST_PAD_PROBE_OK;
1187 rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
1189 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
1190 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1195 if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
1196 remained_time = videoinfo->max_time - rec_pipe_time;
1198 if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
1199 _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
1201 if (!sc->isMaxtimePausing) {
1202 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1204 sc->isMaxtimePausing = TRUE;
1206 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1207 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1208 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1209 msg.param.recording_status.remained_time = 0;
1210 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1212 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1213 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1216 return GST_PAD_PROBE_DROP;
1219 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1220 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1221 msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
1222 msg.param.recording_status.remained_time = remained_time;
1223 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1226 _mmstreamrec_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
1227 GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
1230 return GST_PAD_PROBE_OK;
1233 void __mmstreamrecorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle)
1235 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
1237 _mmstreamrec_dbg_log("ENTER(%s)", GST_PAD_NAME(pad));
1238 /* FIXME : the name of audio sink pad of wavparse, oggmux doesn't have 'audio'. How could I handle the name? */
1239 if ((strstr(GST_PAD_NAME(pad), "audio")) || (strstr(GST_PAD_NAME(pad), "sink"))) {
1240 MMSTREAMRECORDER_ADD_BUFFER_PROBE(pad, _MMSTREAMRECORDER_HANDLER_AUDIOREC, __mmstreamrecorder_audio_dataprobe_record, hstreamrecorder);
1242 _mmstreamrec_dbg_warn("Unknow pad is added, check it : [%s]", GST_PAD_NAME(pad));
1248 GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1250 static int count = 0;
1251 guint64 rec_pipe_time = 0;
1252 guint64 free_space = 0;
1253 guint64 buffer_size = 0;
1254 guint64 trailer_size = 0;
1255 char *filename = NULL;
1256 unsigned long long remained_time = 0;
1257 GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
1259 _MMStreamRecorderSubContext *sc = NULL;
1260 mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
1261 _MMStreamRecorderAudioInfo *audioinfo = NULL;
1262 _MMStreamRecorderFileInfo *finfo = NULL;
1263 _MMStreamRecorderMsgItem msg;
1265 mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_DROP);
1266 mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
1268 sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
1269 mmf_return_val_if_fail(sc && sc->info_audio && sc->info_file, FALSE);
1270 audioinfo = sc->info_audio;
1271 finfo = sc->info_file;
1273 if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
1274 _mmstreamrec_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]", sc->isMaxtimePausing, sc->isMaxsizePausing);
1275 return GST_PAD_PROBE_DROP;
1278 buffer_size = gst_buffer_get_size(buffer);
1280 if (audioinfo->filesize == 0) {
1281 if (finfo->fileformat == MM_FILE_FORMAT_WAV) {
1282 audioinfo->filesize += 44; /* wave header size */
1283 } else if (finfo->fileformat == MM_FILE_FORMAT_AMR) {
1284 audioinfo->filesize += 6; /* amr header size */
1287 audioinfo->filesize += buffer_size;
1288 return GST_PAD_PROBE_OK;
1291 if (sc->ferror_send) {
1292 _mmstreamrec_dbg_warn("file write error, drop frames");
1293 return GST_PAD_PROBE_DROP;
1296 /* get trailer size */
1297 if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4 || finfo->fileformat == MM_FILE_FORMAT_AAC) {
1298 MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
1299 /*_mmstreamrec_dbg_log("trailer_size %d", trailer_size);*/
1301 trailer_size = 0; /* no trailer */
1304 filename = finfo->filename;
1306 /* to minimizing free space check overhead */
1307 count = count % _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL;
1309 gint free_space_ret = _mmstreamrecorder_get_freespace(filename, &free_space);
1311 /*_mmstreamrec_dbg_log("check free space for recording");*/
1313 switch (free_space_ret) {
1314 case -2: /* file not exist */
1315 case -1: /* failed to get free space */
1316 _mmstreamrec_dbg_err("Error occured. [%d]", free_space_ret);
1317 if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
1318 sc->ferror_send = TRUE;
1319 msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
1320 if (free_space_ret == -2) {
1321 msg.param.code = MM_ERROR_FILE_NOT_FOUND;
1323 msg.param.code = MM_ERROR_FILE_READ;
1325 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1330 return GST_PAD_PROBE_DROP; /* skip this buffer */
1332 default: /* succeeded to get free space */
1333 /* check free space for recording */
1334 if (free_space < (guint64) (_MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) {
1335 _mmstreamrec_dbg_warn("No more space for recording!!!");
1336 _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]", free_space, audioinfo->filesize);
1338 if (audioinfo->bMuxing) {
1339 MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
1341 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);
1376 sc->isMaxtimePausing = TRUE;
1377 msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
1378 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1380 /* skip this buffer */
1381 return GST_PAD_PROBE_DROP;
1384 /* send message for recording time and recorded file size */
1385 if (audioinfo->b_commiting == FALSE) {
1386 audioinfo->filesize += buffer_size;
1388 msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
1389 msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
1390 msg.param.recording_status.filesize = (unsigned long long)((audioinfo->filesize + trailer_size) >> 10);
1391 msg.param.recording_status.remained_time = remained_time;
1392 _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
1394 return GST_PAD_PROBE_OK;
1396 /* skip this buffer if commit process has been started */
1397 return GST_PAD_PROBE_DROP;