diff --git a/daemon/src/video/video_encoder.cpp b/daemon/src/video/video_encoder.cpp
index 76a27c4370636748b565c2397b386543e94e4ec3..80fb338623c58c2334302d172d666455dd9d6173 100644
--- a/daemon/src/video/video_encoder.cpp
+++ b/daemon/src/video/video_encoder.cpp
@@ -221,10 +221,13 @@ void print_averror(const char *funcname, int err)
 
 int VideoEncoder::encode(VideoFrame &input, bool is_keyframe, int64_t frame_number)
 {
-    int ret;
-    AVFrame *frame = scaledFrame_.get();
+    /* Prepare a frame suitable to our encoder frame format,
+     * keeping also the input aspect ratio.
+     */
+    scaledFrame_.clear(); // to fill blank space left by the "keep aspect"
+    scaler_.scale_with_aspect(input, scaledFrame_);
 
-    scaler_.scale(input, scaledFrame_);
+    AVFrame *frame = scaledFrame_.get();
     frame->pts = frame_number;
 
     if (is_keyframe) {
@@ -245,7 +248,7 @@ int VideoEncoder::encode(VideoFrame &input, bool is_keyframe, int64_t frame_numb
 #if LIBAVCODEC_VERSION_MAJOR >= 54
 
     int got_packet;
-    ret = avcodec_encode_video2(encoderCtx_, &pkt, frame, &got_packet);
+    int ret = avcodec_encode_video2(encoderCtx_, &pkt, frame, &got_packet);
     if (ret < 0) {
         print_averror("avcodec_encode_video2", ret);
         av_free_packet(&pkt);
diff --git a/daemon/src/video/video_mixer.cpp b/daemon/src/video/video_mixer.cpp
index c5202a63bfc0a3031df92bd93c0dd38fb7b61d8d..d926382e271f47b243199ba7658ba4a9d37c3fd9 100644
--- a/daemon/src/video/video_mixer.cpp
+++ b/daemon/src/video/video_mixer.cpp
@@ -163,19 +163,7 @@ void VideoMixer::render_frame(VideoFrame& output, const VideoFrame& input,
     int xoff = (index % zoom) * cell_width;
     int yoff = (index / zoom) * cell_height;
 
-    /* Corrections to respect input frame ratio */
-    const float local_ratio = width_ / height_;
-    const float input_ratio = input.getWidth() / input.getHeight();
-    if (local_ratio >= input_ratio) {
-        xoff += (cell_width * (1. - input_ratio)) / 2;
-        cell_width *= input_ratio;
-    } else {
-        const int fixed_height = cell_width / input_ratio;
-        yoff += (cell_height - fixed_height) / 2;
-        cell_height = fixed_height;
-    }
-
-    scaler_.scale_and_pad(input, output, xoff, yoff, cell_width, cell_height);
+    scaler_.scale_and_pad(input, output, xoff, yoff, cell_width, cell_height, true);
 }
 
 void VideoMixer::setDimensions(int width, int height)
diff --git a/daemon/src/video/video_scaler.cpp b/daemon/src/video/video_scaler.cpp
index 5cb92203498ed9056e5a4e1d0e94a960ff43b57a..16f60864fab6455430326efdbf7d3379b84a0fe8 100644
--- a/daemon/src/video/video_scaler.cpp
+++ b/daemon/src/video/video_scaler.cpp
@@ -33,6 +33,8 @@
 #include "video_scaler.h"
 #include "logger.h"
 
+#include <cassert>
+
 namespace sfl_video {
 
 VideoScaler::VideoScaler() : ctx_(0), mode_(SWS_FAST_BILINEAR) {}
@@ -59,28 +61,62 @@ void VideoScaler::scale(const VideoFrame &input, VideoFrame &output)
     }
 
     sws_scale(ctx_, input_frame->data, input_frame->linesize, 0,
-              input_frame->height, output_frame->data, output_frame->linesize);
+              input_frame->height, output_frame->data,
+              output_frame->linesize);
+}
+
+void VideoScaler::scale_with_aspect(const VideoFrame &input, VideoFrame &output)
+{
+    AVFrame *output_frame = output.get();
+    scale_and_pad(input, output, 0, 0, output_frame->width,
+                  output_frame->height, true);
+}
+
+static inline bool is_yuv_planar(const AVPixFmtDescriptor *desc)
+{
+    unsigned used_bit_mask = (1u << desc->nb_components) - 1;
+
+    if (not (desc->flags & PIX_FMT_PLANAR)
+        or desc->flags & PIX_FMT_RGB)
+        return false;
+
+    /* handle formats that do not use all planes */
+    for (unsigned i = 0; i < desc->nb_components; ++i)
+        used_bit_mask &= ~(1u << desc->comp[i].plane);
+
+    return not used_bit_mask;
 }
 
 void VideoScaler::scale_and_pad(const VideoFrame &input, VideoFrame &output,
                                 unsigned xoff, unsigned yoff,
-                                unsigned dest_width, unsigned dest_height)
+                                unsigned dest_width, unsigned dest_height,
+                                bool keep_aspect)
 {
     const AVFrame *input_frame = input.get();
     AVFrame *output_frame = output.get();
-    uint8_t *data[AV_NUM_DATA_POINTERS];
 
-    for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) {
-        if (output_frame->data[i]) {
-            const unsigned divisor = i == 0 ? 1 : 2;
-            unsigned offset = (yoff * output_frame->linesize[i] + xoff) / divisor;
-            data[i] = output_frame->data[i] + offset;
+    /* Correct destination width/height and offset if we need to keep input
+     * frame aspect.
+     */
+    if (keep_aspect) {
+        const float local_ratio = (float)dest_width / dest_height;
+        const float input_ratio = (float)input_frame->width / input_frame->height;
+
+        if (local_ratio > input_ratio) {
+            auto old_dest_width = dest_width;
+            dest_width = dest_height * input_ratio;
+            xoff += (old_dest_width - dest_width) / 2;
         } else {
-            data[i] = 0;
-            break;
+            auto old_dest_heigth = dest_height;
+            dest_height = dest_width / input_ratio;
+            yoff += (old_dest_heigth - dest_height) / 2;
         }
     }
 
+    // buffer overflow checks
+    assert(xoff + dest_width <= (unsigned)output_frame->width);
+    assert(yoff + dest_height <= (unsigned)output_frame->height);
+
     ctx_ = sws_getCachedContext(ctx_,
                                 input_frame->width,
                                 input_frame->height,
@@ -95,8 +131,23 @@ void VideoScaler::scale_and_pad(const VideoFrame &input, VideoFrame &output,
         return;
     }
 
+    // Make an offset'ed copy of output data from xoff and yoff
+    const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get((AVPixelFormat)output_frame->format);
+    if (is_yuv_planar(out_desc)) {
+        unsigned x_shift = out_desc->log2_chroma_w;
+        unsigned y_shift = out_desc->log2_chroma_h;
+
+        tmp_data_[0] = output_frame->data[0] + yoff * output_frame->linesize[0] + xoff;
+        tmp_data_[1] = output_frame->data[1] + (yoff >> y_shift) * output_frame->linesize[1] + (xoff >> x_shift);
+        tmp_data_[2] = output_frame->data[2] + (yoff >> y_shift) * output_frame->linesize[2] + (xoff >> x_shift);
+        tmp_data_[3] = nullptr;
+    } else {
+        memcpy(tmp_data_, output_frame->data, sizeof(tmp_data_));
+        tmp_data_[0] += yoff * output_frame->linesize[0] + xoff;
+    }
+
     sws_scale(ctx_, input_frame->data, input_frame->linesize, 0,
-              input_frame->height, data, output_frame->linesize);
+              input_frame->height, tmp_data_, output_frame->linesize);
 }
 
 void VideoScaler::reset()
diff --git a/daemon/src/video/video_scaler.h b/daemon/src/video/video_scaler.h
index cde1c4e0a2faa7371ec357f492b9393e6e3e74e2..8ff7cca192523b6b088d5a72b1e2d7fd67bd6109 100644
--- a/daemon/src/video/video_scaler.h
+++ b/daemon/src/video/video_scaler.h
@@ -44,16 +44,19 @@ class VideoScaler {
 public:
     VideoScaler();
     ~VideoScaler();
-    void scale(const VideoFrame &input, VideoFrame &output);
     void reset();
+    void scale(const VideoFrame &input, VideoFrame &output);
+    void scale_with_aspect(const VideoFrame &input, VideoFrame &output);
     void scale_and_pad(const VideoFrame &input, VideoFrame &output,
                        unsigned xoff, unsigned yoff,
-                       unsigned dest_width, unsigned dest_height);
+                       unsigned dest_width, unsigned dest_height,
+                       bool keep_aspect);
 
 private:
     NON_COPYABLE(VideoScaler);
     SwsContext *ctx_;
     int mode_;
+    uint8_t *tmp_data_[4]; // used by scale_and_pad
 };
 
 }