From 385a3b545c41f9fd0fdbec4ed8ecfa29b8193ace Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 19 Jun 2015 00:55:01 -0500 Subject: [PATCH] FS-7656 fix various edge cases with video and non video files mixed into a source, fix a typo bug in file_read_video and fix same bug in mod_vlc, add a new flag to file_read_video to check if the handle is has active video, make mod_conference move the video in and out of a layer when the stream has video or not --- src/include/switch_apr.h | 1 + src/include/switch_types.h | 3 +- src/mod/applications/mod_av/avformat.c | 4 + .../mod_conference/mod_conference.c | 68 +++++---- .../mod_local_stream/mod_local_stream.c | 130 +++++++++++++----- src/mod/formats/mod_vlc/mod_vlc.c | 6 +- src/switch_apr.c | 28 ++++ 7 files changed, 175 insertions(+), 65 deletions(-) diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 0f872e2296..55b6b85f5c 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -916,6 +916,7 @@ SWITCH_DECLARE(switch_status_t) switch_dir_make_recursive(const char *path, swit SWITCH_DECLARE(switch_status_t) switch_dir_open(switch_dir_t ** new_dir, const char *dirname, switch_memory_pool_t *pool); SWITCH_DECLARE(switch_status_t) switch_dir_close(switch_dir_t *thedir); SWITCH_DECLARE(const char *) switch_dir_next_file(switch_dir_t *thedir, char *buf, switch_size_t len); +SWITCH_DECLARE(uint32_t) switch_dir_count(switch_dir_t *thedir); /** @} */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index c435106c38..95220b1542 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -2558,7 +2558,8 @@ typedef struct switch_frame_buffer_s switch_frame_buffer_t; typedef enum { SVR_BLOCK = (1 << 0), - SVR_FLUSH = (1 << 1) + SVR_FLUSH = (1 << 1), + SVR_CHECK = (1 << 2) } switch_video_read_flag_t; typedef enum { diff --git a/src/mod/applications/mod_av/avformat.c b/src/mod/applications/mod_av/avformat.c index 80b17c516a..9b897381b8 100644 --- a/src/mod/applications/mod_av/avformat.c +++ b/src/mod/applications/mod_av/avformat.c @@ -1578,6 +1578,10 @@ static switch_status_t av_file_read(switch_file_handle_t *handle, void *data, si av_file_context_t *context = (av_file_context_t *)handle->private_info; int size; + if ((flags & SVR_CHECK)) { + return SWITCH_STATUS_BREAK; + } + if (!context->has_audio && context->has_video && switch_queue_size(context->eh.video_queue) > 0) { memset(data, 0, *len * handle->channels * 2); return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index eb2116cf5e..e300588f5b 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -1906,19 +1906,43 @@ static void check_flush(conference_member_t *member) } } -static void patch_fnode(conference_obj_t *conference, conference_file_node_t *fnode, switch_frame_t *write_frame) +static void patch_fnode(conference_obj_t *conference, conference_file_node_t *fnode) { if (fnode && fnode->layer_id > -1) { mcu_layer_t *layer = &conference->canvas->layers[fnode->layer_id]; - - if (switch_core_file_read_video(&fnode->fh, write_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { + switch_frame_t file_frame = { 0 }; + switch_status_t status = switch_core_file_read_video(&fnode->fh, &file_frame, SVR_FLUSH); + + if (status == SWITCH_STATUS_SUCCESS) { switch_img_free(&layer->cur_img); - layer->cur_img = write_frame->img; + layer->cur_img = file_frame.img; layer->tagged = 1; + } else if (status == SWITCH_STATUS_IGNORE) { + if (conference->canvas && fnode->layer_id > -1 ) { + canvas_del_fnode_layer(conference, fnode); + } } } } +static void fnode_check_video(conference_obj_t *conference, conference_file_node_t *fnode) { + if (switch_core_file_has_video(&fnode->fh) && switch_core_file_read_video(&fnode->fh, NULL, SVR_CHECK) == SWITCH_STATUS_BREAK) { + int full_screen = 0; + + if (fnode->fh.params) { + full_screen = switch_true(switch_event_get_header(fnode->fh.params, "full-screen")); + } + + if (full_screen) { + conference->canvas->play_file = 1; + conference->playing_video_file = 1; + } else { + canvas_set_fnode_layer(conference, fnode, -1); + } + } +} + + static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj) { conference_obj_t *conference = (conference_obj_t *) obj; @@ -2275,12 +2299,20 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_mutex_unlock(conference->member_mutex); - if (conference->async_fnode && conference->async_fnode->layer_id > -1) { - patch_fnode(conference, conference->async_fnode, &write_frame); - } + if (conference->async_fnode) { + if (conference->async_fnode->layer_id > -1) { + patch_fnode(conference, conference->async_fnode); + } else { + fnode_check_video(conference, conference->async_fnode); + } + } - if (conference->fnode && conference->fnode->layer_id > -1) { - patch_fnode(conference, conference->fnode, &write_frame); + if (conference->fnode) { + if (conference->fnode->layer_id > -1) { + patch_fnode(conference, conference->fnode); + } else { + fnode_check_video(conference, conference->fnode); + } } if (!conference->playing_video_file) { @@ -4989,24 +5021,6 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi return SWITCH_STATUS_SUCCESS; } -static void fnode_check_video(conference_obj_t *conference, conference_file_node_t *fnode) { - - if (switch_core_file_has_video(&fnode->fh)) { - int full_screen = 0; - - if (fnode->fh.params) { - full_screen = switch_true(switch_event_get_header(fnode->fh.params, "full-screen")); - } - - if (full_screen) { - conference->canvas->play_file = 1; - conference->playing_video_file = 1; - } else { - canvas_set_fnode_layer(conference, fnode, -1); - } - } -} - static void conference_command_handler(switch_live_array_t *la, const char *cmd, const char *sessid, cJSON *jla, void *user_data) { } diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c index 903db6506c..5277587b15 100644 --- a/src/mod/formats/mod_local_stream/mod_local_stream.c +++ b/src/mod/formats/mod_local_stream/mod_local_stream.c @@ -102,25 +102,45 @@ struct local_stream_source { switch_file_handle_t chime_fh; switch_queue_t *video_q; int has_video; + switch_image_t *blank_img; }; typedef struct local_stream_source local_stream_source_t; -static int do_rand(void) +static int do_rand(uint32_t count) { double r; int index; + + if (count < 3) return 0; + r = ((double) rand() / ((double) (RAND_MAX) + (double) (1))); - index = (int) (r * 9) + 1; + index = (int) (r * count) + 1; + return index; } +static void flush_video_queue(switch_queue_t *q) +{ + void *pop; + + if (switch_queue_size(q) == 0) { + return; + } + + while (switch_queue_trypop(q, &pop) == SWITCH_STATUS_SUCCESS) { + switch_image_t *img = (switch_image_t *) pop; + switch_img_free(&img); + } + +} + static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj) { local_stream_source_t *source = obj; switch_file_handle_t fh = { 0 }; local_stream_context_t *cp; - char file_buf[128] = "", path_buf[512] = ""; + char file_buf[128] = "", path_buf[512] = "", last_path[512]; switch_timer_t timer = { 0 }; int fd = -1; switch_buffer_t *audio_buffer; @@ -128,6 +148,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void switch_size_t used; int skip = 0; switch_memory_pool_t *temp_pool = NULL; + uint32_t dir_count = 0, do_shuffle = 0; switch_mutex_lock(globals.mutex); THREADS++; @@ -137,14 +158,14 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void source->prebuf = DEFAULT_PREBUFFER_SIZE; } + if (source->shuffle) { + do_shuffle = 1; + } + switch_queue_create(&source->video_q, 500, source->pool); switch_buffer_create_dynamic(&audio_buffer, 1024, source->prebuf + 10, 0); dist_buf = switch_core_alloc(source->pool, source->prebuf + 10); - if (source->shuffle) { - skip = do_rand(); - } - switch_thread_rwlock_create(&source->rwlock, source->pool); if (RUNNING) { @@ -171,6 +192,21 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void goto done; } + if (fd > -1) { + dir_count = 0; + while (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { + dir_count++; + } + lseek(fd, 0, SEEK_SET); + } else { + dir_count = switch_dir_count(source->dir_handle); + } + + if (do_shuffle) { + skip = do_rand(dir_count); + do_shuffle = 0; + } + switch_yield(1000000); while (RUNNING && !source->stopped) { @@ -204,11 +240,17 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } } + if (dir_count > 1 && !strcmp(last_path, path_buf)) { + continue; + } + if (skip > 0) { skip--; continue; } + switch_set_string(last_path, path_buf); + fname = path_buf; fh.prebuf = source->prebuf; fh.pre_buffer_datalen = source->prebuf; @@ -221,6 +263,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void continue; } + if (switch_core_timer_init(&timer, source->timer_name, source->interval, (int)source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n"); switch_dir_close(source->dir_handle); @@ -265,6 +308,8 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void retry: + source->has_video = switch_core_file_has_video(use_fh); + is_open = switch_test_flag(use_fh, SWITCH_FILE_OPEN); if (source->hup) { @@ -281,8 +326,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } } } - - + if (is_open) { if (switch_core_has_video() && switch_core_file_has_video(use_fh)) { switch_frame_t vid_frame = { 0 }; @@ -290,13 +334,21 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void if (switch_core_file_read_video(use_fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { if (vid_frame.img) { source->has_video = 1; - switch_queue_push(source->video_q, vid_frame.img); + + if (source->total) { + switch_queue_push(source->video_q, vid_frame.img); + } else { + flush_video_queue(source->video_q); + } } } + } else { + source->has_video = 0; } if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(use_fh); + if (use_fh == &source->chime_fh) { source->chime_counter = source->rate * source->chime_freq; } @@ -333,15 +385,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2 * source->channels); if (!source->total) { - switch_mutex_lock(source->mutex); - - while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) { - switch_image_t *img = (switch_image_t *) pop; - switch_img_free(&img); - } - - switch_mutex_unlock(source->mutex); - + flush_video_queue(source->video_q); } else { uint32_t bused = 0; @@ -371,7 +415,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } switch_mutex_unlock(source->mutex); - switch_mutex_lock(source->mutex); + while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) { switch_image_t *img = (switch_image_t *) pop; switch_image_t *imgcp = NULL; @@ -380,6 +424,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void switch_queue_push(source->context_list->video_q, img); } else { if (source->context_list) { + switch_mutex_lock(source->mutex); for (cp = source->context_list; cp && RUNNING; cp = cp->next) { if (cp->video_q) { imgcp = NULL; @@ -389,19 +434,18 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } } } + switch_mutex_unlock(source->mutex); } switch_img_free(&img); } } - switch_mutex_unlock(source->mutex); - } } } switch_core_timer_destroy(&timer); if (RUNNING && source->shuffle) { - skip = do_rand(); + skip = do_rand(dir_count); } } @@ -484,14 +528,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void switch_buffer_destroy(&audio_buffer); - if (source->video_q) { - void *pop; - - while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) { - switch_image_t *img = (switch_image_t *) pop; - switch_img_free(&img); - } - } + flush_video_queue(source->video_q); if (fd > -1) { close(fd); @@ -649,7 +686,22 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle if (!(context->ready && context->source->ready)) { return SWITCH_STATUS_FALSE; } - + + if (!context->source->has_video) { + if (frame && context->source->blank_img) { + switch_image_t *img = NULL; + + switch_img_copy(context->source->blank_img, &img); + frame->img = img; + return SWITCH_STATUS_SUCCESS; + } + return SWITCH_STATUS_IGNORE; + } + + if ((flags & SVR_CHECK)) { + return SWITCH_STATUS_BREAK; + } + while(context->ready && context->source->ready && (flags & SVR_FLUSH) && switch_queue_size(context->video_q) > 1) { if (switch_queue_trypop(context->video_q, &pop) == SWITCH_STATUS_SUCCESS) { switch_image_t *img = (switch_image_t *) pop; @@ -661,7 +713,7 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle return SWITCH_STATUS_FALSE; } - if ((flags && SVR_BLOCK)) { + if ((flags & SVR_BLOCK)) { status = switch_queue_pop(context->video_q, &pop); } else { status = switch_queue_trypop(context->video_q, &pop); @@ -673,6 +725,7 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle } frame->img = (switch_image_t *) pop; + return SWITCH_STATUS_SUCCESS; } @@ -694,10 +747,13 @@ static switch_status_t local_stream_file_read(switch_file_handle_t *handle, void if ((bytes = switch_buffer_read(context->audio_buffer, data, need))) { *len = bytes / 2 / handle->real_channels; } else { - if (need > 2560) { - need = 2560; + size_t blank = (handle->samplerate / 20) * 2 * handle->real_channels; + + if (need > blank) { + need = blank; } - memset(data, 255, need); + + memset(data, 0, need); *len = need / 2 / handle->real_channels; } switch_mutex_unlock(context->audio_mutex); @@ -780,6 +836,8 @@ static void launch_thread(const char *name, const char *path, switch_xml_t direc } } else if (!strcasecmp(var, "timer-name")) { source->timer_name = switch_core_strdup(source->pool, val); + } else if (!strcasecmp(var, "blank-img") && !zstr(val)) { + source->blank_img = switch_img_read_png(val, SWITCH_IMG_FMT_I420); } } diff --git a/src/mod/formats/mod_vlc/mod_vlc.c b/src/mod/formats/mod_vlc/mod_vlc.c index 6f10ac8400..7bedd16c22 100644 --- a/src/mod/formats/mod_vlc/mod_vlc.c +++ b/src/mod/formats/mod_vlc/mod_vlc.c @@ -1063,6 +1063,10 @@ static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, s size_t bytes = *len * sizeof(int16_t) * handle->channels, read; libvlc_state_t status; + if ((flags & SVR_CHECK)) { + return SWITCH_STATUS_BREAK; + } + if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) { return vlc_file_av_read(handle, data, len); } @@ -1143,7 +1147,7 @@ static switch_status_t vlc_file_read_video(switch_file_handle_t *handle, switch_ return SWITCH_STATUS_FALSE; } - if ((flags && SVR_BLOCK)) { + if ((flags & SVR_BLOCK)) { status = switch_queue_pop(vcontext->video_queue, &pop); } else { status = switch_queue_trypop(vcontext->video_queue, &pop); diff --git a/src/switch_apr.c b/src/switch_apr.c index a2ce5074b2..9abc3b7035 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -559,6 +559,34 @@ SWITCH_DECLARE(switch_status_t) switch_dir_close(switch_dir_t *thedir) return status; } +SWITCH_DECLARE(uint32_t) switch_dir_count(switch_dir_t *thedir) +{ + const char *name; + apr_int32_t finfo_flags = APR_FINFO_DIRENT | APR_FINFO_TYPE | APR_FINFO_NAME; + uint32_t count = 0; + + apr_dir_rewind(thedir->dir_handle); + + while (apr_dir_read(&(thedir->finfo), finfo_flags, thedir->dir_handle) == SWITCH_STATUS_SUCCESS) { + + if (thedir->finfo.filetype != APR_REG && thedir->finfo.filetype != APR_LNK) { + continue; + } + + if (!(name = thedir->finfo.fname)) { + name = thedir->finfo.name; + } + + if (name) { + count++; + } + } + + apr_dir_rewind(thedir->dir_handle); + + return count; +} + SWITCH_DECLARE(const char *) switch_dir_next_file(switch_dir_t *thedir, char *buf, switch_size_t len) { const char *fname = NULL;