You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by mj...@apache.org on 2016/03/20 03:24:37 UTC

[07/50] incubator-guacamole-server git commit: GUAC-236: Maintain aspect ratio by adding letterboxes / pillarboxes as necessary.

GUAC-236: Maintain aspect ratio by adding letterboxes / pillarboxes as necessary.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/commit/8ed0cd5f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/tree/8ed0cd5f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/diff/8ed0cd5f

Branch: refs/heads/master
Commit: 8ed0cd5f16fdeec3c9d841801ad04c3b45aa7c0d
Parents: 2798536
Author: Michael Jumper <mi...@guac-dev.org>
Authored: Sat Mar 12 21:46:45 2016 -0800
Committer: Michael Jumper <mi...@guac-dev.org>
Committed: Mon Mar 14 20:22:04 2016 -0700

----------------------------------------------------------------------
 src/guacenc/video.c | 101 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 88 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-server/blob/8ed0cd5f/src/guacenc/video.c
----------------------------------------------------------------------
diff --git a/src/guacenc/video.c b/src/guacenc/video.c
index 7c6c0c2..fbf02e0 100644
--- a/src/guacenc/video.c
+++ b/src/guacenc/video.c
@@ -255,18 +255,39 @@ int guacenc_video_advance_timeline(guacenc_video* video,
 
 /**
  * Converts the given Guacamole video encoder buffer to a frame in the format
- * required by libavcodec / libswscale. No scaling is performed; the image data
- * is copied verbatim.
+ * required by libavcodec / libswscale. Black margins of the specified sizes
+ * will be added. No scaling is performed; the image data is copied verbatim.
  *
  * @param buffer
  *     The guacenc_buffer to copy as a new AVFrame.
  *
+ * @param lsize
+ *     The size of the letterboxes to add, in pixels. Letterboxes are the
+ *     horizontal black boxes added to images which are scaled down to fit the
+ *     destination because they are too wide (the width is scaled to exactly
+ *     fit the destination, resulting in extra space at the top and bottom).
+ *
+ * @param psize
+ *     The size of the pillarboxes to add, in pixels. Pillarboxes are the
+ *     vertical black boxes added to images which are scaled down to fit the
+ *     destination because they are too tall (the height is scaled to exactly
+ *     fit the destination, resulting in extra space on the sides).
+ *
  * @return
  *     A pointer to a newly-allocated AVFrame containing exactly the same image
  *     data as the given buffer. The image data within the frame and the frame
  *     itself must be manually freed later.
  */
-static AVFrame* guacenc_video_frame_convert(guacenc_buffer* buffer) {
+static AVFrame* guacenc_video_frame_convert(guacenc_buffer* buffer, int lsize,
+        int psize) {
+
+    /* Init size of left/right pillarboxes */
+    int left = psize;
+    int right = psize;
+
+    /* Init size of top/bottom letterboxes */
+    int top = lsize;
+    int bottom = lsize;
 
     /* Prepare source frame for buffer */
     AVFrame* frame = av_frame_alloc();
@@ -275,8 +296,8 @@ static AVFrame* guacenc_video_frame_convert(guacenc_buffer* buffer) {
 
     /* Copy buffer properties to frame */
     frame->format = AV_PIX_FMT_RGB32;
-    frame->width = buffer->width;
-    frame->height = buffer->height;
+    frame->width = buffer->width + left + right;
+    frame->height = buffer->height + top + bottom;
 
     /* Allocate actual backing data for frame */
     if (av_image_alloc(frame->data, frame->linesize, frame->width,
@@ -300,16 +321,46 @@ static AVFrame* guacenc_video_frame_convert(guacenc_buffer* buffer) {
     int width = buffer->width;
     int height = buffer->height;
 
-    /* Source buffer and destination frame dimensions are identical */
-    assert(width == frame->width);
-    assert(height == frame->height);
+    /* Source buffer is guaranteed to fit within destination buffer */
+    assert(width <= frame->width);
+    assert(height <= frame->height);
+
+    /* Add top margin */
+    while (top > 0) {
+        memset(dst_data, 0, frame->width * 4);
+        dst_data += dst_stride;
+        top--;
+    }
 
     /* Copy all data from source buffer to destination frame */
     while (height > 0) {
-        memcpy(dst_data, src_data, width * 4);
+
+        /* Calculate size of margin and data regions */
+        int left_size = left * 4;
+        int data_size = width * 4;
+        int right_size = right * 4;
+
+        /* Add left margin */
+        memset(dst_data, 0, left_size);
+
+        /* Copy data */
+        memcpy(dst_data + left_size, src_data, data_size);
+
+        /* Add right margin */
+        memset(dst_data + left_size + data_size, 0, right_size);
+
         dst_data += dst_stride;
         src_data += src_stride;
+
         height--;
+
+    }
+
+    /* Add bottom margin */
+    while (bottom > 0) {
+        memset(dst_data, 0, frame->width * 4);
+        dst_data += dst_stride;
+        bottom--;
     }
 
     /* Frame converted */
@@ -319,21 +370,45 @@ static AVFrame* guacenc_video_frame_convert(guacenc_buffer* buffer) {
 
 void guacenc_video_prepare_frame(guacenc_video* video, guacenc_buffer* buffer) {
 
+    int lsize;
+    int psize;
+
     /* Ignore NULL buffers */
     if (buffer == NULL || buffer->surface == NULL)
         return;
 
+    /* Obtain destination frame */
+    AVFrame* dst = video->next_frame;
+
+    /* Determine width of image if height is scaled to match destination */
+    int scaled_width = buffer->width * dst->height / buffer->height;
+
+    /* Determine height of image if width is scaled to match destination */
+    int scaled_height = buffer->height * dst->width / buffer->width;
+
+    /* If height-based scaling results in a fit width, add pillarboxes */
+    if (scaled_width <= dst->width) {
+        lsize = 0;
+        psize = (dst->width - scaled_width)
+               * buffer->height / dst->height / 2;
+    }
+
+    /* If width-based scaling results in a fit width, add letterboxes */
+    else {
+        assert(scaled_height <= dst->height);
+        psize = 0;
+        lsize = (dst->height - scaled_height)
+               * buffer->width / dst->width / 2;
+    }
+
     /* Prepare source frame for buffer */
-    AVFrame* src = guacenc_video_frame_convert(buffer);
+    AVFrame* src = guacenc_video_frame_convert(buffer, lsize, psize);
     if (src == NULL) {
         guacenc_log(GUAC_LOG_WARNING, "Failed to allocate source frame. "
                 "Frame dropped.");
         return;
     }
 
-    /* Obtain destination frame */
-    AVFrame* dst = video->next_frame;
-
     /* Prepare scaling context */
     struct SwsContext* sws = sws_getContext(src->width, src->height,
             PIX_FMT_RGB32, dst->width, dst->height, PIX_FMT_YUV420P,