]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7656 fix various edge cases with video and non video files mixed into a source...
authorAnthony Minessale <anthm@freeswitch.org>
Fri, 19 Jun 2015 05:55:01 +0000 (00:55 -0500)
committerAnthony Minessale <anthm@freeswitch.org>
Fri, 19 Jun 2015 05:57:02 +0000 (00:57 -0500)
src/include/switch_apr.h
src/include/switch_types.h
src/mod/applications/mod_av/avformat.c
src/mod/applications/mod_conference/mod_conference.c
src/mod/formats/mod_local_stream/mod_local_stream.c
src/mod/formats/mod_vlc/mod_vlc.c
src/switch_apr.c

index 0f872e229687dbe70cb434d1418ac6a98d71db41..55b6b85f5cf5928ba7bf0b7e417041e3266892f7 100644 (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);
 
 /** @} */
 
index c435106c38a3c0a00daf0ca243ad93cada982570..95220b15424fac9a614b156692edfbc061b5accb 100644 (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 {
index 80b17c516af9fc18f4c6628dd2f320a12bc0ff8b..9b897381b805f4dad64b13df2f8c5432e78d12b8 100644 (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;
index eb2116cf5eb7db89a59555c86f8152734a41e771..e300588f5b0121a83946d80e9d650efe88fb6434 100644 (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)
 {
 }
index 903db6506c6e013361ff87a780264f988eda09cf..5277587b15dd221aff1d5dd6093313ae6b70c74b 100644 (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);
                }
        }
 
index 6f10ac84001a1329d2238d11a833c132bf5d6cae..7bedd16c2223798455f826890dd9b8777a08e711 100644 (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);
index a2ce5074b2f345615f1e02e769ac1a2240a77f92..9abc3b70350c38f37409249663a1323d59f71566 100644 (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;