Merge pull request #723 in FS/freeswitch from bugfix/FS-8864-improve-video-file-playback to master

* commit '6334e1ce394886fee85e5a0352d7a51e434f472e':
  FS-8864 #resolve [Improve video file playback]
This commit is contained in:
Anthony Minessale II 2016-02-26 15:26:45 -06:00
commit 16a531d211
5 changed files with 254 additions and 54 deletions

View File

@ -168,6 +168,8 @@ typedef struct switch_core_media_params_s {
uint32_t video_key_freq; uint32_t video_key_freq;
uint32_t video_key_first; uint32_t video_key_first;
switch_thread_t *video_write_thread;
} switch_core_media_params_t; } switch_core_media_params_t;
static inline const char *switch_media_type2str(switch_media_type_t type) static inline const char *switch_media_type2str(switch_media_type_t type)

View File

@ -1104,6 +1104,7 @@ struct av_file_context {
int audio_start; int audio_start;
int vid_ready; int vid_ready;
int audio_ready; int audio_ready;
int closed;
MediaStream video_st; MediaStream video_st;
MediaStream audio_st; MediaStream audio_st;
@ -1120,6 +1121,7 @@ struct av_file_context {
switch_time_t video_start_time; switch_time_t video_start_time;
switch_image_t *last_img; switch_image_t *last_img;
int read_fps; int read_fps;
switch_time_t last_vid_push;
}; };
typedef struct av_file_context av_file_context_t; typedef struct av_file_context av_file_context_t;
@ -1250,6 +1252,9 @@ err:
return status; return status;
} }
//#define ALT_WAY
#define AUDIO_BUF_SEC 5
static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, void *obj) static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, void *obj)
{ {
av_file_context_t *context = (av_file_context_t *) obj; av_file_context_t *context = (av_file_context_t *) obj;
@ -1257,36 +1262,51 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
int got_data = 0; int got_data = 0;
int error; int error;
int sync = 0; int sync = 0;
int eof = 0;
context->file_read_thread_running = 1; context->file_read_thread_running = 1;
#define AUDIO_BUF_SEC 5 while (context->file_read_thread_running && !context->closed) {
int vid_frames = 0;
while (context->file_read_thread_running) { if (context->has_video) {
if (switch_buffer_inuse(context->audio_buffer) > AUDIO_BUF_SEC * context->audio_st.sample_rate * context->audio_st.channels * 2) { vid_frames = switch_queue_size(context->eh.video_queue);
switch_yield(10000); }
if (switch_buffer_inuse(context->audio_buffer) > AUDIO_BUF_SEC * context->audio_st.sample_rate * context->audio_st.channels * 2 &&
(!context->has_video || vid_frames > 5)) {
switch_yield(context->has_video ? 1000 : 10000);
continue; continue;
} }
av_init_packet(&pkt); av_init_packet(&pkt);
pkt.data = NULL; pkt.data = NULL;
pkt.size = 0; pkt.size = 0;
if ((error = av_read_frame(context->fc, &pkt)) < 0) { if ((error = av_read_frame(context->fc, &pkt)) < 0) {
if (error == AVERROR_EOF) break; if (error == AVERROR_EOF) {
eof = 1;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not read frame (error '%s')\n", get_error_text(error)); /* just make sure*/
break; pkt.data = NULL;
pkt.size = 0;
pkt.stream_index = context->video_st.st->index;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not read frame (error '%s')\n", get_error_text(error));
break;
}
} }
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "stream: %d, pkt size %d\n", pkt.stream_index, pkt.size); // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "stream: %d, pkt size %d\n", pkt.stream_index, pkt.size);
if (context->has_video && pkt.stream_index == context->video_st.st->index) { if (context->has_video && pkt.stream_index == context->video_st.st->index) {
AVFrame *vframe = av_frame_alloc(); AVFrame *vframe;
switch_image_t *img; switch_image_t *img;
if (!sync) { if (!sync) {
switch_buffer_zero(context->audio_buffer); switch_buffer_zero(context->audio_buffer);
sync = 1; sync = 1;
} }
again:
vframe = av_frame_alloc();
switch_assert(vframe); switch_assert(vframe);
if ((error = avcodec_decode_video2(context->video_st.st->codec, vframe, &got_data, &pkt)) < 0) { if ((error = avcodec_decode_video2(context->video_st.st->codec, vframe, &got_data, &pkt)) < 0) {
@ -1305,7 +1325,7 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
// continue; // continue;
//} //}
if (got_data && error > 0) { if (got_data && error >= 0) {
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got picture %dx%d fmt: %d pktpts:%lld pktdts:%lld\n", vframe->width, vframe->height, vframe->format, vframe->pkt_pts, vframe->pkt_dts); // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got picture %dx%d fmt: %d pktpts:%lld pktdts:%lld\n", vframe->width, vframe->height, vframe->format, vframe->pkt_pts, vframe->pkt_dts);
if (vframe->format != AV_PIX_FMT_YUV420P) { if (vframe->format != AV_PIX_FMT_YUV420P) {
@ -1355,14 +1375,38 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
uint64_t *pts = malloc(sizeof(uint64_t)); uint64_t *pts = malloc(sizeof(uint64_t));
if (pts) { if (pts) {
#ifdef ALT_WAY
int diff;
int sleep = 66000;
#endif
*pts = vframe->pkt_pts; *pts = vframe->pkt_pts;
avframe2img(vframe, img); avframe2img(vframe, img);
img->user_priv = pts; img->user_priv = pts;
#ifdef ALT_WAY
diff = sleep - (switch_time_now() - context->last_vid_push);
if (diff > 0 && diff <= sleep) {
switch_core_timer_next(&context->video_timer);
} else {
switch_core_timer_sync(&context->video_timer);
}
#endif
switch_queue_push(context->eh.video_queue, img); switch_queue_push(context->eh.video_queue, img);
context->last_vid_push = switch_time_now();
} }
} }
} }
av_frame_free(&vframe); av_frame_free(&vframe);
if (eof) {
if (got_data) {
goto again; // to get all delayed video frames in decoder
} else {
break;
}
}
continue; continue;
} else if (context->has_audio && pkt.stream_index == context->audio_st.st->index) { } else if (context->has_audio && pkt.stream_index == context->audio_st.st->index) {
AVFrame in_frame = { { 0 } }; AVFrame in_frame = { { 0 } };
@ -1457,6 +1501,8 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
handle->private_info = context; handle->private_info = context;
context->pool = handle->memory_pool; context->pool = handle->memory_pool;
switch_core_timer_init(&context->video_timer, "soft", 66, 1, context->pool);
context->offset = DFT_RECORD_OFFSET; context->offset = DFT_RECORD_OFFSET;
if (handle->params && (tmp = switch_event_get_header(handle->params, "av_video_offset"))) { if (handle->params && (tmp = switch_event_get_header(handle->params, "av_video_offset"))) {
context->offset = atoi(tmp); context->offset = atoi(tmp);
@ -1634,6 +1680,10 @@ static switch_status_t av_file_write(switch_file_handle_t *handle, void *data, s
uint32_t bytes; uint32_t bytes;
int inuse; int inuse;
if (!switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
return SWITCH_STATUS_FALSE;
}
if (!context->vid_ready) { if (!context->vid_ready) {
return status; return status;
} }
@ -1726,6 +1776,8 @@ static switch_status_t av_file_close(switch_file_handle_t *handle)
av_file_context_t *context = (av_file_context_t *)handle->private_info; av_file_context_t *context = (av_file_context_t *)handle->private_info;
switch_status_t status; switch_status_t status;
context->closed = 1;
if (context->eh.video_queue) { if (context->eh.video_queue) {
switch_queue_push(context->eh.video_queue, NULL); switch_queue_push(context->eh.video_queue, NULL);
} }
@ -1784,6 +1836,10 @@ static switch_status_t av_file_read(switch_file_handle_t *handle, void *data, si
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
while (context->has_video && !context->vid_ready && !context->closed) {
switch_yield(1000);
}
switch_mutex_lock(context->mutex); switch_mutex_lock(context->mutex);
size = switch_buffer_inuse(context->audio_buffer); size = switch_buffer_inuse(context->audio_buffer);
if (size > *len * context->audio_st.channels * 2) size = *len * context->audio_st.channels * 2; if (size > *len * context->audio_st.channels * 2) size = *len * context->audio_st.channels * 2;
@ -1808,6 +1864,46 @@ static switch_status_t av_file_read(switch_file_handle_t *handle, void *data, si
return *len == 0 ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS; return *len == 0 ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS;
} }
#ifdef ALT_WAY
static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_frame_t *frame, switch_video_read_flag_t flags)
{
void *pop;
av_file_context_t *context = (av_file_context_t *)handle->private_info;
switch_status_t status;
if (!context->has_video || context->closed) return SWITCH_STATUS_FALSE;
if ((flags & SVR_CHECK)) {
return SWITCH_STATUS_BREAK;
}
if ((flags & SVR_FLUSH)) {
flush_video_queue(context->eh.video_queue, 1);
}
if ((flags & SVR_BLOCK)) {
status = switch_queue_pop(context->eh.video_queue, &pop);
} else {
status = switch_queue_trypop(context->eh.video_queue, &pop);
}
if (status == SWITCH_STATUS_SUCCESS) {
if (!pop) {
return SWITCH_STATUS_FALSE;
}
context->vid_ready = 1;
frame->img = (switch_image_t *) pop;
return SWITCH_STATUS_SUCCESS;
}
return (flags & SVR_FLUSH) ? SWITCH_STATUS_BREAK : status;
}
#else
static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_frame_t *frame, switch_video_read_flag_t flags) static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_frame_t *frame, switch_video_read_flag_t flags)
{ {
av_file_context_t *context = (av_file_context_t *)handle->private_info; av_file_context_t *context = (av_file_context_t *)handle->private_info;
@ -1815,7 +1911,7 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
MediaStream *mst = &context->video_st; MediaStream *mst = &context->video_st;
AVStream *st = mst->st; AVStream *st = mst->st;
int ticks = 0; int ticks = 0;
int max_delta = 1 * AV_TIME_BASE; // 1 second int64_t max_delta = 1 * AV_TIME_BASE; // 1 second
switch_status_t status = SWITCH_STATUS_SUCCESS; switch_status_t status = SWITCH_STATUS_SUCCESS;
double fl_to = 0.02; double fl_to = 0.02;
int do_fl = 0; int do_fl = 0;
@ -1829,7 +1925,7 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
fl_to = (1000 / context->read_fps) * 1000; fl_to = (1000 / context->read_fps) * 1000;
//printf("WTF %d (%f)\n",switch_queue_size(context->eh.video_queue), fl_to); //printf("WTF %d (%f)\n",switch_queue_size(context->eh.video_queue), fl_to);
if (flags & SVR_FLUSH) { if (flags & SVR_FLUSH) {
max_delta = fl_to * AV_TIME_BASE; max_delta = fl_to;
do_fl = 1; do_fl = 1;
} }
@ -1839,10 +1935,19 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
} else if (mst->next_pts && (switch_time_now() - mst->next_pts > -10000)) { } else if (mst->next_pts && (switch_time_now() - mst->next_pts > -10000)) {
frame->img = context->last_img; frame->img = context->last_img;
context->last_img = NULL; context->last_img = NULL;
context->vid_ready = 1;
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
if (!(flags & SVR_BLOCK) && !do_fl) return SWITCH_STATUS_BREAK; if (!(flags & SVR_BLOCK) && !do_fl) {
if (!mst->next_pts) {
frame->img = context->last_img;
context->last_img = NULL;
context->vid_ready = 1;
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_BREAK;
}
} }
if (!context->file_read_thread_running && switch_queue_size(context->eh.video_queue) == 0) { if (!context->file_read_thread_running && switch_queue_size(context->eh.video_queue) == 0) {
@ -1870,48 +1975,52 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
if (pop && status == SWITCH_STATUS_SUCCESS) { if (pop && status == SWITCH_STATUS_SUCCESS) {
switch_image_t *img = (switch_image_t *)pop; switch_image_t *img = (switch_image_t *)pop;
uint64_t pts; int64_t pts;
uint64_t now = switch_time_now(); int64_t now = switch_time_now();
pts = av_rescale_q(*((uint64_t *)img->user_priv), st->time_base, AV_TIME_BASE_Q); pts = av_rescale_q(*((uint64_t *)img->user_priv), st->time_base, AV_TIME_BASE_Q);
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "pkt_pts: %lld pts: %lld queue size: %u\n", *((uint64_t *)img->user_priv), pts, switch_queue_size(context->eh.video_queue));
if (!context->video_start_time) { if (!context->video_start_time) {
context->video_start_time = now - pts; context->video_start_time = now - pts;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "set start time: %" SWITCH_INT64_T_FMT " now: %" SWITCH_INT64_T_FMT " pts: %" SWITCH_INT64_T_FMT "\n", context->video_start_time, now, pts);
} }
if (st->time_base.num == 0) { if (st->time_base.num == 0) {
mst->next_pts = 0; mst->next_pts = 0;
} else { } else {
//uint64_t last_pts = mst->next_pts; // int64_t last_pts = mst->next_pts;
mst->next_pts = context->video_start_time + pts; mst->next_pts = context->video_start_time + pts;
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "pts: %" SWITCH_INT64_T_FMT " last_pts: %" SWITCH_INT64_T_FMT " delta: %" SWITCH_INT64_T_FMT " frame_pts: %" SWITCH_INT64_T_FMT " nextpts: %" SWITCH_INT64_T_FMT ", num: %d, den:%d num:%d den:%d sleep: %" SWITCH_INT64_T_FMT "\n", // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "pts: %" SWITCH_INT64_T_FMT " last_pts: %" SWITCH_INT64_T_FMT " delta: %" SWITCH_INT64_T_FMT " frame_pts: %" SWITCH_INT64_T_FMT " nextpts: %" SWITCH_INT64_T_FMT ", num: %d, den:%d num:%d den:%d sleep: %" SWITCH_INT64_T_FMT "\n",
//pts, last_pts, mst->next_pts - last_pts, *((uint64_t *)img->user_priv), mst->next_pts, st->time_base.num, st->time_base.den, st->codec->time_base.num, st->codec->time_base.den, mst->next_pts - now); // pts, last_pts, mst->next_pts - last_pts, *((uint64_t *)img->user_priv), mst->next_pts, st->time_base.num, st->time_base.den, st->codec->time_base.num, st->codec->time_base.den, mst->next_pts - now);
} }
if (pts == 0) mst->next_pts = 0; if (pts == 0 || context->video_start_time == 0) mst->next_pts = 0;
if ((mst->next_pts && switch_time_now() - mst->next_pts > max_delta)) { if ((mst->next_pts && (now - mst->next_pts) > max_delta)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG3, "picture is too late, off: %" SWITCH_INT64_T_FMT " queue size:%u\n", (int64_t)(switch_time_now() - mst->next_pts), switch_queue_size(context->eh.video_queue)); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "picture is too late, off: %" SWITCH_INT64_T_FMT " max delta: %" SWITCH_INT64_T_FMT " queue size:%u\n", (int64_t)(now - mst->next_pts), max_delta, switch_queue_size(context->eh.video_queue));
switch_img_free(&img); switch_img_free(&img);
max_delta = AV_TIME_BASE; max_delta = AV_TIME_BASE;
if (switch_queue_size(context->eh.video_queue) > 0) { if (switch_queue_size(context->eh.video_queue) > 0) {
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "WTF again\n");
goto again; goto again;
} else if (!(flags & SVR_BLOCK) && !do_fl) { } else if (!(flags & SVR_BLOCK) && !do_fl) {
mst->next_pts = 0; mst->next_pts = 0;
context->video_start_time = 0;
return SWITCH_STATUS_BREAK; return SWITCH_STATUS_BREAK;
} }
} }
if ((flags & SVR_BLOCK) || do_fl) { if ((flags & SVR_BLOCK) || do_fl) {
while (switch_micro_time_now() - mst->next_pts < -10000 / 2) { while (switch_micro_time_now() - mst->next_pts < -10000) {
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "yield\n"); // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "yield, delta=%" SWITCH_INT64_T_FMT "\n", switch_micro_time_now() - mst->next_pts);
switch_yield(10000); switch_yield(1000);
} }
frame->img = img; frame->img = img;
do_fl = 0; do_fl = 0;
} else { } else {
if (switch_micro_time_now() - mst->next_pts > -10000 / 2) { if (switch_micro_time_now() - mst->next_pts > -10000) {
frame->img = img; frame->img = img;
} else { } else {
context->last_img = img; context->last_img = img;
@ -1923,8 +2032,13 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
return SWITCH_STATUS_BREAK; return SWITCH_STATUS_BREAK;
} }
if (frame->img) {
context->vid_ready = 1;
}
return frame->img ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; return frame->img ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
} }
#endif
static switch_status_t av_file_write_video(switch_file_handle_t *handle, switch_frame_t *frame) static switch_status_t av_file_write_video(switch_file_handle_t *handle, switch_frame_t *frame)
{ {
@ -1978,7 +2092,7 @@ static switch_status_t av_file_write_video(switch_file_handle_t *handle, switch_
//switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME); //switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&context->eh.video_thread, thd_attr, video_thread_run, &context->eh, handle->memory_pool); switch_thread_create(&context->eh.video_thread, thd_attr, video_thread_run, &context->eh, handle->memory_pool);
switch_core_timer_init(&context->video_timer, "soft", 1, 1, context->pool); switch_core_timer_init(&context->video_timer, "soft", 66, 1, context->pool);
switch_buffer_zero(context->audio_buffer); switch_buffer_zero(context->audio_buffer);
context->audio_st.frame->pts = 0; context->audio_st.frame->pts = 0;
context->audio_st.next_pts = 0; context->audio_st.next_pts = 0;

View File

@ -71,6 +71,7 @@ typedef struct core_video_globals_s {
int cur_cpu; int cur_cpu;
switch_memory_pool_t *pool; switch_memory_pool_t *pool;
switch_mutex_t *mutex; switch_mutex_t *mutex;
uint32_t fps;
} core_video_globals_t; } core_video_globals_t;
static core_video_globals_t video_globals = { 0 }; static core_video_globals_t video_globals = { 0 };
@ -229,6 +230,7 @@ struct switch_media_handle_s {
time_t vid_started; time_t vid_started;
int ready_loops; int ready_loops;
switch_thread_t *video_write_thread;
}; };
static switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID] = { static switch_srtp_crypto_suite_t SUITES[CRYPTO_INVALID] = {
@ -1964,7 +1966,7 @@ static void check_jb(switch_core_session_t *session, const char *input, int32_t
static void check_jb_sync(switch_core_session_t *session) static void check_jb_sync(switch_core_session_t *session)
{ {
int32_t jb_sync_msec = 0; int32_t jb_sync_msec = 0;
uint32_t fps, frames = 0; uint32_t fps = 0, frames = 0;
uint32_t min_frames = 0; uint32_t min_frames = 0;
uint32_t max_frames = 0; uint32_t max_frames = 0;
uint32_t cur_frames = 0; uint32_t cur_frames = 0;
@ -2037,12 +2039,16 @@ static void check_jb_sync(switch_core_session_t *session)
sync_video = 1; sync_video = 1;
} }
if (fps) {
video_globals.fps = fps;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
SWITCH_LOG_DEBUG1, "%s %s \"%s\" Sync A/V JB to %dms %u VFrames FPS %u a:%s v:%s\n", SWITCH_LOG_DEBUG1, "%s %s \"%s\" Sync A/V JB to %dms %u VFrames FPS %u a:%s v:%s\n",
switch_core_session_get_uuid(session), switch_core_session_get_uuid(session),
switch_channel_get_name(session->channel), switch_channel_get_name(session->channel),
switch_channel_get_variable_dup(session->channel, "caller_id_name", SWITCH_FALSE, -1), switch_channel_get_variable_dup(session->channel, "caller_id_name", SWITCH_FALSE, -1),
jb_sync_msec, frames, fps, sync_audio ? "yes" : "no", sync_video ? "yes" : "no"); jb_sync_msec, frames, video_globals.fps, sync_audio ? "yes" : "no", sync_video ? "yes" : "no");
if (sync_audio) { if (sync_audio) {
check_jb(session, NULL, jb_sync_msec, 0, SWITCH_TRUE); check_jb(session, NULL, jb_sync_msec, 0, SWITCH_TRUE);
@ -2163,6 +2169,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_read_frame(switch_core_session
goto end; goto end;
} }
if (status == SWITCH_STATUS_BREAK) {
goto end;
}
if (type == SWITCH_MEDIA_TYPE_VIDEO && engine->read_frame.m) { if (type == SWITCH_MEDIA_TYPE_VIDEO && engine->read_frame.m) {
if (!smh->vid_started) { if (!smh->vid_started) {
smh->vid_started = switch_epoch_time_now(NULL); smh->vid_started = switch_epoch_time_now(NULL);
@ -4955,6 +4965,73 @@ SWITCH_DECLARE(switch_file_handle_t *) switch_core_media_get_video_file(switch_c
} }
static void *SWITCH_THREAD_FUNC video_write_thread(switch_thread_t *thread, void *obj)
{
switch_core_session_t *session = (switch_core_session_t *) obj;
switch_media_handle_t *smh;
unsigned char *buf = NULL;
switch_frame_t fr = { 0 };
switch_rtp_engine_t *v_engine;
int buflen = SWITCH_RTP_MAX_BUF_LEN;
switch_timer_t timer = { 0 };
int fps;
if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
return NULL;
}
if (!(smh = session->media_handle)) {
return NULL;
}
v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
buf = switch_core_session_alloc(session, buflen);
fr.packet = buf;
fr.packetlen = buflen;
fr.data = buf + 12;
fr.buflen = buflen - 12;
switch_core_media_gen_key_frame(session);
if (smh->video_write_fh->mm.source_fps) {
fps = (int) smh->video_write_fh->mm.source_fps;
} else {
fps = video_globals.fps;
}
if (!fps) {
fps = 15;
}
switch_core_timer_init(&timer, "soft", (int)(1000 / fps) , 1, switch_core_session_get_pool(session));
while (switch_channel_up_nosig(session->channel) && smh->video_write_fh && switch_test_flag(smh->video_write_fh, SWITCH_FILE_OPEN)) {
switch_status_t wstatus;
switch_core_timer_next(&timer);
switch_mutex_lock(v_engine->mh.file_mutex);
wstatus = switch_core_file_read_video(smh->video_write_fh, &fr, SVR_BLOCK);
if (wstatus == SWITCH_STATUS_SUCCESS) {
switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_NONE, SVR_FLUSH);
switch_img_free(&fr.img);
} else if (wstatus != SWITCH_STATUS_BREAK && wstatus != SWITCH_STATUS_IGNORE) {
smh->video_write_fh = NULL;
}
switch_mutex_unlock(v_engine->mh.file_mutex);
}
switch_core_timer_destroy(&timer);
switch_core_session_rwunlock(session);
return NULL;
}
SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh, switch_rw_t rw) SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_session_t *session, switch_file_handle_t *fh, switch_rw_t rw)
{ {
switch_media_handle_t *smh; switch_media_handle_t *smh;
@ -5004,7 +5081,24 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_ses
} }
switch_core_media_gen_key_frame(session); switch_core_media_gen_key_frame(session);
if (fh) {
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, switch_core_session_get_pool(session));
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&smh->video_write_thread, thd_attr, video_write_thread, session, switch_core_session_get_pool(session));
}
smh->video_write_fh = fh; smh->video_write_fh = fh;
if (!fh && smh->video_write_thread) {
switch_status_t st;
switch_thread_join(&st, smh->video_write_thread);
}
} }
if (!fh) switch_channel_video_sync(session->channel); if (!fh) switch_channel_video_sync(session->channel);
@ -5045,9 +5139,9 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
switch_frame_t *read_frame = NULL; switch_frame_t *read_frame = NULL;
switch_media_handle_t *smh; switch_media_handle_t *smh;
uint32_t loops = 0, xloops = 0, vloops = 0; uint32_t loops = 0, xloops = 0, vloops = 0;
switch_image_t *blank_img = NULL;
switch_frame_t fr = { 0 }; switch_frame_t fr = { 0 };
unsigned char *buf = NULL; unsigned char *buf = NULL;
switch_image_t *blank_img = NULL;
switch_rgb_color_t bgcolor; switch_rgb_color_t bgcolor;
switch_rtp_engine_t *v_engine = NULL; switch_rtp_engine_t *v_engine = NULL;
@ -5139,13 +5233,13 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
} }
//if (!smh->video_write_fh || !switch_channel_test_flag(channel, CF_VIDEO_READY)) { //if (!smh->video_write_fh || !switch_channel_test_flag(channel, CF_VIDEO_READY)) {
status = switch_core_session_read_video_frame(session, &read_frame, smh->video_write_fh ? SWITCH_IO_FLAG_NOBLOCK : SWITCH_IO_FLAG_NONE, 0); status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) { if (!SWITCH_READ_ACCEPTABLE(status)) {
switch_cond_next(); switch_cond_next();
continue; continue;
} }
//if (switch_test_flag(read_frame, SFF_CNG)) { //if (switch_test_flag(read_frame, SFF_CNG)) {
// continue; // continue;
//} //}
@ -5167,19 +5261,11 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
fr.buflen = buflen - 12; fr.buflen = buflen - 12;
switch_core_media_gen_key_frame(session); switch_core_media_gen_key_frame(session);
} }
if (switch_channel_test_flag(channel, CF_VIDEO_READY)) { if (switch_channel_test_flag(channel, CF_VIDEO_READY)) {
switch_mutex_lock(mh->file_mutex); switch_mutex_lock(mh->file_mutex);
if (smh->video_write_fh && switch_channel_ready(session->channel) && switch_test_flag(smh->video_write_fh, SWITCH_FILE_OPEN)) { if (smh->video_read_fh && switch_test_flag(smh->video_read_fh, SWITCH_FILE_OPEN) && read_frame->img) {
switch_status_t wstatus = switch_core_file_read_video(smh->video_write_fh, &fr, 0);
if (wstatus == SWITCH_STATUS_SUCCESS) {
switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_NONE, SVR_FLUSH);
switch_img_free(&fr.img);
} else if (wstatus != SWITCH_STATUS_BREAK && wstatus != SWITCH_STATUS_IGNORE) {
smh->video_write_fh = NULL;
}
send_blank = 0;
} else if (smh->video_read_fh && switch_test_flag(smh->video_read_fh, SWITCH_FILE_OPEN) && read_frame->img) {
switch_core_file_write_video(smh->video_read_fh, read_frame); switch_core_file_write_video(smh->video_read_fh, read_frame);
send_blank = 0; send_blank = 0;
} }

View File

@ -5159,7 +5159,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
if (*bytes) { if (*bytes) {
b = (unsigned char *) &rtp_session->recv_msg; b = (unsigned char *) &rtp_session->recv_msg;
/* version 2 probably rtp, zrtp cookie present means zrtp */ /* version 2 probably rtp, zrtp cookie present means zrtp */
rtp_session->has_rtp = (rtp_session->recv_msg.header.version == 2 || ntohl(*(int *)(b+4)) == ZRTP_MAGIC_COOKIE); rtp_session->has_rtp = (rtp_session->recv_msg.header.version == 2 || ntohl(*(int *)(b+4)) == ZRTP_MAGIC_COOKIE);
@ -6276,11 +6276,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
pt = 20000; pt = 20000;
} }
if ((io_flags & SWITCH_IO_FLAG_NOBLOCK)) {
pt = 0;
}
if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && !rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA]) { if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && !rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA]) {
pt = 200000; pt = 200000;
} }
@ -6290,6 +6285,10 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
pt = 0; pt = 0;
} }
} }
if ((io_flags & SWITCH_IO_FLAG_NOBLOCK)) {
pt = 0;
}
poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, pt); poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, pt);
@ -6397,8 +6396,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
ret = -1; ret = -1;
goto end; goto end;
} }
if ((!(io_flags & SWITCH_IO_FLAG_NOBLOCK)) && if ((!(io_flags & SWITCH_IO_FLAG_NOBLOCK)) &&
(rtp_session->dtmf_data.out_digit_dur == 0) && !rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP]) { (rtp_session->dtmf_data.out_digit_dur == 0) && !rtp_session->flags[SWITCH_RTP_FLAG_ENABLE_RTCP]) {
return_cng_frame(); return_cng_frame();
@ -6506,7 +6505,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
switch_core_timer_sync(&rtp_session->timer); switch_core_timer_sync(&rtp_session->timer);
reset_jitter_seq(rtp_session); reset_jitter_seq(rtp_session);
} }
goto recvfrom; goto recvfrom;
} }
} }

View File

@ -783,7 +783,7 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *
context->codec_settings.video.height = height; context->codec_settings.video.height = height;
reset_codec_encoder(codec); reset_codec_encoder(codec);
frame->flags |= SFF_PICTURE_RESET; frame->flags |= SFF_PICTURE_RESET;
context->need_key_frame = 1; context->need_key_frame = 3;
} }
@ -803,7 +803,7 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *
now = switch_time_now(); now = switch_time_now();
if (context->need_key_frame != 0) { if (context->need_key_frame > 0) {
// force generate a key frame // force generate a key frame
if (!context->last_key_frame || (now - context->last_key_frame) > KEY_FRAME_MIN_FREQ) { if (!context->last_key_frame || (now - context->last_key_frame) > KEY_FRAME_MIN_FREQ) {