From 68588e811fcad79c8fbd390baaa21b22b6d24909 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 8 Mar 2016 18:53:55 -0600 Subject: [PATCH] FS-8914 #resolve [recording mp4 cuts off the end in some cases] --- src/include/switch_core_media.h | 1 + src/include/switch_types.h | 5 ++- src/mod/applications/mod_av/avformat.c | 54 +++++++++++++++++++++----- src/switch_core_media.c | 41 ++++++++++++++++++- src/switch_ivr_play_say.c | 5 ++- 5 files changed, 92 insertions(+), 14 deletions(-) diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 65c400ea33..3a09b3163f 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -348,6 +348,7 @@ SWITCH_DECLARE(switch_bool_t) switch_core_session_in_video_thread(switch_core_se SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t *session, switch_media_type_t type); SWITCH_DECLARE(switch_status_t) switch_core_media_set_outgoing_bitrate(switch_core_session_t *session, switch_media_type_t type, uint32_t bitrate); SWITCH_DECLARE(switch_status_t) switch_core_media_reset_jb(switch_core_session_t *session, switch_media_type_t type); +SWITCH_DECLARE(switch_status_t) switch_core_session_wait_for_video_input_params(switch_core_session_t *session, uint32_t timeout_ms); SWITCH_END_EXTERN_C #endif diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 31f4ebfc31..0883285587 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1517,8 +1517,9 @@ typedef enum { } switch_channel_flag_t; typedef struct switch_vid_params_s { - int width; - int height; + uint32_t width; + uint32_t height; + uint32_t fps; } switch_vid_params_t; diff --git a/src/mod/applications/mod_av/avformat.c b/src/mod/applications/mod_av/avformat.c index 190a23456f..2df8e951e9 100644 --- a/src/mod/applications/mod_av/avformat.c +++ b/src/mod/applications/mod_av/avformat.c @@ -143,6 +143,7 @@ typedef struct record_helper_s { switch_queue_t *video_queue; switch_thread_t *video_thread; switch_mm_t *mm; + int finalize; } record_helper_t; static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt) @@ -514,6 +515,7 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void * switch_image_t *img = NULL, *tmp_img = NULL; int d_w = eh->video_st->width, d_h = eh->video_st->height; int size = 0, skip = 0, skip_freq = 0, skip_count = 0, skip_total = 0, skip_total_count = 0; + uint64_t delta = 0, last_ts = 0; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "video thread start\n"); @@ -557,7 +559,7 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void * size = switch_queue_size(eh->video_queue); - if (size > 5) { + if (size > 5 && !eh->finalize) { skip = size; if (size > 10) { @@ -585,14 +587,25 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void * fill_avframe(eh->video_st->frame, img); switch_core_timer_sync(eh->timer); - if (eh->video_st->frame->pts == eh->timer->samplecount) { + if (eh->finalize && delta) { + eh->video_st->frame->pts += delta; + } else if (eh->video_st->frame->pts == eh->timer->samplecount) { // never use the same pts, or the encoder coughs eh->video_st->frame->pts++; } else { + uint64_t delta_tmp = eh->timer->samplecount - last_ts; + + if (delta_tmp > 1) { + delta = delta_tmp; + } + eh->video_st->frame->pts = eh->timer->samplecount; } - // eh->video_st->frame->pts = switch_time_now() / 1000 - eh->video_st->next_pts; - // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "pts: %lld\n", eh->video_st->frame->pts); + + last_ts = eh->video_st->frame->pts; + + //eh->video_st->frame->pts = switch_time_now() / 1000 - eh->video_st->next_pts; + //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "pts: %ld\n", eh->video_st->frame->pts); /* encode the image */ ret = avcodec_encode_video2(eh->video_st->st->codec, &pkt, eh->video_st->frame, &got_packet); @@ -1573,7 +1586,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa if (fmt->video_codec != AV_CODEC_ID_NONE) { const AVCodecDescriptor *desc; - if (handle->stream_name && (!strcasecmp(handle->stream_name, "rtmp") || !strcasecmp(handle->stream_name, "youtube"))) { + if ((handle->stream_name && (!strcasecmp(handle->stream_name, "rtmp") || !strcasecmp(handle->stream_name, "youtube"))) || !strcasecmp(ext, "mp4")) { if (fmt->video_codec != AV_CODEC_ID_H264 ) { fmt->video_codec = AV_CODEC_ID_H264; // force H264 } @@ -1608,7 +1621,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa } } - if (handle->mm.fps > 0.0f) { + if (handle->stream_name && handle->mm.fps > 0.0f) { handle->mm.keyint = (int) 2.0f * handle->mm.fps; } } @@ -1684,6 +1697,7 @@ static switch_status_t av_file_write(switch_file_handle_t *handle, void *data, s } if (!context->vid_ready) { + switch_buffer_zero(context->audio_buffer); return status; } @@ -1793,16 +1807,39 @@ static switch_status_t av_file_close(switch_file_handle_t *handle) switch_status_t status; context->closed = 1; + context->eh.finalize = 1; if (context->eh.video_queue) { + + + if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { + switch_rgb_color_t bgcolor; + int x; + + switch_color_set_rgb(&bgcolor, "#000000"); + x = (int)handle->mm.fps * 1; + + if (x <= 0) x = 100; + + while(handle->mm.vw && x-- > 0) { + switch_image_t *blank_img = NULL; + if ((blank_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, handle->mm.vw, handle->mm.vh, 1))) { + switch_img_fill(blank_img, 0, 0, blank_img->d_w, blank_img->d_h, &bgcolor); + switch_queue_push(context->eh.video_queue, blank_img); + } + } + + } switch_queue_push(context->eh.video_queue, NULL); } + if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { + av_file_write(handle, NULL, NULL); + } + if (context->eh.video_thread) { switch_thread_join(&status, context->eh.video_thread); } - - av_file_write(handle, NULL, NULL); if (context->file_read_thread_running && context->file_read_thread) { context->file_read_thread_running = 0; @@ -1857,7 +1894,6 @@ static switch_status_t av_file_read(switch_file_handle_t *handle, void *data, si } switch_mutex_lock(context->mutex); - size = switch_buffer_read(context->audio_buffer, data, need); switch_mutex_unlock(context->mutex); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index a3dba3cfd1..84c16a6ce6 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -2044,6 +2044,7 @@ static void check_jb_sync(switch_core_session_t *session) if (fps) { video_globals.fps = fps; + smh->vid_params.fps = fps; } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), @@ -11171,6 +11172,44 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor return status; } +SWITCH_DECLARE(switch_status_t) switch_core_session_wait_for_video_input_params(switch_core_session_t *session, uint32_t timeout_ms) +{ + switch_media_handle_t *smh; + switch_codec_implementation_t read_impl = { 0 }; + + switch_assert(session != NULL); + + if (!(smh = session->media_handle)) { + return SWITCH_STATUS_FALSE; + } + + if (!switch_channel_test_flag(session->channel, CF_VIDEO_DECODED_READ)) { + return SWITCH_STATUS_GENERR;; + } + + switch_core_session_get_read_impl(session, &read_impl); + + while(switch_channel_ready(session->channel) && timeout_ms > 0) { + switch_frame_t *read_frame; + switch_status_t status; + + status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + break; + } + + if (switch_channel_test_flag(session->channel, CF_VIDEO_READY) && smh->vid_params.width && smh->vid_params.height && smh->vid_params.fps) { + return SWITCH_STATUS_SUCCESS; + } + + timeout_ms -= (read_impl.microseconds_per_packet / 1000); + } + + return SWITCH_STATUS_TIMEOUT; + +} + SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id) { @@ -11252,7 +11291,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core decode_status = switch_core_codec_decode_video((*frame)->codec, *frame); - if ((*frame)->img && switch_channel_test_flag(session->channel, CF_VIDEO_DEBUG_READ)) { + if ((*frame)->img) {//((*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); } diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index a99690d95f..3c8465885a 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -536,10 +536,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se file_flags |= SWITCH_FILE_FLAG_VIDEO; switch_channel_set_flag_recursive(channel, CF_VIDEO_DECODED_READ); - fh->mm.fps = switch_core_media_get_video_fps(session); + switch_core_session_wait_for_video_input_params(session, 10000); switch_core_media_get_vid_params(session, &vid_params); fh->mm.vw = vid_params.width; fh->mm.vh = vid_params.height; + fh->mm.fps = vid_params.fps; } if (switch_core_file_open(fh, file, fh->channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) { @@ -579,7 +580,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se switch_channel_set_flag_recursive(channel, CF_VIDEO_DECODED_READ); switch_channel_set_flag(channel, CF_VIDEO_ECHO); } - + switch_core_media_set_video_file(session, fh, SWITCH_RW_READ); } else if (switch_channel_test_flag(channel, CF_VIDEO)) { switch_channel_set_flag(channel, CF_VIDEO_BLANK);