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

This commit is contained in:
Anthony Minessale 2015-06-19 00:55:01 -05:00
parent 434d39d450
commit 385a3b545c
7 changed files with 175 additions and 65 deletions

View File

@ -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);
/** @} */

View File

@ -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 {

View File

@ -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;

View File

@ -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)
{
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;