diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index d4adedf942..f7554422c3 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -324,6 +324,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_END_EXTERN_C #endif diff --git a/src/include/switch_core_video.h b/src/include/switch_core_video.h index 4b92ae8b45..b9b20b8b3e 100644 --- a/src/include/switch_core_video.h +++ b/src/include/switch_core_video.h @@ -78,6 +78,9 @@ typedef struct switch_image_rect { unsigned int h; /**< height */ } switch_image_rect_t; +typedef enum { + SWITCH_CONVERT_FMT_YUYV = 0 +} switch_convert_fmt_t; /*!\brief Open a descriptor, allocating storage for the underlying image * @@ -222,6 +225,7 @@ SWITCH_DECLARE(switch_status_t) switch_img_scale(switch_image_t *src, switch_ima SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, int height); SWITCH_DECLARE(switch_img_position_t) parse_img_position(const char *name); SWITCH_DECLARE(void) switch_img_find_position(switch_img_position_t pos, int sw, int sh, int iw, int ih, int *xP, int *yP); +SWITCH_DECLARE(switch_status_t) switch_img_convert(switch_image_t *src, switch_convert_fmt_t fmt, void *dest, switch_size_t *size); /** @} */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 83ae8b168b..b9415fd93e 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1465,11 +1465,18 @@ typedef enum { CF_VIDEO_DEBUG_READ, CF_VIDEO_DEBUG_WRITE, CF_VIDEO_ONLY, + CF_VIDEO_READY, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ CF_FLAG_MAX } switch_channel_flag_t; +typedef struct switch_vid_params_s { + int width; + int height; +} switch_vid_params_t; + + typedef enum { CF_APP_TAGGED = (1 << 0), diff --git a/src/mod/formats/mod_vlc/mod_vlc.c b/src/mod/formats/mod_vlc/mod_vlc.c index c6e619aa09..1f02024c54 100644 --- a/src/mod/formats/mod_vlc/mod_vlc.c +++ b/src/mod/formats/mod_vlc/mod_vlc.c @@ -84,6 +84,8 @@ struct vlc_file_context { int err; int pts; libvlc_instance_t *inst_out; + void *frame_buffer; + switch_size_t frame_buffer_len; }; typedef struct vlc_file_context vlc_file_context_t; @@ -115,6 +117,15 @@ struct vlc_video_context { int force_width; int force_height; int channels; + int samplerate; + int samples; + //int pts; + void *video_frame_buffer; + switch_size_t video_frame_buffer_len; + void *audio_frame_buffer; + switch_size_t audio_frame_buffer_len; + switch_timer_t timer; + int64_t pts; }; typedef struct vlc_video_context vlc_video_context_t; @@ -327,45 +338,166 @@ void video_format_clean_callback(void *opaque) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "cleanup\n"); } +#if 0 +static int i420_size(int width, int height) +{ + int half_width = (width + 1) >> 1; + int half_height = (height + 1) >> 1; + + return width * height + half_width * half_height * 2; +} +#endif + +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) +{ + switch_frame_t *read_frame; + switch_status_t status = SWITCH_STATUS_FALSE; + vlc_video_context_t *context = (vlc_video_context_t *) data; + int bytes = 0, bread = 0, blen = 0; + int r = 0; + + switch_mutex_lock(context->audio_mutex); + + if (!switch_channel_ready(context->channel)) { + if (!switch_buffer_inuse(context->audio_buffer)) { + r = -1; + goto nada; + } + } + + if (*cookie == 'v') { + if (!switch_channel_ready(context->channel)) { + goto nada; + } + + status = switch_core_session_read_video_frame(context->session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + r = -1; + goto nada; + } + + if (switch_test_flag(read_frame, SFF_CNG) || !read_frame->img) { + goto nada; + } + + switch_core_timer_sync(&context->timer); + *dts = *pts = context->timer.samplecount; + + if (read_frame->img) { + *size = read_frame->img->d_w * read_frame->img->d_h * 2; + + if (context->video_frame_buffer_len < *size) { + context->video_frame_buffer_len = *size; + context->video_frame_buffer = switch_core_alloc(context->pool, context->video_frame_buffer_len); + } + + *output = context->video_frame_buffer; + *size = 0; + switch_img_convert(read_frame->img, SWITCH_CONVERT_FMT_YUYV, *output, size); + + switch_core_session_write_video_frame(context->session, read_frame, SWITCH_IO_FLAG_NONE, 0); + } else { + *output = read_frame->data; + *size = read_frame->datalen; + } + + goto ok; + } + + + if ((blen = switch_buffer_inuse(context->audio_buffer))) { + switch_buffer_read(context->audio_buffer, &context->pts, sizeof(context->pts)); + blen = switch_buffer_inuse(context->audio_buffer); + *pts = *dts = context->pts; + } + + if (!(bytes = blen)) { + goto nada; + } + + if (context->audio_frame_buffer_len < bytes) { + context->audio_frame_buffer_len = bytes; + context->audio_frame_buffer = switch_core_alloc(context->pool, context->audio_frame_buffer_len); + } + + *output = context->audio_frame_buffer; + + bread = switch_buffer_read(context->audio_buffer, *output, bytes); + + *size = (size_t) bread; + + //printf("A SIZE %ld ts %ld %p\n", *size, *pts, (void *)pthread_self()); + + ok: + + switch_mutex_unlock(context->audio_mutex); + return 0; + + nada: + + switch_mutex_unlock(context->audio_mutex); + + if (!switch_channel_ready(context->channel)) { + r = -1; + } + + //printf("nada %s\n", cookie); + + switch_core_timer_sync(&context->timer); + *dts = *pts = context->timer.samplecount; + + *size = 0; + *output = NULL; + + return r; +} + +void vlc_write_video_imem_release_callback(void *data, const char *cookie, size_t size, void *unknown) +{ + +} + 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; - int bytes = 0; + //int samples = 0; + int bytes = 0, bread = 0, blen = 0; + if (context->playing == 0) return -1; + switch_mutex_lock(context->audio_mutex); + + blen = switch_buffer_inuse(context->audio_buffer); - /* If the stream should no longer be sending audio */ - /* then pretend we have less than one sample of audio */ - /* so that libvlc will close the client connections */ - if ( context->playing == 0 && switch_buffer_inuse(context->audio_buffer) == 0 ) { - switch_mutex_unlock(context->audio_mutex); - return 1; + if (!(bytes = blen)) { + *size = 0; + *output = NULL; + switch_mutex_unlock(context->audio_mutex); + return 0; } - - samples = context->samples; - context->samples = 0; - - if ( samples ) { - bytes = samples * 2 * context->channels; - *output = malloc(bytes); - bytes = switch_buffer_read(context->audio_buffer, *output, bytes); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC imem samples: %d\n", samples); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC imem bytes: %d\n", bytes); - } else { - bytes = 128; - *output = malloc(bytes); - memset(*output, 0, bytes); + + + if (context->frame_buffer_len < bytes) { + context->frame_buffer_len = bytes; + context->frame_buffer = switch_core_alloc(context->pool, context->frame_buffer_len); } + + *output = context->frame_buffer; + + bread = switch_buffer_read(context->audio_buffer, *output, bytes); + switch_mutex_unlock(context->audio_mutex); - *size = (size_t) bytes; + *size = (size_t) bread; + return 0; } void vlc_imem_release_callback(void *data, const char *cookie, size_t size, void *unknown) { - free(unknown); + //printf("Free?? %p\n", unknown); + //free(unknown); } static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *path) @@ -435,26 +567,29 @@ 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)) { - const char * opts[10] = { + const char * opts[25] = { *vlc_args, - switch_mprintf("--sout=%s", path) + switch_core_sprintf(context->pool, "--sout=%s", path) }; - int opts_count = 10; - + int opts_count = 2; + if ( !handle->samplerate) handle->samplerate = 16000; context->samplerate = handle->samplerate; context->channels = handle->channels; - opts[2] = switch_mprintf("--imem-get=%ld", vlc_imem_get_callback); - opts[3] = switch_mprintf("--imem-release=%ld", vlc_imem_release_callback); - opts[4] = switch_mprintf("--imem-cat=%d", 4); - opts[5] = "--demux=rawaud"; - opts[6] = "--rawaud-fourcc=s16l"; - opts[7] = switch_mprintf("--rawaud-samplerate=%d", context->samplerate); - opts[8] = switch_mprintf("--imem-data=%ld", context); - //opts[9] = "--rawaud-channels=1"; + opts[opts_count++] = switch_core_sprintf(context->pool, "--imem-get=%ld", vlc_imem_get_callback); + opts[opts_count++] = switch_core_sprintf(context->pool, "--imem-release=%ld", vlc_imem_release_callback); + opts[opts_count++] = switch_core_sprintf(context->pool, "--imem-cat=%d", 4); + opts[opts_count++] = "--demux=rawaud"; + opts[opts_count++] = "--rawaud-fourcc=s16l"; + opts[opts_count++] = "--imem-codec=s16l"; + opts[opts_count++] = switch_core_sprintf(context->pool, "--imem-samplerate=%d", context->samplerate); + opts[opts_count++] = switch_core_sprintf(context->pool, "--imem-channels=%d", context->channels); + opts[opts_count++] = switch_core_sprintf(context->pool, "--rawaud-channels=%d", context->channels); + opts[opts_count++] = switch_core_sprintf(context->pool, "--imem-data=%ld", context); + /* Prepare to write to an output stream. */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for writing\n", path); @@ -467,8 +602,6 @@ 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; - context->playing = 1; - libvlc_media_player_play(context->mp); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC tried to open %s for unknown reason\n", path); return SWITCH_STATUS_GENERR; @@ -543,46 +676,28 @@ static switch_status_t vlc_file_write(switch_file_handle_t *handle, void *data, context->samples += *len; switch_buffer_write(context->audio_buffer, data, bytes); switch_mutex_unlock(context->audio_mutex); - + + if (!context->playing) { + context->playing = 1; + libvlc_media_player_play(context->mp); + } + return SWITCH_STATUS_SUCCESS; } static switch_status_t vlc_file_close(switch_file_handle_t *handle) { vlc_file_context_t *context = handle->private_info; - int sanity = 0; context->playing = 0; + + libvlc_media_player_stop(context->mp); + + switch_buffer_zero(context->audio_buffer); + + if (context->m) libvlc_media_release(context->m); - /* The clients need to empty the last of the audio buffer */ - while ( switch_buffer_inuse(context->audio_buffer) > 0 ) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC waiting to close the files: %d \n", (int) switch_buffer_inuse(context->audio_buffer)); - switch_yield(500000); - if (++sanity > 10) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Giving up waiting for client to empty the audio buffer\n"); - break; - } - } - - /* Let the clients get the last of the audio stream */ - sanity = 0; - while ( 3 == libvlc_media_get_state(context->m) ) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC waiting for clients: %d \n", libvlc_media_get_state(context->m)); - switch_yield(500000); - if (++sanity > 10) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Giving up waiting for client to get the last of the audio stream\n"); - break; - } - } - - if( context->mp ) - libvlc_media_player_stop(context->mp); - - if( context->m ) - libvlc_media_release(context->m); - - if ( context->inst_out != NULL ) - libvlc_release(context->inst_out); + if (context->inst_out) libvlc_release(context->inst_out); return SWITCH_STATUS_SUCCESS; } @@ -599,7 +714,6 @@ SWITCH_STANDARD_APP(play_video_function) switch_dtmf_t dtmf = { 0 }; switch_frame_t *read_frame; switch_codec_implementation_t read_impl = { 0 }; - switch_core_session_message_t msg = { 0 }; vlc_video_context_t *context; char *path = (char *)data; const char *tmp; @@ -622,7 +736,6 @@ SWITCH_STANDARD_APP(play_video_function) switch_channel_pre_answer(channel); switch_core_session_get_read_impl(session, &read_impl); - switch_core_session_receive_message(session, &msg); if ((read_vid_codec = switch_core_session_get_video_read_codec(session))) { pt = read_vid_codec->agreed_pt; @@ -717,8 +830,6 @@ SWITCH_STANDARD_APP(play_video_function) switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); }; - // switch_core_service_session_av(session, SWITCH_FALSE, SWITCH_TRUE); - while (switch_channel_ready(channel)) { switch_core_timer_next(&timer); @@ -779,7 +890,6 @@ SWITCH_STANDARD_APP(play_video_function) context->playing = 0; - switch_core_thread_session_end(session); switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "OK"); end: @@ -801,6 +911,213 @@ end: switch_core_session_video_reset(session); } + +SWITCH_STANDARD_APP(capture_video_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_memory_pool_t *pool = switch_core_session_get_pool(session); + switch_codec_t *write_vid_codec; + switch_payload_t pt = 0; + switch_dtmf_t dtmf = { 0 }; + switch_codec_implementation_t read_impl = { 0 }; + vlc_video_context_t *context; + char *path = (char *)data; + libvlc_instance_t *inst_out; + switch_status_t status; + switch_frame_t *read_frame; + switch_vid_params_t vid_params = { 0 }; + int64_t pts = 0; + char *imem_main, *imem_slave; + libvlc_state_t vlc_status; + unsigned char audio_data_buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; + void *audio_data; + switch_size_t audio_datalen; + + const char *tmp; + const char * opts[25] = { + *vlc_args, + switch_core_session_sprintf(session, "--sout=%s", path + 6) + }; + int argc = 2; + + context = switch_core_session_alloc(session, sizeof(vlc_video_context_t)); + switch_assert(context); + memset(context, 0, sizeof(vlc_file_context_t)); + + if ((tmp = switch_channel_get_variable(channel, "vlc_force_width"))) { + context->force_width = atoi(tmp); + } + + if ((tmp = switch_channel_get_variable(channel, "vlc_force_height"))) { + context->force_height = atoi(tmp); + } + + switch_channel_pre_answer(channel); + switch_core_session_get_read_impl(session, &read_impl); + + if ((write_vid_codec = switch_core_session_get_video_read_codec(session))) { + pt = write_vid_codec->agreed_pt; + } + + context->pt = pt; + context->channels = read_impl.number_of_channels; + + context->session = session; + context->channel = channel; + context->pool = pool; + context->playing = 0; + context->samplerate = read_impl.actual_samples_per_second; + vid_params.width = 640; + vid_params.height = 480; + + 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_mutex_init(&context->video_mutex, SWITCH_MUTEX_NESTED, context->pool); + + switch_core_timer_init(&context->timer, "soft", 1, 1000, context->pool); + + switch_channel_set_flag(channel, CF_VIDEO_DECODED_READ); + switch_channel_wait_for_flag(channel, CF_VIDEO_READY, SWITCH_TRUE, 10000, NULL); + switch_core_media_get_vid_params(session, &vid_params); + switch_channel_set_flag(channel, CF_VIDEO_PASSIVE); + switch_core_session_raw_read(session); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for writing\n", path); + + opts[argc++] = switch_core_session_sprintf(session, "--imem-get=%ld", vlc_write_video_imem_get_callback); + opts[argc++] = switch_core_session_sprintf(session, "--imem-release=%ld", vlc_write_video_imem_release_callback); + opts[argc++] = switch_core_session_sprintf(session, "--imem-data=%ld", context); + + inst_out = libvlc_new(argc, opts); + + imem_main = switch_core_session_sprintf(session, + "imem://cookie=video:" + "fps=30.0/1:" + "width=%d:" + "height=%d:" + "codec=YUYV:" + "cat=2:" + "id=2:" + "caching=0", + vid_params.width, vid_params.height); + + imem_slave = switch_core_session_sprintf(session, + ":input-slave=imem://cookie=audio:" + "cat=1:" + "codec=s16l:" + "samplerate=%d:" + "channels=%d:" + "id=1:" + "caching=0", + context->samplerate, context->channels); + + context->m = libvlc_media_new_location(inst_out, imem_main); + + 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_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return ; + } + + context->mp = libvlc_media_player_new_from_media(context->m); + + context->samples = 0; + context->pts = 0; + context->playing = 1; + + if (libvlc_media_player_play(context->mp) == -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error playing %s\n", path); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + }; + + while (switch_channel_ready(channel)) { + + status = switch_core_session_read_frame(context->session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + + if (switch_test_flag(read_frame, SFF_CNG)) { + audio_data = audio_data_buf; + audio_datalen = read_impl.decoded_bytes_per_packet; + } else { + audio_data = read_frame->data; + audio_datalen = read_frame->datalen; + } + + switch_mutex_lock(context->audio_mutex); + if (!switch_buffer_inuse(context->audio_buffer)) { + switch_core_timer_sync(&context->timer); + pts = context->timer.samplecount; + switch_buffer_write(context->audio_buffer, &pts, sizeof(pts)); + } + switch_buffer_write(context->audio_buffer, audio_data, audio_datalen); + switch_mutex_unlock(context->audio_mutex); + + + if (switch_channel_test_flag(channel, CF_BREAK)) { + switch_channel_clear_flag(channel, CF_BREAK); + break; + } + + switch_ivr_parse_all_events(session); + + if (switch_channel_has_dtmf(channel)) { + const char * terminators = switch_channel_get_variable(channel, SWITCH_PLAYBACK_TERMINATORS_VARIABLE); + switch_channel_dequeue_dtmf(channel, &dtmf); + + if (terminators && !strcasecmp(terminators, "none")) { + terminators = NULL; + } + + if (terminators && strchr(terminators, dtmf.digit)) { + char sbuf[2] = {dtmf.digit, '\0'}; + switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, sbuf); + break; + } + } + + vlc_status = libvlc_media_get_state(context->m); + + if (vlc_status == libvlc_Ended || vlc_status == libvlc_Error || vlc_status == libvlc_Stopped ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "VLC done. status = %d\n", vlc_status); + break; + } + } + + while(switch_buffer_inuse(context->audio_buffer)) { + libvlc_state_t status = libvlc_media_get_state(context->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); + } + + if (context->mp) libvlc_media_player_stop(context->mp); + if (context->m) libvlc_media_release(context->m); + if (inst_out) libvlc_release(inst_out); + + context->playing = 0; + + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "OK"); + + switch_img_free(&context->img); + + switch_core_timer_destroy(&context->timer); + + if (context->audio_buffer) { + switch_buffer_destroy(&context->audio_buffer); + } + + switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); + switch_core_session_video_reset(session); +} + static switch_status_t channel_on_init(switch_core_session_t *session); static switch_status_t channel_on_consume_media(switch_core_session_t *session); static switch_status_t channel_on_destroy(switch_core_session_t *session); @@ -1384,7 +1701,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vlc_load) return SWITCH_STATUS_GENERR; } - SWITCH_ADD_APP(app_interface, "play_video", "play an videofile", "play an video file", play_video_function, "", SAF_SUPPORT_NOMEDIA); + SWITCH_ADD_APP(app_interface, "play_video", "play a videofile", "play a video file", play_video_function, "", SAF_NONE); + SWITCH_ADD_APP(app_interface, "capture_video", "capture a videofile", "capture a video file", capture_video_function, "", SAF_NONE); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Initialized VLC instance\n"); diff --git a/src/switch_core.c b/src/switch_core.c index 1c68d0d551..b7aaf6078b 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -2374,6 +2374,7 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, void * if (!strcasecmp(tech, "flush")) { flush++; + tech = NULL; if (prof) { tech = prof; diff --git a/src/switch_core_media.c b/src/switch_core_media.c index b52cd04783..5416e59cd6 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -202,6 +202,7 @@ struct switch_media_handle_s { switch_video_function_t video_function; void *video_user_data; int8_t video_function_running; + switch_vid_params_t vid_params; }; @@ -490,7 +491,20 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_check_autoadj(switch_core_sess return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } +SWITCH_DECLARE(switch_status_t) switch_core_media_get_vid_params(switch_core_session_t *session, switch_vid_params_t *vid_params) +{ + switch_media_handle_t *smh; + switch_assert(session); + + if (!(smh = session->media_handle)) { + return SWITCH_STATUS_FALSE; + } + + *vid_params = smh->vid_params; + + return SWITCH_STATUS_SUCCESS; +} SWITCH_DECLARE(switch_t38_options_t *) switch_core_media_extract_t38_options(switch_core_session_t *session, const char *r_sdp) { @@ -4654,6 +4668,14 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi continue; } + + + if (read_frame->img) { + switch_channel_set_flag(channel, CF_VIDEO_READY); + smh->vid_params.width = read_frame->img->d_w; + smh->vid_params.height = read_frame->img->d_h; + } + if (switch_channel_test_flag(channel, CF_VIDEO_ECHO)) { switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0); } diff --git a/src/switch_core_video.c b/src/switch_core_video.c index 68953d45d1..97cc4450f9 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -1269,6 +1269,30 @@ SWITCH_DECLARE(switch_status_t) switch_img_fit(switch_image_t **srcP, int width, return SWITCH_STATUS_FALSE; } +SWITCH_DECLARE(switch_status_t) switch_img_convert(switch_image_t *src, switch_convert_fmt_t fmt, void *dest, switch_size_t *size) +{ + switch (fmt) { + case SWITCH_CONVERT_FMT_YUYV: + { + switch_size_t size_in = *size; + ConvertFromI420(src->planes[0], src->stride[0], + src->planes[1], src->stride[1], + src->planes[2], src->stride[2], + dest, size_in, + src->d_w, src->d_h, + FOURCC_YUY2); + *size = src->d_w * src->d_h * 2; + + return SWITCH_STATUS_SUCCESS; + } + default: + abort(); + break; + } + + +} + SWITCH_DECLARE(switch_status_t) switch_img_scale(switch_image_t *src, switch_image_t **destP, int width, int height) { switch_image_t *dest = NULL;