]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7503 FS-7514: A bunch of stuff:
authorAnthony Minessale <anthm@freeswitch.org>
Fri, 27 Feb 2015 05:51:04 +0000 (23:51 -0600)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:47:06 +0000 (12:47 -0500)
Get filehandles working with video in some cases (if using vlc://):
    mod_conference for play and record video (will record the canvas in mix mode or floor holder in non-mix mode)
    regular playback app should be able to play vlc streams

Add no-minimize-encoding member flag so particilar memebers can opt out of that setting and still get their own encoded stream (for bw related needs)

TODO:

  mod_vlc is a mess.  Find a way to merge video_context and file_context.  They are very similar and they are intertwined and messy.
  Find out why vlc creates messed up mp4 files that don't play everywhere
  Get VLC so it can record aac, mp4x webm

src/include/switch_core.h
src/include/switch_core_media.h
src/include/switch_module_interfaces.h
src/include/switch_types.h
src/mod/applications/mod_conference/mod_conference.c
src/mod/applications/mod_fsv/mod_fsv.c
src/mod/formats/mod_vlc/mod_vlc.c
src/switch_core_file.c
src/switch_core_media.c
src/switch_ivr_async.c
src/switch_ivr_play_say.c

index 581b2cbe43c5aa8400388c48a47dd9b10bdd74b1..015ca79361b26d1bf35c3facae43930fd4864c88 100644 (file)
@@ -1851,7 +1851,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(_In_ switch_file_handle_t
   \param len the amount of data to write from the buffer
   \return SWITCH_STATUS_SUCCESS with len adjusted to the bytes written if successful
 */
-SWITCH_DECLARE(switch_status_t) switch_core_file_write_video(_In_ switch_file_handle_t *fh, void *data, switch_size_t *len);
+SWITCH_DECLARE(switch_status_t) switch_core_file_write_video(_In_ switch_file_handle_t *fh, switch_frame_t *frame);
+SWITCH_DECLARE(switch_status_t) switch_core_file_read_video(switch_file_handle_t *fh, switch_frame_t *frame);
 
 /*!
   \brief Seek a position in a file
@@ -1890,6 +1891,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_get_string(_In_ switch_file_han
 SWITCH_DECLARE(switch_status_t) switch_core_file_close(_In_ switch_file_handle_t *fh);
 
 SWITCH_DECLARE(switch_status_t) switch_core_file_truncate(switch_file_handle_t *fh, int64_t offset);
+SWITCH_DECLARE(switch_bool_t) switch_core_file_has_video(switch_file_handle_t *fh);
 
 
 ///\}
index f7554422c36cf1e98c307f845561828791d47a79..d1bdaea5328a992b85616638efc777bc26f9a96d 100644 (file)
@@ -325,6 +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_END_EXTERN_C
 #endif
index 0a2dc0946a42494cf89fe1850f1fb57a55b8d72e..a5fe0035f60742e051a6731bc097506e02b26c77 100644 (file)
@@ -280,9 +280,9 @@ struct switch_file_interface {
        /*! function to write from the file */
        switch_status_t (*file_write) (switch_file_handle_t *, void *data, switch_size_t *len);
        /*! function to seek to a certian position in the file */
-       switch_status_t (*file_read_video) (switch_file_handle_t *, void *data, switch_size_t *len);
+       switch_status_t (*file_read_video) (switch_file_handle_t *, switch_frame_t *frame);
        /*! function to write from the file */
-       switch_status_t (*file_write_video) (switch_file_handle_t *, void *data, switch_size_t *len);
+       switch_status_t (*file_write_video) (switch_file_handle_t *, switch_frame_t *frame);
        /*! function to seek to a certian position in the file */
        switch_status_t (*file_seek) (switch_file_handle_t *, unsigned int *cur_pos, int64_t samples, int whence);
        /*! function to set meta data */
index b9415fd93eb11fcb016bee7247766d3cda7c22c9..020845acc652ec85cd2ceff641160d62148f8cbc 100644 (file)
@@ -1756,7 +1756,8 @@ typedef enum {
        SWITCH_FILE_WRITE_APPEND = (1 << 15),
        SWITCH_FILE_WRITE_OVER = (1 << 16),
        SWITCH_FILE_NOMUX = (1 << 17),
-       SWITCH_FILE_BREAK_ON_CHANGE = (1 << 18)
+       SWITCH_FILE_BREAK_ON_CHANGE = (1 << 18),
+       SWITCH_FILE_FLAG_VIDEO = (1 << 19)
 } switch_file_flag_enum_t;
 typedef uint32_t switch_file_flag_t;
 
index 064a2d26b18e0a93343ea77b336a23098ef2339b..a636bcc57c38e0dcfa67bdd3356b1f38d4f3f344 100644 (file)
@@ -201,7 +201,7 @@ typedef enum {
        MFLAG_ITHREAD = (1 << 4),
        MFLAG_NOCHANNEL = (1 << 5),
        MFLAG_INTREE = (1 << 6),
-       MFLAG_WASTE_FLAG = (1 << 7),
+       MFLAG_NO_MINIMIZE_ENCODING = (1 << 7),
        MFLAG_FLUSH_BUFFER = (1 << 8),
        MFLAG_ENDCONF = (1 << 9),
        MFLAG_HAS_AUDIO = (1 << 10),
@@ -460,6 +460,7 @@ typedef struct conference_obj {
        char *video_layout_group;
        char *video_canvas_bgcolor;
        char *video_layout_bgcolor;
+       int members_with_video;
        int video_timer_reset;
        int32_t video_write_bandwidth;
        switch_codec_settings_t video_codec_settings;
@@ -544,7 +545,6 @@ typedef struct conference_obj {
        conference_record_t *rec_node_head;
        int last_speech_channels;
        switch_file_handle_t *record_fh;
-       int video_recording;
        switch_thread_t *video_muxing_thread;
        mcu_canvas_t *canvas;
        switch_hash_t *layout_hash;
@@ -1502,6 +1502,10 @@ static void write_canvas_image_to_codec_group(conference_obj_t *conference, code
 
                        switch_mutex_lock(conference->member_mutex);
                        for (imember = conference->members; imember; imember = imember->next) {
+                               if (switch_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) {
+                                       continue;
+                               }
+
                                if (imember->video_codec_index != codec_index) {
                                        continue;
                                }
@@ -1576,6 +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;
 
 #ifdef TRACK_FPS
        uint64_t frames = 0;
@@ -1600,13 +1605,12 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
 
        conference->video_timer_reset = 1;
        
-       if (!switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) {
-               packet = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
-       }
+       packet = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
 
        while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT) && switch_test_flag(conference, CFLAG_VIDEO_MUXING)) {
                switch_bool_t need_refresh = SWITCH_FALSE, need_keyframe = SWITCH_FALSE, need_reset = SWITCH_FALSE;
                switch_time_t now;
+               int min_members = 0;
 
                if (conference->video_timer_reset) {
                        conference->video_timer_reset = 0;
@@ -1631,6 +1635,10 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                                continue;
                        }                       
 
+                       if (switch_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) {
+                               min_members++;
+                       }
+
                        if (conference->canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder && 
                                imember->video_layer_id != conference->canvas->layout_floor_id) {
                                attach_video_layer(imember, conference->canvas->layout_floor_id);
@@ -1832,9 +1840,22 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                        last_key_time = now;
                }
                        
-               if (switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) {
+               write_img = conference->canvas->img;
+
+               if (conference->fnode) {
+                       if (switch_core_file_read_video(&conference->fnode->fh, &write_frame) == SWITCH_STATUS_SUCCESS) {
+                               write_img = free_img = write_frame.img;
+                       }
+               }
+
+               if (conference->record_fh) {
+                       write_frame.img = write_img;
+                       switch_core_file_write_video(conference->record_fh, &write_frame);
+               }
+
+               if (min_members && switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) {
                        for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) {
-                               write_codecs[i]->frame.img = conference->canvas->img;
+                               write_codecs[i]->frame.img = write_img;
                                write_canvas_image_to_codec_group(conference, write_codecs[i], i, 
                                                                                                  conference->canvas->timer.samplecount, need_refresh, need_keyframe, need_reset);
 
@@ -1844,32 +1865,39 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                                }
 
                        }
-               } else {
-                       switch_mutex_lock(conference->member_mutex);
-                       for (imember = conference->members; imember; imember = imember->next) {
+               }
 
-                               if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) ||
-                                       switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) {
-                                       continue;
-                               }
+               switch_mutex_lock(conference->member_mutex);
+               for (imember = conference->members; imember; imember = imember->next) {
 
-                               switch_set_flag(&write_frame, SFF_RAW_RTP);
-                               write_frame.img = conference->canvas->img;
-                               write_frame.packet = packet;
-                               write_frame.data = packet + 12;
-                               write_frame.datalen = SWITCH_RECOMMENDED_BUFFER_SIZE - 12;
-                               write_frame.buflen = write_frame.datalen;
-                               write_frame.packetlen = SWITCH_RECOMMENDED_BUFFER_SIZE;
+                       if (switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING) && !switch_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) {
+                               continue;
+                       }
 
-                               switch_core_session_write_video_frame(imember->session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
+                       if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) ||
+                               switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) {
+                               continue;
+                       }
 
-                               if (imember->session) {
-                                       switch_core_session_rwunlock(imember->session);
-                               }
+
+                       switch_set_flag(&write_frame, SFF_RAW_RTP);
+                       write_frame.img = write_img;
+                       write_frame.packet = packet;
+                       write_frame.data = packet + 12;
+                       write_frame.datalen = SWITCH_RECOMMENDED_BUFFER_SIZE - 12;
+                       write_frame.buflen = write_frame.datalen;
+                       write_frame.packetlen = SWITCH_RECOMMENDED_BUFFER_SIZE;
+
+                       switch_core_session_write_video_frame(imember->session, &write_frame, SWITCH_IO_FLAG_NONE, 0);
+
+                       if (imember->session) {
+                               switch_core_session_rwunlock(imember->session);
                        }
-                       switch_mutex_unlock(conference->member_mutex);
                }
+               switch_mutex_unlock(conference->member_mutex);
+               
 
+               switch_img_free(&free_img);
        }
 
        for (i = 0; i < MCU_MAX_LAYERS; i++) {
@@ -4317,24 +4345,6 @@ static void conference_write_video_frame(conference_obj_t *conference, conferenc
        }
        switch_mutex_unlock(conference->member_mutex);
 
-       /* seems we are recording a video file */
-       switch_mutex_lock(conference->mutex);
-       if (conference->record_fh) {
-               switch_size_t len = vid_frame->packetlen;
-               if (!conference->video_recording) {
-                       want_refresh++;
-                       conference->video_recording++;
-               } else {
-                       if (len > 14) { // 14 = 12(rtp) + 2(cng?)
-                               switch_core_file_write_video(conference->record_fh, vid_frame->packet, &len);
-                       }
-               }
-       } else {
-               conference->video_recording = 0;
-       }
-
-       switch_mutex_unlock(conference->mutex);
-
        if (want_refresh && floor_holder->session) {
                switch_core_session_request_video_refresh(floor_holder->session);
        }
@@ -4395,6 +4405,9 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
        if (member) {
                if (member->id == member->conference->video_floor_holder) {
                        conference_write_video_frame(member->conference, member, frame);
+                       if (frame->img && member->conference->record_fh) {
+                               switch_core_file_write_video(member->conference->record_fh, frame);
+                       }
                } else if (!switch_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK) && member->id == member->conference->last_video_floor_holder) {
                        conference_member_t *fmember;
 
@@ -4541,6 +4554,8 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
                        switch_mutex_unlock(imember->audio_in_mutex);
                }
                
+               conference->members_with_video = members_with_video;
+
                if (floor_holder != conference->floor_holder) {
                        conference_set_floor_holder(conference, floor_holder);
                }
@@ -6494,6 +6509,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
        switch_event_t *event;
        switch_size_t len = 0;
        char *ext;
+       int flags = 0;
 
        data_buf_len = samples * sizeof(int16_t);
 
@@ -6565,11 +6581,14 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
                }
        }
 
-       if (switch_core_file_open(&fh,
-                                                         rec->path, (uint8_t) conference->channels, conference->rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT,
-                                                         rec->pool) != SWITCH_STATUS_SUCCESS) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s]\n", rec->path);
+       flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT;
+
+       if (conference->members_with_video && switch_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) {
+               flags |= SWITCH_FILE_FLAG_VIDEO;
+       }
 
+       if (switch_core_file_open(&fh, rec->path, (uint8_t) conference->channels, conference->rate, flags, rec->pool) != SWITCH_STATUS_SUCCESS) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s]\n", rec->path);
 
                if (test_eflag(conference, EFLAG_RECORD) &&
                        switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
@@ -6850,6 +6869,7 @@ static switch_status_t conference_play_file(conference_obj_t *conference, char *
        int say = 0;
        uint8_t channels = (uint8_t) conference->channels;
        int bad_params = 0;
+       int flags = 0;
 
        switch_assert(conference != NULL);
 
@@ -6933,9 +6953,15 @@ static switch_status_t conference_play_file(conference_obj_t *conference, char *
        
  retry:
 
+       flags = SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT;
+
+       if (conference->members_with_video && switch_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) {
+               flags |= SWITCH_FILE_FLAG_VIDEO;
+       }
+
        /* Open the file */
        fnode->fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
-       if (switch_core_file_open(&fnode->fh, file, channels, conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, pool) !=
+       if (switch_core_file_open(&fnode->fh, file, channels, conference->rate, flags, pool) !=
                SWITCH_STATUS_SUCCESS) {
                switch_event_t *event;
 
@@ -10696,6 +10722,8 @@ static void set_mflags(const char *flags, member_flag_t *f)
                                *f |= MFLAG_NO_POSITIONAL;
                        } else if (!strcasecmp(argv[i], "join-vid-floor")) {
                                *f |= MFLAG_JOIN_VID_FLOOR;
+                       } else if (!strcasecmp(argv[i], "no-minimize-encoding")) {
+                               *f |= MFLAG_NO_MINIMIZE_ENCODING;
                        }
                }
 
index 8f703e8776f7ff8e7a188d4bd2c64a905efdbfa1..d57d316e5788a5ff6a2cddbf3aacdaeefb83e979 100644 (file)
@@ -951,6 +951,7 @@ static switch_status_t fsv_file_write(switch_file_handle_t *handle, void *data,
        return status;
 }
 
+#if 0
 static switch_status_t fsv_file_write_video(switch_file_handle_t *handle, void *data, size_t *len)
 {
        uint32_t datalen = (uint32_t)*len;
@@ -978,6 +979,7 @@ static switch_status_t fsv_file_write_video(switch_file_handle_t *handle, void *
 
        return status;
 }
+#endif
 
 static switch_status_t fsv_file_set_string(switch_file_handle_t *handle, switch_audio_col_t col, const char *string)
 {
@@ -1011,7 +1013,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_fsv_load)
        file_interface->file_truncate = fsv_file_truncate;
        file_interface->file_read = fsv_file_read;
        file_interface->file_write = fsv_file_write;
+#if 0
        file_interface->file_write_video = fsv_file_write_video;
+#endif
        file_interface->file_seek = fsv_file_seek;
        file_interface->file_set_string = fsv_file_set_string;
        file_interface->file_get_string = fsv_file_get_string;
index 41f20cf35a2c5fb0dbdbda4bbe60a2a9a96df307..2ea8074bd2ae8bb168e929c88475b3081fef6d01 100644 (file)
@@ -65,13 +65,15 @@ typedef void (*imem_release_t)(void *data, const char *cookie, size_t, void *);
 const char *vlc_args[] = {""};
 // const char *vlc_args[] = {"--network-caching", "500"};
 
-libvlc_instance_t *read_inst;
+
 switch_endpoint_interface_t *vlc_endpoint_interface = NULL;
 
 typedef struct vlc_frame_data_s {
        int64_t pts;
 } vlc_frame_data_t;
 
+struct vlc_video_context;
+
 struct vlc_file_context {
        libvlc_media_player_t *mp;
        libvlc_media_t *m;
@@ -90,6 +92,8 @@ struct vlc_file_context {
        libvlc_instance_t *inst_out;
        void *frame_buffer;
        switch_size_t frame_buffer_len;
+       libvlc_instance_t *vlc_handle;
+       struct vlc_video_context *vcontext;
 };
 
 typedef struct vlc_file_context vlc_file_context_t;
@@ -124,6 +128,7 @@ struct vlc_video_context {
        int channels;
        int samplerate;
        int samples;
+       int err;
        //int pts;
        void *video_frame_buffer;
        switch_size_t video_frame_buffer_len;
@@ -131,6 +136,7 @@ struct vlc_video_context {
        switch_size_t audio_frame_buffer_len;
        switch_timer_t timer;
        int64_t pts;
+       libvlc_instance_t *vlc_handle;
 };
 
 typedef struct vlc_video_context vlc_video_context_t;
@@ -139,6 +145,10 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_vlc_shutdown);
 SWITCH_MODULE_LOAD_FUNCTION(mod_vlc_load);
 SWITCH_MODULE_DEFINITION(mod_vlc, mod_vlc_load, mod_vlc_shutdown, NULL);
 
+static int vlc_write_video_imem_get_callback(void *data, const char *cookie, int64_t *dts, int64_t *pts, unsigned *flags, size_t *size, void **output);
+void vlc_write_video_imem_release_callback(void *data, const char *cookie, size_t size, void *unknown);
+static switch_status_t av_init_handle(switch_file_handle_t *handle, switch_image_t *img);
+
 void yuyv_to_i420(uint8_t *pixels, void *out_buffer, int src_width, int src_height)
 {
        uint8_t *Y, *U, *V;
@@ -171,10 +181,14 @@ static void vlc_mediaplayer_error_callback(const libvlc_event_t * event, void *
         int status = libvlc_media_get_state(context->m);
         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got a libvlc_MediaPlayerEncounteredError callback. mediaPlayer Status: %d\n", status);
         if (status == libvlc_Error) {
-               context->err = 1;
-               switch_thread_cond_signal(context->cond);
-            }
+                       context->err = 1;
+                       if (switch_mutex_lock(context->audio_mutex) == SWITCH_STATUS_SUCCESS) {
+                               switch_thread_cond_signal(context->cond);
+                               switch_mutex_unlock(context->audio_mutex);
+                       }
+               }
 }
+
 static void vlc_media_state_callback(const libvlc_event_t * event, void * data)
 {
         vlc_file_context_t *context = (vlc_file_context_t *) data;
@@ -182,12 +196,45 @@ static void vlc_media_state_callback(const libvlc_event_t * event, void * data)
 
         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got a libvlc_MediaStateChanged callback. New state: %d\n", new_state);
         if (new_state == libvlc_Ended || new_state == libvlc_Error) {
-                switch_thread_cond_signal(context->cond);
+                       if (switch_mutex_lock(context->audio_mutex) == SWITCH_STATUS_SUCCESS) {
+                               switch_thread_cond_signal(context->cond);
+                               switch_mutex_unlock(context->audio_mutex);
+                       }
         }
 }
 
 
 
+static void vlc_mediaplayer_av_error_callback(const libvlc_event_t * event, void * data)
+{
+       vlc_video_context_t *context = (vlc_video_context_t *) data;
+       int status = libvlc_media_get_state(context->m);
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got a libvlc_MediaPlayerEncounteredError callback. mediaPlayer Status: %d\n", status);
+       if (status == libvlc_Error) {
+               context->err = 1;
+               if (switch_mutex_lock(context->audio_mutex) == SWITCH_STATUS_SUCCESS) {
+                       switch_thread_cond_signal(context->cond);
+                       switch_mutex_unlock(context->audio_mutex);
+               }
+       }
+}
+static void vlc_media_av_state_callback(const libvlc_event_t * event, void * data)
+{
+       vlc_video_context_t *context = (vlc_video_context_t *) data;
+       int new_state = event->u.media_state_changed.new_state;
+       
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Got a libvlc_MediaStateChanged callback. New state: %d\n", new_state);
+       if (new_state == libvlc_Ended || new_state == libvlc_Error) {
+               if (switch_mutex_lock(context->audio_mutex) == SWITCH_STATUS_SUCCESS) {
+                       switch_thread_cond_signal(context->cond);
+                       switch_mutex_unlock(context->audio_mutex);
+               }
+       }
+}
+
+
+
 void vlc_auto_play_callback(void *data, const void *samples, unsigned count, int64_t pts) {
 
        vlc_file_context_t *context = (vlc_file_context_t *) data;
@@ -232,6 +279,19 @@ void vlc_play_audio_callback(void *data, const void *samples, unsigned count, in
        // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "VLC callback, play audio: %d \n", count);
 }
 
+static void vlc_video_av_unlock_callback(void *data, void *id, void *const *p_pixels)
+{
+       vlc_video_context_t *context = (vlc_video_context_t *) data;
+
+       if (!context->img) context->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, context->width, context->height, 0);
+
+       switch_assert(context->img);
+
+       yuyv_to_i420(*p_pixels, context->img->img_data, context->width, context->height);
+
+       switch_mutex_unlock(context->video_mutex);
+}
+
 static void *vlc_video_lock_callback(void *data, void **p_pixels)
 {
        vlc_video_context_t *context = (vlc_video_context_t *)data;
@@ -354,7 +414,7 @@ static int i420_size(int width, int height)
 #endif
 
 
-int  vlc_imem_get_callback(void *data, const char *cookie, int64_t *dts, int64_t *pts, unsigned *flags, size_t *size, void **output)
+static int vlc_imem_get_callback(void *data, const char *cookie, int64_t *dts, int64_t *pts, unsigned *flags, size_t *size, void **output)
 {
        vlc_file_context_t *context = (vlc_file_context_t *) data;
        //int samples = 0;
@@ -396,6 +456,196 @@ void vlc_imem_release_callback(void *data, const char *cookie, size_t size, void
        //free(unknown);
 }
 
+static switch_status_t av_init_handle(switch_file_handle_t *handle, switch_image_t *img) 
+{
+       vlc_file_context_t *acontext = (vlc_file_context_t *) handle->private_info;
+       vlc_video_context_t *vcontext = acontext->vcontext;
+       switch_memory_pool_t *pool = acontext->pool;
+       int64_t pts = 0;
+       char *imem_main, *imem_slave;
+    unsigned char audio_data_buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
+       void *audio_data;
+       switch_size_t audio_datalen;
+       uint32_t offset = 500;
+       const char *tmp;
+       const char * opts[25] = {
+               *vlc_args,
+               switch_core_sprintf(acontext->pool, "--sout=%s", acontext->path)
+       };
+       int argc = 2;
+
+       vcontext = switch_core_alloc(acontext->pool, sizeof(vlc_video_context_t));
+
+       if (handle->params && (tmp = switch_event_get_header(handle->params, "vlc_capture_offset"))) {
+               int x = atoi(tmp);
+               if (x >= 0) offset = x;
+       }
+
+       vcontext->channels = handle->channels;
+       vcontext->pool = pool;
+       vcontext->playing = 0;
+       vcontext->samplerate = handle->samplerate;
+
+       switch_queue_create(&vcontext->video_queue, SWITCH_CORE_QUEUE_LEN, vcontext->pool);
+
+       switch_buffer_create_dynamic(&(vcontext->audio_buffer), VLC_BUFFER_SIZE, VLC_BUFFER_SIZE * 8, 0);
+       switch_mutex_init(&vcontext->audio_mutex, SWITCH_MUTEX_NESTED, vcontext->pool);
+       switch_mutex_init(&vcontext->video_mutex, SWITCH_MUTEX_NESTED, vcontext->pool);
+       switch_thread_cond_create(&vcontext->cond, vcontext->pool);
+
+       switch_core_timer_init(&vcontext->timer, "soft", 1, 1000, vcontext->pool);
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for writing\n", acontext->path);
+
+       opts[argc++] = switch_core_sprintf(vcontext->pool, "--imem-get=%ld", vlc_write_video_imem_get_callback);
+       opts[argc++] = switch_core_sprintf(vcontext->pool, "--imem-release=%ld", vlc_write_video_imem_release_callback);
+       opts[argc++] = switch_core_sprintf(vcontext->pool, "--imem-data=%ld", vcontext);
+
+       acontext->inst_out = libvlc_new(argc, opts);
+       
+       imem_main = switch_core_sprintf(vcontext->pool,
+                                                                                       "imem://cookie=video:"
+                                                                                       "fps=15.0/1:"
+                                                                                       "width=%d:"
+                                                                                       "height=%d:"
+                                                                                       "codec=YUYV:"
+                                                                                       "cat=2:"
+                                                                                       "id=2:"
+                                                                                       "caching=0",
+                                                                                       img->d_w, img->d_h);
+
+       imem_slave = switch_core_sprintf(vcontext->pool,
+                                                                                        ":input-slave=imem://cookie=audio:"
+                                                                                        "cat=1:"
+                                                                                        "codec=s16l:"
+                                                                                        "samplerate=%d:"
+                                                                                        "channels=%d:"
+                                                                                        "id=1:"
+                                                                                        "caching=0", 
+                                                                                        vcontext->samplerate, vcontext->channels);
+       
+       vcontext->m = libvlc_media_new_location(acontext->inst_out, imem_main);
+       
+       libvlc_media_add_option_flag( vcontext->m, imem_slave, libvlc_media_option_trusted );                                                                       
+
+       if (vcontext->m == NULL) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error opening %s for writing\n", acontext->path);
+               return SWITCH_STATUS_FALSE;
+       }
+       
+       vcontext->mp = libvlc_media_player_new_from_media(vcontext->m);
+
+       vcontext->samples = 0;
+       vcontext->pts = 0;
+
+       if (offset) {
+               uint32_t need = (handle->samplerate / 1000) * offset * handle->channels;
+               uint32_t off_frames = need / SWITCH_RECOMMENDED_BUFFER_SIZE;
+               uint32_t rem = need % SWITCH_RECOMMENDED_BUFFER_SIZE;
+               int i = 0;
+
+               vcontext->sync_offset = offset;
+               switch_mutex_lock(vcontext->audio_mutex);
+
+               switch_core_timer_sync(&vcontext->timer);
+               pts = vcontext->timer.samplecount;
+               switch_buffer_write(vcontext->audio_buffer, &pts, sizeof(pts));
+
+               audio_data = audio_data_buf;
+
+               if (off_frames) {
+                       audio_datalen = SWITCH_RECOMMENDED_BUFFER_SIZE;
+
+                       for (i = 0; i < off_frames; i++) {
+                               switch_buffer_write(vcontext->audio_buffer, audio_data, audio_datalen);
+                       }
+               }
+
+               if (rem) {
+                       audio_datalen = rem;
+                       switch_buffer_write(vcontext->audio_buffer, audio_data, audio_datalen);
+               }
+
+               switch_mutex_unlock(vcontext->audio_mutex);
+       }
+       
+       acontext->vcontext = vcontext;
+       
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t vlc_file_av_open(switch_file_handle_t *handle, const char *path)
+{
+       vlc_file_context_t *acontext = (vlc_file_context_t *) handle->private_info;
+       vlc_video_context_t *vcontext;
+       libvlc_event_manager_t *mp_event_manager, *m_event_manager;
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for reading\n", acontext->path);
+
+       vcontext = switch_core_alloc(acontext->pool, sizeof(vlc_video_context_t));
+       vcontext->pool = acontext->pool;
+       acontext->vcontext = vcontext;
+
+       /* Determine if this is a url or a path */
+       /* TODO: Change this so that it tries local files first, and then if it fails try location. */
+       if(! strncmp(acontext->path, "http", 4)){
+               vcontext->m = libvlc_media_new_location(acontext->vlc_handle, acontext->path);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is http %s\n", acontext->path);
+       } else if (! strncmp(acontext->path, "rtp", 3)){
+               vcontext->m = libvlc_media_new_path(acontext->vlc_handle, acontext->path);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is rtp %s\n", acontext->path);
+       } else if (! strncmp(acontext->path, "mms", 3)){
+               vcontext->m = libvlc_media_new_path(acontext->vlc_handle, acontext->path);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is mms %s\n", acontext->path);
+       } else if (! strncmp(acontext->path, "/", 1)){
+               vcontext->m = libvlc_media_new_path(acontext->vlc_handle, acontext->path);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is file %s\n", acontext->path);
+       } else {
+               vcontext->m = libvlc_media_new_location(acontext->vlc_handle, acontext->path);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is unknown type %s\n", acontext->path);
+       }
+
+       if (vcontext->m == NULL) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error opening %s for reading\n", path);
+               return SWITCH_STATUS_GENERR;
+       }
+
+       vcontext->playing = 0;
+       vcontext->err = 0;
+       
+       vcontext->mp = libvlc_media_player_new_from_media(vcontext->m);
+
+       if (!handle->samplerate) {
+               handle->samplerate = 16000;
+       }
+
+       switch_mutex_init(&vcontext->audio_mutex, SWITCH_MUTEX_NESTED, vcontext->pool);
+       switch_mutex_init(&vcontext->video_mutex, SWITCH_MUTEX_NESTED, vcontext->pool);
+       switch_queue_create(&vcontext->video_queue, SWITCH_CORE_QUEUE_LEN, vcontext->pool);
+       switch_thread_cond_create(&vcontext->cond, vcontext->pool);
+       switch_buffer_create_dynamic(&vcontext->audio_buffer, VLC_BUFFER_SIZE, VLC_BUFFER_SIZE * 8, 0);
+
+       vcontext->samplerate = handle->samplerate;
+       vcontext->channels = handle->channels;
+
+       libvlc_audio_set_format(vcontext->mp, "S16N", vcontext->samplerate, handle->channels);
+               
+       m_event_manager = libvlc_media_event_manager(vcontext->m);
+       libvlc_event_attach(m_event_manager, libvlc_MediaStateChanged, vlc_media_av_state_callback, (void *) vcontext);
+
+       mp_event_manager = libvlc_media_player_event_manager(vcontext->mp);
+       libvlc_event_attach(mp_event_manager, libvlc_MediaPlayerEncounteredError, vlc_mediaplayer_av_error_callback, (void *) vcontext);
+               
+       libvlc_audio_set_callbacks(vcontext->mp, vlc_play_audio_callback, NULL,NULL,NULL,NULL, (void *) vcontext);
+       
+       libvlc_video_set_format_callbacks(vcontext->mp, video_format_setup_callback, video_format_clean_callback);
+       libvlc_video_set_callbacks(vcontext->mp, vlc_video_lock_callback, vlc_video_av_unlock_callback, vlc_video_display_callback, vcontext);
+
+       libvlc_media_player_play(vcontext->mp);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *path)
 {
        vlc_file_context_t *context;
@@ -403,33 +653,40 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p
        
        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);
 
-       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);
-       switch_thread_cond_create(&(context->cond), context->pool);
+       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);
+               switch_thread_cond_create(&(context->cond), context->pool);
+       }
+
+       handle->private_info = context;
 
        if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) {
+               if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
+                       return vlc_file_av_open(handle, path);
+               }
 
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for reading\n", path);
 
                /* Determine if this is a url or a path */
                /* TODO: Change this so that it tries local files first, and then if it fails try location. */
                if(! strncmp(context->path, "http", 4)){
-                       context->m = libvlc_media_new_location(read_inst, context->path);
+                       context->m = libvlc_media_new_location(context->vlc_handle, context->path);
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is http %s\n", context->path);
                } else if (! strncmp(context->path, "rtp", 3)){
-                       context->m = libvlc_media_new_path(read_inst, context->path);
+                       context->m = libvlc_media_new_path(context->vlc_handle, context->path);
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is rtp %s\n", context->path);
                } else if (! strncmp(context->path, "mms", 3)){
-                       context->m = libvlc_media_new_path(read_inst, context->path);
+                       context->m = libvlc_media_new_path(context->vlc_handle, context->path);
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is mms %s\n", context->path);
                } else if (! strncmp(context->path, "/", 1)){
-                       context->m = libvlc_media_new_path(read_inst, context->path);
+                       context->m = libvlc_media_new_path(context->vlc_handle, context->path);
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is file %s\n", context->path);
                } else {
-                       context->m = libvlc_media_new_location(read_inst, context->path);
+                       context->m = libvlc_media_new_location(context->vlc_handle, context->path);
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is unknown type %s\n", context->path);
                }
 
@@ -462,7 +719,7 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p
 
                libvlc_media_player_play(context->mp);
 
-       } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
+       } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE) && !switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
                const char * opts[25] = {
                        *vlc_args,
                        switch_core_sprintf(context->pool, "--sout=%s", path)
@@ -498,12 +755,59 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p
                context->mp = libvlc_media_player_new_from_media(context->m);
                context->samples = 0;
                context->pts = 0;
-       } else {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC tried to open %s for unknown reason\n", path);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t vlc_file_av_read(switch_file_handle_t *handle, void *data, size_t *len)
+{
+       vlc_file_context_t *acontext = handle->private_info;
+       vlc_video_context_t *vcontext = acontext->vcontext;
+
+       size_t bytes = *len * sizeof(int16_t) * handle->channels, read;
+       libvlc_state_t status;
+
+       if (vcontext->err) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error\n");
                return SWITCH_STATUS_GENERR;
        }
 
-       handle->private_info = context;
+       status = libvlc_media_get_state(vcontext->m);
+       
+       if (status == libvlc_Error) {
+               return SWITCH_STATUS_GENERR;
+       }
+
+       switch_mutex_lock(vcontext->audio_mutex); 
+       while (vcontext->playing == 0 && status != libvlc_Ended && status != libvlc_Error) {
+               switch_thread_cond_wait(vcontext->cond, vcontext->audio_mutex);         
+               status = libvlc_media_get_state(vcontext->m);
+       }
+
+       if (vcontext->err == 1) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error\n");
+               return SWITCH_STATUS_FALSE;
+       }
+
+       switch_mutex_unlock(vcontext->audio_mutex);
+
+       switch_mutex_lock(vcontext->audio_mutex);
+       read = switch_buffer_read(vcontext->audio_buffer, data, bytes);
+       switch_mutex_unlock(vcontext->audio_mutex);
+       
+       status = libvlc_media_get_state(vcontext->m);
+
+       if (!read && (status == libvlc_Stopped || status == libvlc_Ended || status == libvlc_Error)) {
+               return SWITCH_STATUS_FALSE;
+       } else if (!read) {
+               read = 2;
+               memset(data, 0, read);
+       }
+
+       if (read) {
+               *len = read / 2 / handle->channels;
+       }
 
        return SWITCH_STATUS_SUCCESS;
 }
@@ -514,6 +818,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 (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
+               return vlc_file_av_read(handle, data, len);
+       }
+
        if (!context) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC read handle context is NULL\n");
                return SWITCH_STATUS_GENERR;
@@ -547,7 +855,7 @@ static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, s
        read = switch_buffer_read(context->audio_buffer, data, bytes);
        switch_mutex_unlock(context->audio_mutex);
        
-        status = libvlc_media_get_state(context->m);
+       status = libvlc_media_get_state(context->m);
 
        if (!read && (status == libvlc_Stopped || status == libvlc_Ended || status == libvlc_Error)) {
                return SWITCH_STATUS_FALSE;
@@ -563,11 +871,107 @@ static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, s
        return SWITCH_STATUS_SUCCESS;
 }
 
+static switch_status_t vlc_file_read_video(switch_file_handle_t *handle, switch_frame_t *frame)
+{
+       vlc_file_context_t *acontext = (vlc_file_context_t *) handle->private_info;
+       vlc_video_context_t *vcontext = acontext->vcontext;
+       void *pop;
+
+       if (switch_queue_pop(vcontext->video_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
+               frame->img = (switch_image_t *) pop;
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       return SWITCH_STATUS_BREAK;
+}
+
+static switch_status_t vlc_file_write_video(switch_file_handle_t *handle, switch_frame_t *frame)
+{
+       vlc_file_context_t *acontext = (vlc_file_context_t *) handle->private_info;
+       vlc_video_context_t *vcontext = acontext->vcontext;
+       switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+       if (!frame->img) {
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if (!vcontext) {
+               if ((status = av_init_handle(handle, frame->img)) != SWITCH_STATUS_SUCCESS) {
+                       return status;
+               }
+               vcontext = acontext->vcontext;
+
+               switch_mutex_lock(vcontext->audio_mutex);
+               switch_buffer_zero(vcontext->audio_buffer);
+               switch_mutex_unlock(vcontext->audio_mutex);
+       }
+
+       if (frame->img) {
+               unsigned int size = switch_queue_size(vcontext->video_queue);
+               switch_image_t *img_copy = NULL;
+               vlc_frame_data_t *fdata = NULL;
+
+               switch_img_copy(frame->img, &img_copy);
+               switch_zmalloc(fdata, sizeof(*fdata));
+
+               switch_mutex_lock(vcontext->audio_mutex);
+               switch_core_timer_sync(&vcontext->timer);
+               fdata->pts = vcontext->timer.samplecount;
+               switch_mutex_unlock(vcontext->audio_mutex);
+               
+               img_copy->user_priv = (void *) fdata;
+               switch_queue_push(vcontext->video_queue, img_copy);
+
+               if (!size) { /* was empty before this push */
+                       if (switch_mutex_trylock(vcontext->video_mutex) == SWITCH_STATUS_SUCCESS) {
+                               switch_thread_cond_signal(vcontext->cond);
+                               switch_mutex_unlock(vcontext->video_mutex);
+                       }
+               }
+       }
+
+       return status;
+}
+
+static switch_status_t vlc_file_av_write(switch_file_handle_t *handle, void *data, size_t *len)
+{
+       vlc_file_context_t *acontext = handle->private_info;
+       vlc_video_context_t *vcontext = acontext->vcontext;
+       size_t bytes = *len * sizeof(int16_t) * handle->channels;
+       int64_t pts;
+
+       if (!vcontext) {
+               return SWITCH_STATUS_SUCCESS;
+       }       
+
+       switch_mutex_lock(vcontext->audio_mutex);
+       if (!switch_buffer_inuse(vcontext->audio_buffer)) {
+               switch_core_timer_sync(&vcontext->timer);
+               pts = vcontext->timer.samplecount - vcontext->sync_offset;
+               switch_buffer_write(vcontext->audio_buffer, &pts, sizeof(pts));
+       }
+
+       switch_buffer_write(vcontext->audio_buffer, data, bytes);
+       switch_mutex_unlock(vcontext->audio_mutex);
+
+
+       if (!vcontext->playing) {
+               vcontext->playing = 1;          
+               libvlc_media_player_play(vcontext->mp);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static switch_status_t vlc_file_write(switch_file_handle_t *handle, void *data, size_t *len)
 {
        vlc_file_context_t *context = handle->private_info;
        size_t bytes = *len * sizeof(int16_t) * handle->channels;
-       
+
+       if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
+               return vlc_file_av_write(handle, data, len);
+       }
+
        switch_mutex_lock(context->audio_mutex);
        context->samples += *len;
        switch_buffer_write(context->audio_buffer, data, bytes);
@@ -581,9 +985,60 @@ static switch_status_t vlc_file_write(switch_file_handle_t *handle, void *data,
        return SWITCH_STATUS_SUCCESS;
 }
 
+static switch_status_t vlc_file_av_close(switch_file_handle_t *handle)
+{
+       vlc_file_context_t *acontext = handle->private_info;
+       vlc_video_context_t *vcontext = acontext->vcontext;
+
+       vcontext->ending = 1;
+       
+       if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE) && switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
+
+               if (switch_mutex_trylock(vcontext->video_mutex) == SWITCH_STATUS_SUCCESS) {
+                       switch_thread_cond_signal(vcontext->cond);
+                       switch_mutex_unlock(vcontext->video_mutex);
+               }
+
+               while(switch_buffer_inuse(vcontext->audio_buffer) || switch_queue_size(vcontext->video_queue)) {
+                       libvlc_state_t status = libvlc_media_get_state(vcontext->m);
+                       
+                       if (status == libvlc_Ended || status == libvlc_Error || status == libvlc_Stopped ) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "VLC done. status = %d\n", status);
+                               break;
+                       }
+
+                       switch_yield(10000);
+               }
+       }
+
+       vcontext->playing = 0;
+       acontext->playing = 0;
+
+
+       if (vcontext->mp) libvlc_media_player_stop(vcontext->mp);
+       if (vcontext->m) libvlc_media_release(vcontext->m);
+       if (acontext->inst_out) libvlc_release(acontext->inst_out);
+
+       switch_img_free(&vcontext->img);
+
+       if (vcontext->timer.interval) switch_core_timer_destroy(&vcontext->timer);
+
+       if (vcontext->audio_buffer) {
+               switch_buffer_destroy(&vcontext->audio_buffer);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static switch_status_t vlc_file_close(switch_file_handle_t *handle)
 {
        vlc_file_context_t *context = handle->private_info;
+
+       if (context->vlc_handle) libvlc_release(context->vlc_handle);
+
+       if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
+               return vlc_file_av_close(handle);
+       }
        
        context->playing = 0;
 
@@ -613,8 +1068,10 @@ SWITCH_STANDARD_APP(play_video_function)
        vlc_video_context_t *context;
        char *path = (char *)data;
        const char *tmp;
-
        switch_size_t audio_datalen;
+       libvlc_instance_t *vlc_handle;
+
+       vlc_handle = libvlc_new(sizeof(vlc_args)/sizeof(char *), vlc_args);
 
        context = switch_core_session_alloc(session, sizeof(vlc_video_context_t));
        switch_assert(context);
@@ -687,22 +1144,22 @@ SWITCH_STANDARD_APP(play_video_function)
        /* Determine if this is a url or a path */
        /* TODO: Change this so that it tries local files first, and then if it fails try location. */
        if(! strncmp(path, "http", 4)){
-               context->m = libvlc_media_new_location(read_inst, path);
+               context->m = libvlc_media_new_location(vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is http %s\n", path);
        } else if (! strncmp(path, "rtp", 3)){
-               context->m = libvlc_media_new_path(read_inst, path);
+               context->m = libvlc_media_new_path(vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is rtp %s\n", path);
        } else if (! strncmp(path, "mms", 3)){
-               context->m = libvlc_media_new_path(read_inst, path);
+               context->m = libvlc_media_new_path(vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is mms %s\n", path);
        } else if (! strncmp(path, "rtsp", 3)){
-               context->m = libvlc_media_new_path(read_inst, path);
+               context->m = libvlc_media_new_path(vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is rtsp %s\n", path);
        } else if (! strncmp(path, "/", 1)){
-               context->m = libvlc_media_new_path(read_inst, path);
+               context->m = libvlc_media_new_path(vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is file %s\n", path);
        } else {
-               context->m = libvlc_media_new_location(read_inst, path);
+               context->m = libvlc_media_new_location(vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is unknown type %s\n", path);
        }
 
@@ -805,6 +1262,8 @@ end:
        }
 
        switch_core_session_video_reset(session);
+
+       if (vlc_handle) libvlc_release(vlc_handle);
 }
 
 int  vlc_write_video_imem_get_callback(void *data, const char *cookie, int64_t *dts, int64_t *pts, unsigned *flags, size_t *size, void **output)
@@ -847,7 +1306,6 @@ int  vlc_write_video_imem_get_callback(void *data, const char *cookie, int64_t *
                *size = 0;
                switch_img_convert(img, SWITCH_CONVERT_FMT_YUYV, *output, size);
                switch_img_free(&img);
-
                return 0;
        }
 
@@ -962,7 +1420,7 @@ SWITCH_STANDARD_APP(capture_video_function)
     unsigned char audio_data_buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
        void *audio_data;
        switch_size_t audio_datalen;
-       uint32_t offset = 500000;
+       uint32_t offset = 500;
        const char *tmp;
        const char * opts[25] = {
                *vlc_args,
@@ -976,7 +1434,7 @@ SWITCH_STANDARD_APP(capture_video_function)
 
        if ((tmp = switch_channel_get_variable(channel, "vlc_capture_offset"))) {
                int x = atoi(tmp);
-               if (x > 0) offset = x;
+               if (x >= 0) offset = x;
        }
 
        switch_channel_pre_answer(channel);
@@ -1046,7 +1504,7 @@ SWITCH_STANDARD_APP(capture_video_function)
        libvlc_media_add_option_flag( context->m, imem_slave, libvlc_media_option_trusted );                                                                       
 
        if ( context->m == NULL ) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error opening %s for reading\n", data);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error opening %s for writing\n", data);
                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
                return ;
        }
@@ -1064,12 +1522,12 @@ SWITCH_STANDARD_APP(capture_video_function)
 
 
        switch_channel_audio_sync(channel);
-
+       
        if (offset) {
-               uint32_t off_frames = offset / read_impl.microseconds_per_packet;
+               uint32_t off_frames = (offset * 1000) / read_impl.microseconds_per_packet;
                int i = 0;
 
-               context->sync_offset = offset;
+               context->sync_offset = offset * 1000;
                switch_mutex_lock(context->audio_mutex);
                switch_core_timer_sync(&context->timer);
                pts = context->timer.samplecount;
@@ -1104,7 +1562,7 @@ SWITCH_STANDARD_APP(capture_video_function)
                switch_mutex_lock(context->audio_mutex);
                if (!switch_buffer_inuse(context->audio_buffer)) {
                        switch_core_timer_sync(&context->timer);
-                       pts = context->timer.samplecount - offset;
+                       pts = context->timer.samplecount - context->sync_offset;
                        switch_buffer_write(context->audio_buffer, &pts, sizeof(pts));
                }
                switch_buffer_write(context->audio_buffer, audio_data, audio_datalen);
@@ -1143,7 +1601,7 @@ SWITCH_STANDARD_APP(capture_video_function)
 
        switch_core_session_set_video_read_callback(session, NULL, NULL);
        context->ending = 1;
-
+       
        if (switch_mutex_trylock(context->video_mutex) == SWITCH_STATUS_SUCCESS) {
                switch_thread_cond_signal(context->cond);
                switch_mutex_unlock(context->video_mutex);
@@ -1283,7 +1741,7 @@ static switch_status_t setup_tech_pvt(switch_core_session_t *osession, switch_co
        switch_assert(context);
        memset(context, 0, sizeof(vlc_file_context_t));
        tech_pvt->context = context;
-
+       context->vlc_handle = libvlc_new(sizeof(vlc_args)/sizeof(char *), vlc_args);
 
        switch_buffer_create_dynamic(&(context->audio_buffer), VLC_BUFFER_SIZE, VLC_BUFFER_SIZE * 8, 0);
        switch_queue_create(&context->video_queue, SWITCH_CORE_QUEUE_LEN, switch_core_session_get_pool(session));
@@ -1315,22 +1773,22 @@ static switch_status_t setup_tech_pvt(switch_core_session_t *osession, switch_co
        /* Determine if this is a url or a path */
        /* TODO: Change this so that it tries local files first, and then if it fails try location. */
        if(! strncmp(path, "http", 4)){
-               context->m = libvlc_media_new_location(read_inst, path);
+               context->m = libvlc_media_new_location(context->vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is http %s\n", path);
        } else if (! strncmp(path, "rtp", 3)){
-               context->m = libvlc_media_new_path(read_inst, path);
+               context->m = libvlc_media_new_path(context->vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is rtp %s\n", path);
        } else if (! strncmp(path, "mms", 3)){
-               context->m = libvlc_media_new_path(read_inst, path);
+               context->m = libvlc_media_new_path(context->vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is mms %s\n", path);
        } else if (! strncmp(path, "rtsp", 3)){
-               context->m = libvlc_media_new_path(read_inst, path);
+               context->m = libvlc_media_new_path(context->vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is rtsp %s\n", path);
        } else if (! strncmp(path, "/", 1)){
-               context->m = libvlc_media_new_path(read_inst, path);
+               context->m = libvlc_media_new_path(context->vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is file %s\n", path);
        } else {
-               context->m = libvlc_media_new_location(read_inst, path);
+               context->m = libvlc_media_new_location(context->vlc_handle, path);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is unknown type %s\n", path);
        }
 
@@ -1430,6 +1888,8 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session)
 
        switch_img_free(&tech_pvt->read_video_frame.img);
 
+       if (tech_pvt->context->vlc_handle) libvlc_release(tech_pvt->context->vlc_handle);
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -1752,20 +2212,14 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vlc_load)
        file_interface->file_close = vlc_file_close;
        file_interface->file_read = vlc_file_read;
        file_interface->file_write = vlc_file_write;
+       file_interface->file_read_video = vlc_file_read_video;
+       file_interface->file_write_video = vlc_file_write_video;
 
        vlc_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
        vlc_endpoint_interface->interface_name = "vlc";
        vlc_endpoint_interface->io_routines = &vlc_io_routines;
        vlc_endpoint_interface->state_handler = &vlc_state_handlers;
 
-       /* load the vlc engine. */
-       read_inst = libvlc_new(sizeof(vlc_args)/sizeof(char *), vlc_args);
-
-       if ( ! read_inst ) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "FAILED TO LOAD\n");
-                       return SWITCH_STATUS_GENERR;
-       }
-
        SWITCH_ADD_APP(app_interface, "play_video", "play a videofile", "play a video file", play_video_function, "<file>", SAF_NONE);
        SWITCH_ADD_APP(app_interface, "capture_video", "capture a videofile", "capture a video file", capture_video_function, "<file>", SAF_NONE);
 
@@ -1780,8 +2234,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vlc_load)
   Macro expands to: switch_status_t mod_vlc_shutdown() */
 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_vlc_shutdown)
 {
-       if ( read_inst != NULL )
-               libvlc_release(read_inst);
        return SWITCH_STATUS_SUCCESS;
 }
 
index 81fb16ed28860a11e7ad021436a526bc91413a7b..18d72743999db58f9da15da9603de533f2a65188 100644 (file)
@@ -154,6 +154,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file,
        fh->func = func;
        fh->line = line;
 
+       if (switch_test_flag(fh, SWITCH_FILE_FLAG_VIDEO) && !fh->file_interface->file_read_video) {
+               switch_clear_flag(fh, SWITCH_FILE_FLAG_VIDEO);
+       }
 
        if (spool_path) {
                char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
@@ -382,6 +385,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh,
        return status;
 }
 
+SWITCH_DECLARE(switch_bool_t) switch_core_file_has_video(switch_file_handle_t *fh)
+{
+       return switch_test_flag(fh, SWITCH_FILE_FLAG_VIDEO) ? SWITCH_TRUE : SWITCH_FALSE;
+}
 
 SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh, void *data, switch_size_t *len)
 {
@@ -464,7 +471,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh,
        }
 }
 
-SWITCH_DECLARE(switch_status_t) switch_core_file_write_video(switch_file_handle_t *fh, void *data, switch_size_t *len)
+SWITCH_DECLARE(switch_status_t) switch_core_file_write_video(switch_file_handle_t *fh, switch_frame_t *frame)
 {
        switch_assert(fh != NULL);
        switch_assert(fh->file_interface != NULL);
@@ -477,8 +484,24 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write_video(switch_file_handle_
                return SWITCH_STATUS_FALSE;
        }
 
-       return fh->file_interface->file_write_video(fh, data, len);
+       return fh->file_interface->file_write_video(fh, frame);
+
+}
+
+SWITCH_DECLARE(switch_status_t) switch_core_file_read_video(switch_file_handle_t *fh, switch_frame_t *frame)
+{
+       switch_assert(fh != NULL);
+       switch_assert(fh->file_interface != NULL);
+
+       if (!switch_test_flag(fh, SWITCH_FILE_OPEN)) {
+               return SWITCH_STATUS_GENERR;
+       }
+
+       if (!fh->file_interface->file_read_video) {
+               return SWITCH_STATUS_FALSE;
+       }
 
+       return fh->file_interface->file_read_video(fh, frame);
 }
 
 SWITCH_DECLARE(switch_status_t) switch_core_file_seek(switch_file_handle_t *fh, unsigned int *cur_pos, int64_t samples, int whence)
index 5416e59cd6e9d823a196b151a8ff1c4876b26bb4..91a62cb6c46276fa0a5ae111e40cd54cb44d9f94 100644 (file)
@@ -203,6 +203,7 @@ 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;
 };
 
 
@@ -4581,6 +4582,32 @@ 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_media_handle_t *smh;
+       switch_rtp_engine_t *v_engine;
+
+       switch_assert(session);
+
+       if (!switch_channel_test_flag(session->channel, CF_VIDEO)) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       if (!(smh = session->media_handle)) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];      
+
+       if (!v_engine->media_thread) {
+               return SWITCH_STATUS_FALSE;
+       }
+
+       smh->video_fh = fh;
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, void *obj)
 {
        struct media_helper *mh = obj;
@@ -4590,6 +4617,8 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
        switch_frame_t *read_frame;
        switch_media_handle_t *smh;
        uint32_t loops = 0, xloops = 0;
+       switch_frame_t fr = { 0 };
+       unsigned char *buf = NULL;
 
        if (!(smh = session->media_handle)) {
                return NULL;
@@ -4676,7 +4705,21 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
                        smh->vid_params.height = read_frame->img->d_h;
                }
 
-               if (switch_channel_test_flag(channel, CF_VIDEO_ECHO)) {
+               if (smh->video_fh) {
+                       if (!buf) {
+                               int buflen = SWITCH_RECOMMENDED_BUFFER_SIZE * 2;
+                               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) {
+                               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)) {
                        switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
                }
 
@@ -10074,6 +10117,30 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core
                goto done;
        }
 
+       if (switch_channel_test_flag(session->channel, CF_VIDEO_DECODED_READ) && (*frame)->img == NULL) {
+               switch_status_t decode_status;
+
+               (*frame)->img = NULL;
+
+               decode_status = switch_core_codec_decode_video((*frame)->codec, *frame);
+               
+               if ((*frame)->img && switch_channel_test_flag(session->channel, CF_VIDEO_DEBUG_READ)) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "IMAGE %dx%d %dx%d\n", 
+                                                         (*frame)->img->w, (*frame)->img->h, (*frame)->img->d_w, (*frame)->img->d_h);
+               }
+
+               if (switch_test_flag((*frame), SFF_WAIT_KEY_FRAME)) {
+                       switch_core_session_request_video_refresh(session);
+                       switch_clear_flag((*frame), SFF_WAIT_KEY_FRAME);
+               }
+
+               if (decode_status == SWITCH_STATUS_MORE_DATA || !(*frame)->img) {
+                       goto top;
+               }
+       }
+
+  done:
+
        if (session->bugs) {
                switch_media_bug_t *bp;
                switch_bool_t ok = SWITCH_TRUE;
@@ -10117,29 +10184,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core
                }
        }
 
-       if (switch_channel_test_flag(session->channel, CF_VIDEO_DECODED_READ) && (*frame)->img == NULL) {
-               switch_status_t decode_status;
-
-               (*frame)->img = NULL;
-
-               decode_status = switch_core_codec_decode_video((*frame)->codec, *frame);
-               
-               if ((*frame)->img && switch_channel_test_flag(session->channel, CF_VIDEO_DEBUG_READ)) {
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "IMAGE %dx%d %dx%d\n", 
-                                                         (*frame)->img->w, (*frame)->img->h, (*frame)->img->d_w, (*frame)->img->d_h);
-               }
-
-               if (switch_test_flag((*frame), SFF_WAIT_KEY_FRAME)) {
-                       switch_core_session_request_video_refresh(session);
-                       switch_clear_flag((*frame), SFF_WAIT_KEY_FRAME);
-               }
-
-               if (decode_status == SWITCH_STATUS_MORE_DATA || !(*frame)->img) {
-                       goto top;
-               }
-       }
 
-  done:
 
        if (status == SWITCH_STATUS_SUCCESS) {
                switch_core_session_video_read_callback(session, *frame);
index 57cc40552381fc71d8c67e35b3a6f9c540b01e7d..cb38710d314850aa7eb3d4726cf21631924fbce6 100644 (file)
@@ -1471,13 +1471,9 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s
        case SWITCH_ABC_TYPE_READ_VIDEO_PING:
 
                if (rh->fh) {
-                       switch_size_t len;
-
                        if (!bug->ping_frame) break;
 
-                       len = bug->ping_frame->packetlen;
-
-                       if (len && switch_core_file_write_video(rh->fh, bug->ping_frame->packet, &len) != SWITCH_STATUS_SUCCESS && rh->hangup_on_error) {
+                       if (len && switch_core_file_write_video(rh->fh, bug->ping_frame) != SWITCH_STATUS_SUCCESS && rh->hangup_on_error) {
                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing video to %s\n", rh->file);
                                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
                                switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
index eda1d6ef01a75ed7609f54b66947572cd99a1878..4d8b93e2b1f3c99555c9c83f718a8a3705185d29 100644 (file)
@@ -1043,6 +1043,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
        switch_event_t *event;
        uint32_t test_native = 0, last_native = 0;
        uint32_t buflen = 0;
+       int flags;
 
        if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
                return SWITCH_STATUS_FALSE;
@@ -1237,10 +1238,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                        fh->prefix = prefix;
                }
 
+               flags = SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT;
+
+               if (switch_channel_test_flag(channel, CF_VIDEO)) {
+                       flags |= SWITCH_FILE_FLAG_VIDEO;
+               }
+
                if (switch_core_file_open(fh,
                                                                  file,
                                                                  read_impl.number_of_channels,
-                                                                 read_impl.actual_samples_per_second, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
+                                                                 read_impl.actual_samples_per_second, flags, NULL) != SWITCH_STATUS_SUCCESS) {
                        switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE);
                        status = SWITCH_STATUS_NOTFOUND;
                        continue;
@@ -1251,6 +1258,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                switch_channel_set_private(channel, "__fh", fh);
                switch_core_session_io_rwunlock(session);
 
+               if (switch_core_file_has_video(fh)) {
+                       switch_core_media_set_video_file(session, fh);
+               }
 
                if (!abuf) {
                        buflen = write_frame.buflen = FILE_STARTSAMPLES * sizeof(*abuf) * fh->channels;
@@ -1324,6 +1334,9 @@ 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_file_close(fh);
 
                                switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE);
@@ -1345,6 +1358,9 @@ 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_file_close(fh);
 
                                switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE);
@@ -1370,6 +1386,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
                                switch_core_session_io_write_lock(session);
                                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_file_close(fh);
                                switch_core_session_reset(session, SWITCH_TRUE, SWITCH_FALSE);
                                status = SWITCH_STATUS_GENERR;
@@ -1777,6 +1796,9 @@ 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_file_close(fh);
 
                if (fh->audio_buffer) {