diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index d1bdaea532..340f18f0b6 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -325,7 +325,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_lock_unlock(switch_core_s SWITCH_DECLARE(void) switch_core_session_stop_media(switch_core_session_t *session); SWITCH_DECLARE(switch_media_flow_t) switch_core_session_media_flow(switch_core_session_t *session, switch_media_type_t type); SWITCH_DECLARE(switch_status_t) switch_core_media_get_vid_params(switch_core_session_t *session, switch_vid_params_t *vid_params); -SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh); +SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh, switch_rw_t rw); SWITCH_END_EXTERN_C #endif diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 020845acc6..7cda2838a1 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -552,6 +552,11 @@ SWITCH_DECLARE_DATA extern switch_filenames SWITCH_GLOBAL_filenames; #define SWITCH_ACCEPTABLE_INTERVAL(_i) (_i && _i <= SWITCH_MAX_INTERVAL && (_i % 10) == 0) +typedef enum { + SWITCH_RW_READ, + SWITCH_RW_WRITE +} switch_rw_t; + typedef enum { SWITCH_CPF_NONE = 0, SWITCH_CPF_SCREEN = (1 << 0), diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index a636bcc57c..7ff9b9d0c5 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -1580,7 +1580,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_frame_t write_frame = { 0 }; uint8_t *packet = NULL; layout_group_t *lg = NULL; - switch_image_t *write_img = NULL, *free_img = NULL; + switch_image_t *write_img = NULL, *file_img = NULL; #ifdef TRACK_FPS uint64_t frames = 0; @@ -1617,8 +1617,10 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_core_timer_init(&conference->canvas->timer, "soft", conference->video_fps.ms, conference->video_fps.samples, NULL); need_reset = SWITCH_TRUE; } - - switch_core_timer_next(&conference->canvas->timer); + + if (!conference->record_fh) { + switch_core_timer_next(&conference->canvas->timer); + } now = switch_micro_time_now(); @@ -1635,7 +1637,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread continue; } - if (switch_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { + if (!switch_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { min_members++; } @@ -1844,8 +1846,11 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread if (conference->fnode) { if (switch_core_file_read_video(&conference->fnode->fh, &write_frame) == SWITCH_STATUS_SUCCESS) { - write_img = free_img = write_frame.img; + switch_img_free(&file_img); + write_img = file_img = write_frame.img; } + } else if (file_img) { + switch_img_free(&file_img); } if (conference->record_fh) { @@ -1894,10 +1899,9 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_core_session_rwunlock(imember->session); } } + switch_mutex_unlock(conference->member_mutex); - - switch_img_free(&free_img); } for (i = 0; i < MCU_MAX_LAYERS; i++) { diff --git a/src/mod/formats/mod_vlc/mod_vlc.c b/src/mod/formats/mod_vlc/mod_vlc.c index 2ea8074bd2..77d2c5933a 100644 --- a/src/mod/formats/mod_vlc/mod_vlc.c +++ b/src/mod/formats/mod_vlc/mod_vlc.c @@ -283,6 +283,12 @@ static void vlc_video_av_unlock_callback(void *data, void *id, void *const *p_pi { vlc_video_context_t *context = (vlc_video_context_t *) data; + if (context->img) { + if (context->img->d_w != context->width || context->img->d_h != context->height) { + switch_img_free(&context->img); + } + } + if (!context->img) context->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, context->width, context->height, 0); switch_assert(context->img); @@ -344,10 +350,13 @@ static void vlc_video_display_callback(void *data, void *id) vlc_video_context_t *context = (vlc_video_context_t *) data; if (context->channel && !switch_channel_test_flag(context->channel, CF_VIDEO)) return; + if (!context->img) return; if (context->video_queue) { - switch_queue_push(context->video_queue, context->img); - context->img = NULL; + switch_image_t *img_copy = NULL; + switch_img_copy(context->img, &img_copy); + switch_queue_push(context->video_queue, img_copy); + } else { context->vid_frame->img = context->img; context->vid_frame->packet = context->video_packet; @@ -650,12 +659,21 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p { vlc_file_context_t *context; libvlc_event_manager_t *mp_event_manager, *m_event_manager; - + char *ext = NULL; + context = switch_core_alloc(handle->memory_pool, sizeof(*context)); context->pool = handle->memory_pool; - context->path = switch_core_strdup(context->pool, path); context->vlc_handle = libvlc_new(sizeof(vlc_args)/sizeof(char *), vlc_args); + + if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO) && switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE) && + (ext = strrchr(path, '.')) && !strcasecmp(ext, ".mp4")) { + path = switch_core_sprintf(context->pool, "#transcode{vcodec=h264,acodec=mp3}:std{access=file,mux=mp4,dst=%s}", path); + } + + context->path = switch_core_strdup(context->pool, path); + + if (!switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) { switch_buffer_create_dynamic(&(context->audio_buffer), VLC_BUFFER_SIZE, VLC_BUFFER_SIZE * 8, 0); switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->pool); @@ -2202,8 +2220,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vlc_load) /* connect my internal structure to the blank pointer passed to me */ *module_interface = switch_loadable_module_create_module_interface(pool, modname); - + vlc_file_supported_formats[0] = "vlc"; + vlc_file_supported_formats[1] = "mp4"; /* maybe add config for this mod to enable or disable */ file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE); file_interface->interface_name = modname; diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 91a62cb6c4..f13029f28d 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -203,7 +203,8 @@ struct switch_media_handle_s { void *video_user_data; int8_t video_function_running; switch_vid_params_t vid_params; - switch_file_handle_t *video_fh; + switch_file_handle_t *video_read_fh; + switch_file_handle_t *video_write_fh; }; @@ -4582,7 +4583,7 @@ SWITCH_DECLARE(int) switch_core_media_toggle_hold(switch_core_session_t *session return changed; } -SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh) +SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh, switch_rw_t rw) { switch_media_handle_t *smh; switch_rtp_engine_t *v_engine; @@ -4603,7 +4604,17 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_ses return SWITCH_STATUS_FALSE; } - smh->video_fh = fh; + if (rw == SWITCH_RW_READ) { + smh->video_read_fh = fh; + if (fh) { + switch_channel_set_flag_recursive(session->channel, CF_VIDEO_DECODED_READ); + } else { + switch_channel_clear_flag_recursive(session->channel, CF_VIDEO_DECODED_READ); + switch_core_session_video_reset(session); + } + } else { + smh->video_write_fh = fh; + } return SWITCH_STATUS_SUCCESS; } @@ -4619,11 +4630,14 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi uint32_t loops = 0, xloops = 0; switch_frame_t fr = { 0 }; unsigned char *buf = NULL; + //switch_rtp_engine_t *v_engine = NULL; if (!(smh = session->media_handle)) { return NULL; } + //v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; + switch_core_session_read_lock(session); mh->up = 1; @@ -4685,47 +4699,52 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi switch_mutex_unlock(smh->control_mutex); } } + + if (!smh->video_write_fh || !switch_channel_test_flag(channel, CF_VIDEO_READY)) { + status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); - status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + if (!SWITCH_READ_ACCEPTABLE(status)) { + switch_cond_next(); + continue; + } + + if (switch_test_flag(read_frame, SFF_CNG)) { + continue; + } - if (!SWITCH_READ_ACCEPTABLE(status)) { - switch_cond_next(); - continue; + if (read_frame->img) { + switch_channel_set_flag(channel, CF_VIDEO_READY); + smh->vid_params.width = read_frame->img->d_w; + smh->vid_params.height = read_frame->img->d_h; + } else if (read_frame->datalen > 2 && !switch_channel_test_flag(channel, CF_VIDEO_DECODED_READ)) { + switch_channel_set_flag(channel, CF_VIDEO_READY); + } } - if (switch_test_flag(read_frame, SFF_CNG)) { - continue; - } - - - - if (read_frame->img) { - switch_channel_set_flag(channel, CF_VIDEO_READY); - smh->vid_params.width = read_frame->img->d_w; - smh->vid_params.height = read_frame->img->d_h; - } - - if (smh->video_fh) { + if (smh->video_write_fh) { if (!buf) { - int buflen = SWITCH_RECOMMENDED_BUFFER_SIZE * 2; + int buflen = SWITCH_RECOMMENDED_BUFFER_SIZE * 4; buf = switch_core_session_alloc(session, buflen); fr.packet = buf; fr.packetlen = buflen; fr.data = buf + 12; fr.buflen = buflen - 12; } - if (switch_core_file_read_video(smh->video_fh, &fr) == SWITCH_STATUS_SUCCESS) { + + if (switch_core_file_read_video(smh->video_write_fh, &fr) == SWITCH_STATUS_SUCCESS) { switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_NONE, 0); switch_img_free(&fr.img); } - - } else if (switch_channel_test_flag(channel, CF_VIDEO_ECHO)) { + + } else if (smh->video_read_fh && read_frame->img) { + switch_core_file_write_video(smh->video_read_fh, read_frame); + } + + if (read_frame && switch_channel_test_flag(channel, CF_VIDEO_ECHO)) { switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0); } - } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread ended\n", switch_channel_get_name(session->channel)); switch_mutex_unlock(mh->cond_mutex); diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 4d8b93e2b1..f2a3204a2b 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -378,7 +378,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT; int restart_limit_on_dtmf = 0; const char *prefix, *var; - + if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) { return SWITCH_STATUS_FALSE; @@ -523,12 +523,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se fh->prefix = prefix; } + if (switch_channel_test_flag(channel, CF_VIDEO)) { + file_flags |= SWITCH_FILE_FLAG_VIDEO; + } + if (switch_core_file_open(fh, file, fh->channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); arg_recursion_check_stop(args); return SWITCH_STATUS_GENERR; } + + if (switch_core_file_has_video(fh)) { + switch_channel_set_flag(channel, CF_VIDEO_ECHO); + switch_core_media_set_video_file(session, fh, SWITCH_RW_READ); + } if (sample_start > 0) { uint32_t pos = 0; @@ -596,7 +605,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, read_impl.microseconds_per_packet / 1000); + if (switch_core_file_has_video(fh)) { + switch_channel_set_flag(channel, CF_VIDEO_ECHO); + switch_core_media_set_video_file(session, NULL, SWITCH_RW_READ); + } switch_core_file_close(fh); + switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); arg_recursion_check_stop(args); return SWITCH_STATUS_GENERR; @@ -761,13 +775,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se break; } } - } if (fill_cng || waste_resources) { switch_core_codec_destroy(&write_codec); } + if (switch_core_file_has_video(fh)) { + switch_channel_set_flag(channel, CF_VIDEO_ECHO); + switch_core_media_set_video_file(session, NULL, SWITCH_RW_READ); + } switch_core_file_close(fh); @@ -1259,7 +1276,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess switch_core_session_io_rwunlock(session); if (switch_core_file_has_video(fh)) { - switch_core_media_set_video_file(session, fh); + switch_core_media_set_video_file(session, fh, SWITCH_RW_WRITE); } if (!abuf) { @@ -1335,8 +1352,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess switch_core_session_io_rwunlock(session); if (switch_core_file_has_video(fh)) { - switch_core_media_set_video_file(session, NULL); + switch_core_media_set_video_file(session, NULL, SWITCH_RW_WRITE); } + switch_core_file_close(fh); switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE); @@ -1359,7 +1377,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess switch_core_session_io_rwunlock(session); if (switch_core_file_has_video(fh)) { - switch_core_media_set_video_file(session, NULL); + switch_core_media_set_video_file(session, NULL, SWITCH_RW_WRITE); } switch_core_file_close(fh); @@ -1387,7 +1405,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess switch_channel_set_private(channel, "__fh", NULL); switch_core_session_io_rwunlock(session); if (switch_core_file_has_video(fh)) { - switch_core_media_set_video_file(session, NULL); + switch_core_media_set_video_file(session, NULL, SWITCH_RW_WRITE); } switch_core_file_close(fh); switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE); @@ -1797,7 +1815,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess switch_core_session_io_rwunlock(session); if (switch_core_file_has_video(fh)) { - switch_core_media_set_video_file(session, NULL); + switch_core_media_set_video_file(session, NULL, SWITCH_RW_WRITE); } switch_core_file_close(fh);