]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7513: refactor conference video muxing to create one distinct encoder per codec...
authorAnthony Minessale <anthm@freeswitch.org>
Thu, 5 Feb 2015 02:23:17 +0000 (20:23 -0600)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:46:57 +0000 (12:46 -0500)
src/include/switch_core.h
src/include/switch_core_video.h
src/mod/applications/mod_conference/mod_conference.c
src/switch_core_media.c
src/switch_core_video.c
src/switch_rtp.c
src/switch_vidderbuffer.c

index 261ea97502087ddf0291f81495db014ed150e2e5..581b2cbe43c5aa8400388c48a47dd9b10bdd74b1 100644 (file)
@@ -1283,6 +1283,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(_In_ switch
 SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(_In_ switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags,
                                                                                                                                          int stream_id);
 
+SWITCH_DECLARE(switch_status_t) switch_core_session_write_encoded_video_frame(switch_core_session_t *session, 
+                                                                                                                                               switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+
 SWITCH_DECLARE(switch_status_t) switch_core_session_set_read_impl(switch_core_session_t *session, const switch_codec_implementation_t *impp);
 SWITCH_DECLARE(switch_status_t) switch_core_session_set_write_impl(switch_core_session_t *session, const switch_codec_implementation_t *impp);
 SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_read_impl(switch_core_session_t *session, const switch_codec_implementation_t *impp);
index ef9869f95faf26905896a7468d300f41735747b8..51f4dd6ffee2eec146f53b45e9d75c4388479a15 100644 (file)
@@ -143,6 +143,9 @@ SWITCH_DECLARE(int) switch_img_set_rect(switch_image_t  *img,
                                   unsigned int  w,
                                   unsigned int  h);
 
+
+SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y);
+
 /*!\brief Copy image to a new image
 *
 * if new_img is NULL, a new image is allocated
index 7535ac27de47723b9de96bd37b8841109ef889e5..80ddd0886cd33d0aba25ba82f5be54b70e3e1a48 100644 (file)
@@ -353,6 +353,7 @@ typedef struct mcu_layer_s {
        mcu_layer_geometry_t geometry;
        int member_id;
        switch_image_t *img;
+       switch_image_t *cur_img;
 } mcu_layer_t;
 
 typedef struct bgcolor_yuv_s
@@ -584,6 +585,8 @@ struct conference_member {
        al_handle_t *al;
        int last_speech_channels;
        int video_layer_id;
+       int video_codec_index;
+       int video_codec_id;
 };
 
 typedef enum {
@@ -893,36 +896,6 @@ static void set_bgcolor(bgcolor_yuv_t *bgcolor, char *bgcolor_str)
        bgcolor->v = v;
 }
 
-// simple implementation to patch a small img to a big IMG at position x,y
-static void patch_image(switch_image_t *IMG, switch_image_t *img, int x, int y)
-{
-       int i, j, k;
-       int W = IMG->d_w;
-       int H = IMG->d_h;
-       int w = img->d_w;
-       int h = img->d_h;
-
-       switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
-       switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420);
-
-       for (i = y; i < (y + h) && i < H; i++) {
-               for (j = x; j < (x + w) && j < W; j++) {
-                       IMG->planes[0][i * IMG->stride[0] + j] = img->planes[0][(i - y) * img->stride[0] + (j - x)];
-               }
-       }
-
-       for (i = y; i < (y + h) && i < H; i+=4) {
-               for (j = x; j < (x + w) && j < W; j+=4) {
-                       for (k = 1; k <= 2; k++) {
-                               IMG->planes[k][i/2 * IMG->stride[k] + j/2]         = img->planes[k][(i-y)/2 * img->stride[k] + (j-x)/2];
-                               IMG->planes[k][i/2 * IMG->stride[k] + j/2 + 1]     = img->planes[k][(i-y)/2 * img->stride[k] + (j-x)/2 + 1];
-                               IMG->planes[k][(i+2)/2 * IMG->stride[k] + j/2]     = img->planes[k][(i+2-y)/2 * img->stride[k] + (j-x)/2];
-                               IMG->planes[k][(i+2)/2 * IMG->stride[k] + j/2 + 1] = img->planes[k][(i+2-y)/2 * img->stride[k] + (j-x)/2 + 1];
-                       }
-               }
-       }
-}
-
 #define SCALE_FACTOR 360
 
 static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer)
@@ -947,13 +920,17 @@ static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer)
        switch_assert(layer->img);
 
        reset_image(layer->img, &canvas->bgcolor);
-       patch_image(canvas->img, layer->img, x, y);
+       switch_img_patch(canvas->img, layer->img, x, y);
+       switch_img_free(&layer->cur_img);
+
 }
 
-static void scale_and_patch(switch_image_t *IMG, switch_image_t *img, mcu_layer_t *layer)
+static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer)
 {
        int ret;
        int x = 0, y = 0;
+       switch_image_t *IMG = conference->canvas->img, *img = layer->cur_img;
+
 
        if (layer->geometry.scale) {
                int screen_w = 0, screen_h = 0, img_w = 0, img_h = 0;
@@ -1014,11 +991,11 @@ static void scale_and_patch(switch_image_t *IMG, switch_image_t *img, mcu_layer_
                if (ret != 0) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scaling Error: ret: %d\n", ret);
                } else {
-                       patch_image(IMG, layer->img, x, y);
+                       switch_img_patch(IMG, layer->img, x, y);
                }
        } else {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "insert at %d,%d\n", x, y);
-               patch_image(IMG, img, x, y);
+               switch_img_patch(IMG, img, x, y);
        }
 }
 
@@ -1053,9 +1030,7 @@ static void init_canvas(conference_obj_t *conference, layout_node_t *lnode)
                switch_mutex_init(&conference->canvas->cond2_mutex, SWITCH_MUTEX_NESTED, conference->pool);
        }
 
-       if (conference->canvas->img) {
-               switch_img_free(&conference->canvas->img);
-       }
+       switch_img_free(&conference->canvas->img);
 
        conference->canvas->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->canvas_width, conference->canvas_height, 0);
 
@@ -1070,9 +1045,7 @@ static void destroy_canvas(mcu_canvas_t **canvasP) {
        int i;
        mcu_canvas_t *canvas = *canvasP;
 
-       if (canvas->img) {
-               switch_img_free(&canvas->img);
-       }
+       switch_img_free(&canvas->img);
 
        for (i = 0; i < MCU_MAX_LAYERS; i++) {
                switch_img_free(&canvas->layers[i].img);
@@ -1081,22 +1054,112 @@ static void destroy_canvas(mcu_canvas_t **canvasP) {
        *canvasP = NULL;
 }
 
+typedef struct codec_set_s {
+       switch_codec_t codec;
+       switch_frame_t frame;
+       uint8_t *packet;
+} codec_set_t;                                                                                                                                                 
+
+static void write_canvas_image_to_codec_group(conference_obj_t *conference, codec_set_t *codec_set,
+                                                                                         int codec_index, uint32_t timestamp, switch_bool_t need_refresh, switch_bool_t need_keyframe)
+       
+{
+       conference_member_t *imember;
+       switch_frame_t write_frame = { 0 }, *frame = NULL;
+       switch_status_t encode_status = SWITCH_STATUS_FALSE;
+
+       write_frame = codec_set->frame;
+       frame = &write_frame;
+       frame->img = codec_set->frame.img;
+       frame->packet = codec_set->frame.packet;
+       
+       switch_clear_flag(frame, SFF_SAME_IMAGE);
+       frame->m = 0;
+       frame->timestamp = timestamp;
+
+       if (need_refresh || need_keyframe) {
+               switch_core_codec_control(&codec_set->codec, SCC_VIDEO_REFRESH, SCCT_NONE, NULL, NULL, NULL);
+       }
+
+       do {
+
+               frame->data = ((unsigned char *)frame->packet) + 12;
+               frame->datalen = SWITCH_DEFAULT_VIDEO_SIZE;
+
+               encode_status = switch_core_codec_encode_video(&codec_set->codec, frame);
+
+               if (encode_status == SWITCH_STATUS_SUCCESS || encode_status == SWITCH_STATUS_MORE_DATA) {
+
+                       switch_assert((encode_status == SWITCH_STATUS_SUCCESS && frame->m) || !frame->m);
+
+                       switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME);
+                       frame->packetlen = frame->datalen + 12;
+
+                       switch_mutex_lock(conference->member_mutex);
+                       for (imember = conference->members; imember; imember = imember->next) {
+                               switch_channel_t *ichannel = switch_core_session_get_channel(imember->session);
+
+                               if (imember->video_codec_index != codec_index) {
+                                       continue;
+                               }
+
+                               if (!imember->session || !switch_channel_test_flag(ichannel, CF_VIDEO) ||
+                                       switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) {
+                                       continue;
+                               }
+                               
+                               if (need_refresh) {
+                                       switch_core_session_request_video_refresh(imember->session);
+                               }
+                               
+                               switch_core_session_write_encoded_video_frame(imember->session, frame, 0, 0);
+
+                               switch_core_session_rwunlock(imember->session);
+                       }
+                       switch_mutex_unlock(conference->member_mutex);
+               }
+
+       } while(encode_status == SWITCH_STATUS_MORE_DATA);
+}
+
+#define MAX_MUX_CODECS 10
+//#define TRACK_FPS
+
 static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj)
 {
        conference_obj_t *conference = (conference_obj_t *) obj;
        conference_member_t *imember;
-       switch_frame_t write_frame = { 0 };
-       uint8_t *packet = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
        layout_node_t *lnode = switch_core_hash_find(conference->layout_hash, conference->video_layout_name);
+       switch_codec_t *check_codec = NULL;
+       codec_set_t *write_codecs[MAX_MUX_CODECS] = { 0 };
+       int buflen = SWITCH_RECOMMENDED_BUFFER_SIZE * 2;
+       switch_timer_t timer = { 0 };
+       int i = 0;
+       int used = 0, remaining = 0;
+       uint32_t video_key_freq = 10000000;
+       switch_time_t last_key_time = 0;
+       mcu_layer_t *layer = NULL;
+#ifdef TRACK_FPS
+       uint64_t frames = 0;
+       switch_time_t started = switch_micro_time_now();
+#endif
 
        switch_assert(lnode);
 
        init_canvas(conference, lnode);
 
+       switch_core_timer_init(&timer, "soft", 1, 90, conference->pool);
+       
        switch_mutex_lock(conference->canvas->cond_mutex);
 
        while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT) && switch_test_flag(conference, CFLAG_VIDEO_MUXING)) {
+               switch_bool_t need_refresh = SWITCH_FALSE, need_keyframe = SWITCH_FALSE;
+
+       top:
+
                switch_mutex_lock(conference->member_mutex);
+               remaining = 0;
+               used = 0;
 
                for (imember = conference->members; imember; imember = imember->next) {
                        switch_channel_t *ichannel = switch_core_session_get_channel(imember->session);
@@ -1109,25 +1172,73 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                                continue;
                        }
 
+
+                       if (switch_channel_test_flag(ichannel, CF_VIDEO_REFRESH_REQ)) {
+                               switch_channel_clear_flag(ichannel, CF_VIDEO_REFRESH_REQ);
+                               need_refresh = SWITCH_TRUE;
+                       }
+
+                       if (imember->video_codec_index < 0 && (check_codec = switch_core_session_get_video_write_codec(imember->session))) {
+                               for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) {
+                                       if (check_codec->implementation->codec_id == write_codecs[i]->codec.implementation->codec_id) {
+                                               imember->video_codec_index = i;
+                                               imember->video_codec_id = check_codec->implementation->codec_id;
+                                               break;
+                                       }
+                               }
+
+                               if (imember->video_codec_index < 0) {
+                                       write_codecs[i] = switch_core_alloc(conference->pool, sizeof(codec_set_t));
+                                       
+                                       if (switch_core_codec_copy(check_codec, &write_codecs[i]->codec, conference->pool) == SWITCH_STATUS_SUCCESS) {
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, 
+                                                                                 "Setting up video write codec %s at slot %d\n", write_codecs[i]->codec.implementation->iananame, i);
+                                               
+                                               imember->video_codec_index = i;
+                                               imember->video_codec_id = check_codec->implementation->codec_id;
+
+                                               write_codecs[i]->frame.packet = switch_core_alloc(conference->pool, buflen);
+                                               write_codecs[i]->frame.data = ((uint8_t *)write_codecs[i]->frame.packet) + 12;
+                                               write_codecs[i]->frame.packetlen = 0;
+                                               write_codecs[i]->frame.buflen = buflen - 12;
+                                               switch_set_flag((&write_codecs[i]->frame), SFF_RAW_RTP);
+
+                                       }
+                               }
+                       }
+
+                       if (imember->video_codec_index < 0) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Codec Error\n");
+                               continue;
+                       }
+
+                       img = NULL;
+                       size = 0;
+
                        do {
-                               if (switch_queue_trypop(imember->video_queue, &pop) == SWITCH_STATUS_SUCCESS) {
-                                       if (img) switch_img_free(&img);
+                               if (switch_queue_trypop(imember->video_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
+                                       switch_img_free(&img);
                                        img = (switch_image_t *)pop;
+                                       //remaining += switch_queue_size(imember->video_queue);
+                                       //break;
                                } else {
                                        break;
                                }
                                size = switch_queue_size(imember->video_queue);
-                       } while(size > 1);
+                       } while(size > 0);
 
                        if (img) {
-                               mcu_layer_t *layer = NULL;
                                int i;
 
+                               layer = NULL;
+                               used++;
+
                                switch_mutex_lock(conference->canvas->mutex);
                                
                                if (imember->video_layer_id > -1) {
                                        if (imember->video_layer_id >= conference->canvas->total_layers) {
                                                conference->canvas->layers[imember->video_layer_id].member_id = 0;
+                                               reset_layer(conference->canvas, &conference->canvas->layers[imember->video_layer_id]);
                                                imember->video_layer_id = -1;
                                                conference->canvas->layers_used--;
                                        } else {
@@ -1148,12 +1259,15 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                                        }
                                }
                                switch_mutex_unlock(conference->canvas->mutex);
+
                                
                                if (layer) {
-                                       scale_and_patch(conference->canvas->img, img, layer);
+                                       switch_img_free(&layer->cur_img);
+                                       layer->cur_img = img;
+                                       scale_and_patch(conference, layer);
                                }
 
-                               switch_img_free(&img);
+
                        }
 
                        if (imember->session) {
@@ -1161,39 +1275,53 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                        }
                }
 
-               for (imember = conference->members; imember; imember = imember->next) {
-                       switch_channel_t *ichannel = switch_core_session_get_channel(imember->session);
+               switch_mutex_unlock(conference->member_mutex);
 
-                       if (!imember->session || !switch_channel_test_flag(ichannel, CF_VIDEO) || 
-                               switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) {
-                               continue;
+               if (remaining) goto top;
+
+               if (used) {                     
+                       switch_time_t now = switch_micro_time_now();
+
+#ifdef TRACK_FPS
+                       uint64_t diff = ((now - started) / 1000000);
+
+                       if (!diff) diff = 1;
+                       frames++;
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "foo %ld %ld %ld\n", frames, diff, frames / diff);
+#endif
+
+                       if (video_key_freq && (now - last_key_time) > video_key_freq) {
+                               need_keyframe = SWITCH_TRUE;
+                               last_key_time = now;
                        }
 
-                       switch_set_flag(&write_frame, SFF_RAW_RTP);
-                       write_frame.img = conference->canvas->img;
-                       write_frame.packet = packet;
-                       write_frame.data = packet + 12;
-                       write_frame.datalen = SWITCH_RECOMMENDED_BUFFER_SIZE - 12;
-                       write_frame.buflen = write_frame.datalen;
-                       write_frame.packetlen = SWITCH_RECOMMENDED_BUFFER_SIZE;
 
-                       switch_core_session_write_video_frame(imember->session, &write_frame, SWITCH_IO_FLAG_NONE, 0);                  
+                       switch_core_timer_sync(&timer);
                        
-                       if (imember->session) {
-                               switch_core_session_rwunlock(imember->session);
+                       for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) {
+                               write_codecs[i]->frame.img = conference->canvas->img;
+                               write_canvas_image_to_codec_group(conference, write_codecs[i], i, timer.samplecount, need_refresh, need_keyframe);
                        }
                }
 
-               switch_mutex_unlock(conference->member_mutex);
-
                switch_mutex_lock(conference->canvas->cond2_mutex);
                switch_thread_cond_wait(conference->canvas->cond, conference->canvas->cond_mutex);
                switch_mutex_unlock(conference->canvas->cond2_mutex);
-               
        }
        
        switch_mutex_unlock(conference->canvas->cond_mutex);
 
+       for (i = 0; i < MCU_MAX_LAYERS; i++) {
+               layer = &conference->canvas->layers[i];
+               
+               switch_img_free(&layer->cur_img);
+               switch_img_free(&layer->img);
+       }
+
+       for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) {
+               switch_core_codec_destroy(&write_codecs[i]->codec);
+       }
+
        destroy_canvas(&conference->canvas);
 
        return NULL;
@@ -2862,6 +2990,8 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
        member->score_iir = 0;
        member->verbose_events = conference->verbose_events;
        member->video_layer_id = -1;
+       member->video_codec_index = -1;
+
        switch_queue_create(&member->dtmf_queue, 100, member->pool);
        if (conference->video_layout_name) {
                switch_queue_create(&member->video_queue, 2000, member->pool);
@@ -7288,8 +7418,10 @@ static switch_status_t conf_api_sub_vid_layout(conference_obj_t *conference, swi
                return SWITCH_STATUS_SUCCESS;
        }
 
-       reset_image(conference->canvas->img, &conference->canvas->bgcolor);
+       switch_mutex_lock(conference->member_mutex);
        init_canvas_layers(conference, lnode);
+       reset_image(conference->canvas->img, &conference->canvas->bgcolor);
+       switch_mutex_unlock(conference->member_mutex);
 
        return SWITCH_STATUS_SUCCESS;
 }
index 7be5edcad43bea1e63605ad98d9b9d5b1298d500..a807c4c777af42f997fd4636b45d755aef102f69 100644 (file)
@@ -7319,8 +7319,8 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
                                }
 
                                /* DFF nack pli etc */
-                               //nack = v_engine->nack = 0;
-                               //pli = v_engine->pli = 0;
+                               nack = v_engine->nack = 0;
+                               pli = v_engine->pli = 0;
                                
                                
                                for (pmap = v_engine->cur_payload_map; pmap && pmap->allocated; pmap = pmap->next) {
@@ -8130,7 +8130,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se
                        if (v_engine->rtp_session) {
                                if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PLI)) {
                                        switch_rtp_video_loss(v_engine->rtp_session);
-                               } else if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_FIR)) {
+                               }
+
+                               if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_FIR)) {
                                        switch_rtp_video_refresh(v_engine->rtp_session);
                                }
                        }
@@ -9744,6 +9746,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_sess
 
                        smh->last_codec_refresh = now;
                }
+
+               switch_channel_set_flag(session->channel, CF_VIDEO_REFRESH_REQ);
                return switch_core_codec_control(codec, cmd, ctype, cmd_data, rtype, ret_data);
        }
 
@@ -9751,7 +9755,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_sess
 }
 
 
-static switch_status_t raw_write_video(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id) 
+SWITCH_DECLARE(switch_status_t) switch_core_session_write_encoded_video_frame(switch_core_session_t *session, 
+                                                                                                                                               switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
 {
        switch_io_event_hook_video_write_frame_t *ptr;
        switch_status_t status = SWITCH_STATUS_FALSE;
@@ -9835,7 +9840,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
        }       
 
        if (!img) {
-               return raw_write_video(session, frame, flags, stream_id);
+               return switch_core_session_write_encoded_video_frame(session, frame, flags, stream_id);
        }
 
        write_frame = *frame;
@@ -9849,7 +9854,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
                        if (!smh->video_timer.timer_interface) {
                                switch_core_timer_init(&smh->video_timer, "soft", 1, 90, switch_core_session_get_pool(session));
                        }
-                       
+                       switch_core_timer_sync(&smh->video_timer);
                        timer = &smh->video_timer;
                }
 
@@ -9873,7 +9878,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
                        }
                        
                        switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME);
-                       status = raw_write_video(session, frame, flags, stream_id);
+                       status = switch_core_session_write_encoded_video_frame(session, frame, flags, stream_id);
                }
                
        } while(status == SWITCH_STATUS_SUCCESS && encode_status == SWITCH_STATUS_MORE_DATA);
index d4ffe5120fae2e8b6caedefbf68a34a7b8c59984..2e90ae73a3becf9af90c4fa892de442248ce02f3 100644 (file)
@@ -72,9 +72,41 @@ SWITCH_DECLARE(void) switch_img_free(switch_image_t **img)
        }
 }
 
+// simple implementation to patch a small img to a big IMG at position x,y
+SWITCH_DECLARE(void) switch_img_patch(switch_image_t *IMG, switch_image_t *img, int x, int y)
+{
+       int i, j, k;
+       int W = IMG->d_w;
+       int H = IMG->d_h;
+       int w = img->d_w;
+       int h = img->d_h;
+
+       switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
+       switch_assert(IMG->fmt == SWITCH_IMG_FMT_I420);
+
+       for (i = y; i < (y + h) && i < H; i++) {
+               for (j = x; j < (x + w) && j < W; j++) {
+                       IMG->planes[0][i * IMG->stride[0] + j] = img->planes[0][(i - y) * img->stride[0] + (j - x)];
+               }
+       }
+
+       for (i = y; i < (y + h) && i < H; i+=4) {
+               for (j = x; j < (x + w) && j < W; j+=4) {
+                       for (k = 1; k <= 2; k++) {
+                               IMG->planes[k][i/2 * IMG->stride[k] + j/2]         = img->planes[k][(i-y)/2 * img->stride[k] + (j-x)/2];
+                               IMG->planes[k][i/2 * IMG->stride[k] + j/2 + 1]     = img->planes[k][(i-y)/2 * img->stride[k] + (j-x)/2 + 1];
+                               IMG->planes[k][(i+2)/2 * IMG->stride[k] + j/2]     = img->planes[k][(i+2-y)/2 * img->stride[k] + (j-x)/2];
+                               IMG->planes[k][(i+2)/2 * IMG->stride[k] + j/2 + 1] = img->planes[k][(i+2-y)/2 * img->stride[k] + (j-x)/2 + 1];
+                       }
+               }
+       }
+}
+
+
+
 SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_img)
 {
-       int i;
+       int i = 0;
 
        switch_assert(img);
        switch_assert(new_img);
@@ -101,6 +133,7 @@ SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_i
                memcpy((*new_img)->planes[SWITCH_PLANE_U] + (*new_img)->stride[SWITCH_PLANE_U] * i, img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * i, img->d_w / 2);
                memcpy((*new_img)->planes[SWITCH_PLANE_V] + (*new_img)->stride[SWITCH_PLANE_V] * i, img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * i, img->d_w /2);
        }
+
 }
 
 /* For Emacs:
index 471d84b6c0a29cbe5df8038d6e9415128fa778ae..b9db435eae7d05bd1c8808e1370bb322e74cc39d 100644 (file)
@@ -5242,6 +5242,7 @@ static void handle_nack(switch_rtp_t *rtp_session, uint32_t nack)
        switch_size_t bytes = 0;
        rtp_msg_t send_msg[1] = {{{0}}};
        uint16_t seq = (uint16_t) (nack & 0xFFFF);
+       uint16_t blp = (uint16_t) (nack >> 16);
        int i;
        const char *tx_host = NULL;
        const char *old_host = NULL;
@@ -5278,10 +5279,11 @@ static void handle_nack(switch_rtp_t *rtp_session, uint32_t nack)
                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG, "Cannot send NACK for seq %u\n", ntohs(seq));
        }
 
+       blp = ntohs(blp);
        for (i = 0; i < 16; i++) {
-               if ((nack & (1 << (16 + i)))) {
-                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG, "Also Got NACK for seq %u\n", ntohs(seq) + i);
-                       if (switch_vb_get_packet_by_seq(rtp_session->vbw, htons(ntohs(seq) + i), (switch_rtp_packet_t *) &send_msg, &bytes) == SWITCH_STATUS_SUCCESS) {
+               if (blp & (1 << i)) {
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG, "Also Got NACK for seq %u\n", ntohs(seq) + i + 1);
+                       if (switch_vb_get_packet_by_seq(rtp_session->vbw, htons(ntohs(seq) + i + 1), (switch_rtp_packet_t *) &send_msg, &bytes) == SWITCH_STATUS_SUCCESS) {
                                if (rtp_session->flags[SWITCH_RTP_FLAG_DEBUG_RTP_WRITE]) {
                                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(rtp_session->session), SWITCH_LOG_CONSOLE,
                                                                          "X %s b=%4ld %s:%u %s:%u %s:%u pt=%d ts=%u seq=%u m=%d\n",
index 1c6ffb86eb5e3ab9c86d109355166e0dc4d887cf..9553ded9abd276631dc5d586711ec4b7d07d057a 100644 (file)
@@ -383,6 +383,7 @@ SWITCH_DECLARE(uint32_t) switch_vb_pop_nack(switch_vb_t *vb)
 {
        switch_hash_index_t *hi = NULL;
        uint32_t nack = 0;
+       uint16_t blp = 0;
        uint16_t least = 0;
        int i = 0;
 
@@ -405,15 +406,18 @@ SWITCH_DECLARE(uint32_t) switch_vb_pop_nack(switch_vb_t *vb)
        if (least && switch_core_inthash_delete(vb->missing_seq_hash, (uint32_t)htons(least))) {
                vb_debug(vb, 3, "Found smallest NACKABLE seq %u\n", least);
                nack = (uint32_t) htons(least);
-       
-               for (i = 1; i > 17; i++) {
+               
+               for(i = 0; i < 16; i++) {
                        if (switch_core_inthash_delete(vb->missing_seq_hash, (uint32_t)htons(least + i))) {
-                               vb_debug(vb, 3, "Found addtl NACKABLE seq %u\n", least + i);
-                               nack |= (1 << (16 + i));
+                               vb_debug(vb, 3, "Found addtl NACKABLE seq %u\n", least + i + 1);
+                               blp |= (1 << i);
                        } else {
                                break;
                        }
                }
+
+               blp = htons(blp);
+               nack |= (uint32_t) blp << 16;
        }
        
        switch_mutex_unlock(vb->mutex);