]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7500: add decode_video App
authorSeven Du <dujinfang@gmail.com>
Sun, 27 Jul 2014 22:41:58 +0000 (06:41 +0800)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:46:42 +0000 (12:46 -0500)
src/mod/applications/mod_fsv/mod_fsv.c

index cd43395d80934a27268cedeb352429ccf3e2396c..c569de1c0eddeae8372f369ca6aa0167d6369242 100644 (file)
@@ -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, "<file>", SAF_NONE);
-       SWITCH_ADD_APP(app_interface, "play_yuv", "play a yvv file", "play a yvv file in I420 format", play_yuv_function, "<file> [width] [height]", SAF_NONE);
        SWITCH_ADD_APP(app_interface, "record_fsv", "record an fsv file", "record an fsv file", record_fsv_function, "<file>", SAF_NONE);
+       SWITCH_ADD_APP(app_interface, "play_yuv", "play a yvv file", "play a yvv file in I420 format", play_yuv_function, "<file> [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;