From 71cafe536b4afe33422aa10d1d0c7629b5b57fa0 Mon Sep 17 00:00:00 2001 From: Seven Du Date: Mon, 28 Jul 2014 06:41:58 +0800 Subject: [PATCH] FS-7500: add decode_video App --- src/mod/applications/mod_fsv/mod_fsv.c | 145 ++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) diff --git a/src/mod/applications/mod_fsv/mod_fsv.c b/src/mod/applications/mod_fsv/mod_fsv.c index cd43395d80..c569de1c0e 100644 --- a/src/mod/applications/mod_fsv/mod_fsv.c +++ b/src/mod/applications/mod_fsv/mod_fsv.c @@ -593,7 +593,6 @@ SWITCH_STANDARD_APP(play_yuv_function) width = width ? width : 352; height = height ? height : 288; size = width * height * 3 / 2; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%d %d\n", width, height); yuv = malloc(size); if (!yuv) { @@ -731,6 +730,147 @@ SWITCH_STANDARD_APP(play_yuv_function) switch_channel_set_flag(channel, CF_VIDEO_ECHO); } + +SWITCH_STANDARD_APP(decode_video_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_codec_t *codec = NULL; + switch_dtmf_t dtmf = { 0 }; + switch_frame_t *frame; + uint32_t size; + uint32_t width = 0, height = 0; + switch_byte_t *yuv; + switch_time_t last = switch_micro_time_now(); + uint32_t max_pictures = 0; + uint32_t decoded_pictures = 0; + + if (!zstr(data)) max_pictures = atoi(data); + + switch_channel_set_flag(channel, CF_VIDEO_PASSIVE); + switch_channel_clear_flag(channel, CF_VIDEO_ECHO); + switch_channel_answer(channel); + + if (!switch_channel_test_flag(channel, CF_VIDEO)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Channel %s has no video\n", switch_channel_get_name(channel)); + goto done; + } + + switch_core_session_refresh_video(session); + + size = 1920 * 1080 * 3 / 2; + yuv = malloc(size); + + if (!yuv) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n"); + goto done; + } + + switch_channel_set_variable(channel, SWITCH_PLAYBACK_TERMINATOR_USED, ""); + + + codec = switch_core_session_get_video_read_codec(session); + if (!codec) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Channel has no video read codec\n"); + goto done; + } + + while (switch_channel_ready(channel)) { + switch_core_session_read_video_frame(session, &frame, SWITCH_IO_FLAG_NONE, 0); + + if (switch_channel_test_flag(channel, CF_BREAK)) { + switch_channel_clear_flag(channel, CF_BREAK); + break; + } + + switch_ivr_parse_all_events(session); + + //check for dtmf interrupts + 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; + } + } + + if (frame) { + switch_core_session_write_video_frame(session, frame, SWITCH_IO_FLAG_NONE, 0); + } else { + continue; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "seq: %d ts: %ld len: %4d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x mark: %d %s\n", + frame->seq, frame->timestamp, frame->datalen, + *((uint8_t *)frame->data), *((uint8_t *)frame->data + 1), + *((uint8_t *)frame->data + 2), *((uint8_t *)frame->data + 3), + *((uint8_t *)frame->data + 4), *((uint8_t *)frame->data + 5), + *((uint8_t *)frame->data + 6), *((uint8_t *)frame->data + 7), + *((uint8_t *)frame->data + 8), *((uint8_t *)frame->data + 9), + *((uint8_t *)frame->data + 10), frame->m, switch_test_flag(frame, SFF_CNG) ? " CNG" : ""); + + if (switch_test_flag(frame, SFF_CNG)) { + continue; + } + + if ( 1 ) { /* video part */ + uint32_t decoded_rate = 0; + uint32_t decoded_data_len = size; + uint32_t flag = 0; + + codec->cur_frame = frame; + switch_core_codec_decode(codec, NULL, frame->data, frame->datalen, 0, yuv, &decoded_data_len, &decoded_rate, &flag); + + if (switch_test_flag(codec->cur_frame, SFF_WAIT_KEY_FRAME)) { + switch_time_t now = switch_micro_time_now(); + if (now - last > 3000000) { + switch_core_session_refresh_video(session); + last = now; + } + continue; + } + + if (decoded_data_len > 0) { + if (codec->dec_picture.width > 0 && !width) { + width = codec->dec_picture.width; + switch_channel_set_variable_printf(channel, "video_width", "%d", width); + } + + if (codec->dec_picture.height > 0 && !height) { + height = codec->dec_picture.height; + switch_channel_set_variable_printf(channel, "video_height", "%d", height); + } + + decoded_pictures++; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "picture#%d %dx%d len: %d \n", decoded_pictures, codec->dec_picture.width, codec->dec_picture.height, decoded_data_len); + + if (max_pictures && (decoded_pictures >= max_pictures)) { + break; + } + } + } + } + + switch_core_thread_session_end(session); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "OK"); + + switch_safe_free(yuv); + + done: + switch_channel_clear_flag(channel, CF_VIDEO_PASSIVE); + switch_channel_set_flag(channel, CF_VIDEO_ECHO); +} + + +/* File Interface*/ + struct fsv_file_context { switch_file_t *fd; char *path; @@ -1024,8 +1164,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_fsv_load) file_interface->file_get_string = fsv_file_get_string; SWITCH_ADD_APP(app_interface, "play_fsv", "play a fsv file", "play a fsv file", play_fsv_function, "", SAF_NONE); - SWITCH_ADD_APP(app_interface, "play_yuv", "play a yvv file", "play a yvv file in I420 format", play_yuv_function, " [width] [height]", SAF_NONE); SWITCH_ADD_APP(app_interface, "record_fsv", "record an fsv file", "record an fsv file", record_fsv_function, "", SAF_NONE); + SWITCH_ADD_APP(app_interface, "play_yuv", "play a yvv file", "play a yvv file in I420 format", play_yuv_function, " [width] [height]", SAF_NONE); + SWITCH_ADD_APP(app_interface, "decode_video", "decode picture", "decode picture and dump to log", decode_video_function, "[max_pictures]", SAF_NONE); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS;