[Spice-commits] 2 commits - client/display_channel.cpp client/mjpeg_decoder.cpp common/linux common/win configure.ac server/Makefile.am server/mjpeg_encoder.c server/mjpeg_encoder.h server/red_worker.c server/red_yuv.h

Alexander Larsson alexl at kemper.freedesktop.org
Thu Apr 8 08:10:33 PDT 2010


 client/display_channel.cpp   |    1 
 client/mjpeg_decoder.cpp     |   15 +
 common/linux/ffmpeg_inc.h.in |   12 -
 common/win/ffmpeg_inc.h      |    4 
 configure.ac                 |   14 -
 server/Makefile.am           |    7 
 server/mjpeg_encoder.c       |  125 ++++++++++++++
 server/mjpeg_encoder.h       |   35 ++++
 server/red_worker.c          |  376 +++++++++++++++++++++----------------------
 server/red_yuv.h             |  159 ------------------
 10 files changed, 359 insertions(+), 389 deletions(-)

New commits:
commit de4306af331f5a68c28949c5cfed60adea24f753
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Apr 8 17:09:32 2010 +0200

    Initialize _kill_mark so we don't get spurious valgrind warnings

diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 6427ae4..9219568 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -264,6 +264,7 @@ VideoStream::VideoStream(RedClient& client, Canvas& canvas, DisplayChannel& chan
     , _clip (NULL)
     , _frames_head (0)
     , _frames_tail (0)
+    , _kill_mark (0)
     , _uncompressed_data (NULL)
     , _update_mark (0)
     , _update_time (0)
diff --git a/client/mjpeg_decoder.cpp b/client/mjpeg_decoder.cpp
index df0dbad..cf3e44d 100644
--- a/client/mjpeg_decoder.cpp
+++ b/client/mjpeg_decoder.cpp
@@ -113,13 +113,15 @@ void MJpegDecoder::convert_scanline(void)
 
    row = (uint32_t *)(_frame + _y * _stride);
     s = _scanline;
+
+    /* TODO after major bump.
+       We need to check for the old major and for backwards compat
+       a) swap r and b
+       b) to-yuv with right values and then from-yuv with old wrong values
+    */
+
     for (x = 0; x < _width; x++) {
-        /* This switches the order of red and blue.
-           This is not accidental, but for backwards
-           compatibility, since a bug in the old
-           ffmpeg-using mjpeg code got these switched
-           due to endianness issues. */
-        c = s[0] | s[1] << 8 | s[2] << 16;
+        c = s[0] << 16 | s[1] << 8 | s[2];
         s += 3;
         *row++ = c;
     }
diff --git a/common/linux/ffmpeg_inc.h.in b/common/linux/ffmpeg_inc.h.in
deleted file mode 100644
index 7e322b5..0000000
--- a/common/linux/ffmpeg_inc.h.in
+++ /dev/null
@@ -1,12 +0,0 @@
-
-#ifdef __GNUG__
-extern "C" {
-#endif
-
-#include  "@AVCODEC_PREFIX at avcodec.h"
-
-#ifdef __GNUG__
-}
-#endif
-
-
diff --git a/common/win/ffmpeg_inc.h b/common/win/ffmpeg_inc.h
deleted file mode 100644
index 8d4473f..0000000
--- a/common/win/ffmpeg_inc.h
+++ /dev/null
@@ -1,4 +0,0 @@
-
-extern "C" {
-#include "libavcodec/avcodec.h"
-}
diff --git a/configure.ac b/configure.ac
index c75a16d..e1f0c8e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -144,19 +144,6 @@ AC_SUBST(CELT051_LIBS)
 AC_SUBST(CELT051_LIBDIR)
 SPICE_REQUIRES+=" celt051 >= 0.5.1.1"
 
-PKG_CHECK_MODULES(FFMPEG, libavcodec libavutil)
-AC_SUBST(FFMPEG_CFLAGS)
-AC_SUBST(FFMPEG_LIBS)
-FFMPEG_LIBDIR=`pkg-config --variable=libdir libavutil`
-AC_SUBST(FFMPEG_LIBDIR)
-SPICE_REQUIRES+=" libavcodec libavutil"
-
-saved_CPPFLAGS="$CPPFLAGS"
-CPPFLAGS="$CPPFLAGS $FFMPEG_CFLAGS"
-AC_CHECK_HEADER(avcodec.h, AVCODEC_PREFIX="", AVCODEC_PREFIX="libavcodec/")
-CPPFLAGS="$saved_CPPFLAGS"
-AC_SUBST([AVCODEC_PREFIX])
-
 PKG_CHECK_MODULES(ALSA, alsa)
 AC_SUBST(ALSA_CFLAGS)
 AC_SUBST(ALSA_LIBS)
@@ -349,7 +336,6 @@ AC_OUTPUT([
 Makefile
 spice-server.pc
 common/Makefile
-common/linux/ffmpeg_inc.h
 server/Makefile
 client/Makefile
 client/x11/Makefile
diff --git a/server/Makefile.am b/server/Makefile.am
index d09e2d2..5c4524a 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -5,7 +5,7 @@ INCLUDES = \
 	-I$(top_srcdir)/common			\
 	-I$(top_srcdir)/common/linux	\
 	$(PROTOCOL_CFLAGS)			\
-	$(FFMPEG_CFLAGS)			\
+	$(JPEG_CFLAGS)				\
 	$(PIXMAN_CFLAGS)			\
 	$(GL_CFLAGS)				\
 	$(LOG4CPP_CFLAGS)			\
@@ -42,7 +42,7 @@ libspice_server_la_LDFLAGS =			\
 
 libspice_server_la_LIBADD = 			\
 	$(GL_LIBS)				\
-	$(FFMPEG_LIBS)				\
+	$(JPEG_LIBS)				\
 	$(PIXMAN_LIBS)				\
 	$(SSL_LIBS)				\
 	$(CELT051_LIBS)				\
@@ -66,6 +66,8 @@ libspice_server_la_SOURCES =			\
 	glz_encoder_dictionary.h		\
 	glz_encoder_dictionary_protected.h	\
 	glz_encoder.h				\
+	mjpeg_encoder.h				\
+	mjpeg_encoder.c				\
 	red_bitmap_utils.h			\
 	red_client_cache.h			\
 	red_client_shared_cache.h		\
@@ -77,7 +79,6 @@ libspice_server_la_SOURCES =			\
 	stat.h					\
 	red_worker.c				\
 	red_worker.h				\
-	red_yuv.h				\
 	snd_worker.c				\
 	snd_worker.h				\
 	red_channel.h				\
diff --git a/server/mjpeg_encoder.c b/server/mjpeg_encoder.c
new file mode 100644
index 0000000..b0ae49f
--- /dev/null
+++ b/server/mjpeg_encoder.c
@@ -0,0 +1,125 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "red_common.h"
+#include "mjpeg_encoder.h"
+#include <jpeglib.h>
+
+struct MJpegEncoder {
+    int width;
+    int height;
+    int stride;
+    uint8_t *frame;
+    int first_frame;
+    int quality;
+
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+};
+
+MJpegEncoder *mjpeg_encoder_new(int width, int height)
+{
+    MJpegEncoder *enc;
+
+    enc = spice_new0(MJpegEncoder, 1);
+
+    enc->first_frame = TRUE;
+    enc->width = width;
+    enc->height = height;
+    enc->stride = width * 3;
+    enc->quality = 70;
+    if (enc->stride < width) {
+        abort();
+    }
+    enc->frame = spice_malloc_n(enc->stride, height);
+
+    enc->cinfo.err = jpeg_std_error(&enc->jerr);
+
+    jpeg_create_compress(&enc->cinfo);
+
+    return enc;
+}
+
+void mjpeg_encoder_destroy(MJpegEncoder *encoder)
+{
+    jpeg_destroy_compress(&encoder->cinfo);
+    free(encoder->frame);
+    free(encoder);
+}
+
+uint8_t *mjpeg_encoder_get_frame(MJpegEncoder *encoder)
+{
+    return encoder->frame;
+}
+size_t mjpeg_encoder_get_frame_stride(MJpegEncoder *encoder)
+{
+    return encoder->stride;
+}
+
+void init_destination(j_compress_ptr cinfo)
+{
+}
+
+boolean empty_output_buffer(j_compress_ptr cinfo)
+{
+    return FALSE;
+}
+
+void term_destination(j_compress_ptr cinfo)
+{
+}
+
+int mjpeg_encoder_encode_frame(MJpegEncoder *encoder,
+                               uint8_t *buffer, size_t buffer_len)
+{
+    struct jpeg_destination_mgr destmgr;
+    uint8_t *frame;
+    int n;
+
+    destmgr.next_output_byte = buffer;
+    destmgr.free_in_buffer = buffer_len;
+    destmgr.init_destination = init_destination;
+    destmgr.empty_output_buffer = empty_output_buffer;
+    destmgr.term_destination = term_destination;
+
+    encoder->cinfo.dest = &destmgr;
+
+    encoder->cinfo.image_width      = encoder->width;
+    encoder->cinfo.image_height     = encoder->height;
+    encoder->cinfo.input_components = 3;
+    encoder->cinfo.in_color_space   = JCS_RGB;
+
+    jpeg_set_defaults(&encoder->cinfo);
+    jpeg_set_quality(&encoder->cinfo, encoder->quality, TRUE);
+    jpeg_start_compress(&encoder->cinfo, encoder->first_frame);
+
+    frame = encoder->frame;
+    while (encoder->cinfo.next_scanline < encoder->cinfo.image_height) {
+        n = jpeg_write_scanlines(&encoder->cinfo, &frame, 1);
+        if (n == 0) { /* Not enough space */
+            jpeg_abort_compress(&encoder->cinfo);
+            return 0;
+        }
+        frame += encoder->stride;
+    }
+
+    jpeg_finish_compress(&encoder->cinfo);
+
+    encoder->first_frame = FALSE;
+    return destmgr.next_output_byte - buffer;
+}
diff --git a/server/mjpeg_encoder.h b/server/mjpeg_encoder.h
new file mode 100644
index 0000000..4c966ab
--- /dev/null
+++ b/server/mjpeg_encoder.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_MJPEG_ENCODER
+#define _H_MJPEG_ENCODER
+
+#include "red_common.h"
+
+typedef struct MJpegEncoder MJpegEncoder;
+
+MJpegEncoder *mjpeg_encoder_new(int width, int height);
+void mjpeg_encoder_destroy(MJpegEncoder *encoder);
+
+uint8_t *mjpeg_encoder_get_frame(MJpegEncoder *encoder);
+size_t mjpeg_encoder_get_frame_stride(MJpegEncoder *encoder);
+int mjpeg_encoder_encode_frame(MJpegEncoder *encoder,
+                               uint8_t *buffer, size_t buffer_len);
+
+
+#endif
diff --git a/server/red_worker.c b/server/red_worker.c
index 723f542..6fdc4fe 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 /*
    Copyright (C) 2009 Red Hat, Inc.
 
@@ -38,7 +39,6 @@
 #include "cairo_canvas.h"
 #include "gl_canvas.h"
 #include "ogl_ctx.h"
-#include "ffmpeg_inc.h"
 #include "quic.h"
 #include "lz.h"
 #include "glz_encoder_dictionary.h"
@@ -46,6 +46,7 @@
 #include "stat.h"
 #include "reds.h"
 #include "ring.h"
+#include "mjpeg_encoder.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -412,13 +413,10 @@ struct Stream {
     int height;
     SpiceRect dest_area;
 #endif
+    MJpegEncoder *mjpeg_encoder;
     int top_down;
     Stream *next;
     RingItem link;
-    AVCodecContext *av_ctx;
-    AVFrame *av_frame;
-    uint8_t* frame_buf;
-    uint8_t* frame_buf_end;
     int bit_rate;
 };
 
@@ -1017,8 +1015,6 @@ typedef struct RedWorker {
     SpiceVirtMapping preload_group_virt_mapping;
 } RedWorker;
 
-pthread_mutex_t avcodec_lock = PTHREAD_MUTEX_INITIALIZER;
-
 static void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable);
 static void red_current_flush(RedWorker *worker, int surface_id);
 static void display_channel_push(RedWorker *worker);
@@ -2486,12 +2482,9 @@ static void red_release_stream(RedWorker *worker, Stream *stream)
 #else
         ring_remove(&stream->link);
 #endif
-        pthread_mutex_lock(&avcodec_lock);
-        avcodec_close(stream->av_ctx);
-        pthread_mutex_unlock(&avcodec_lock);
-        av_free(stream->av_ctx);
-        av_free(stream->av_frame);
-        free(stream->frame_buf);
+        if (stream->mjpeg_encoder) {
+            mjpeg_encoder_destroy(stream->mjpeg_encoder);
+        }
         red_free_stream(worker, stream);
     }
 }
@@ -2814,7 +2807,7 @@ static int get_bit_rate(int width, int height)
     return bit_rate;
 }
 
-static void red_dispaly_create_stream(DisplayChannel *display, Stream *stream)
+static void red_display_create_stream(DisplayChannel *display, Stream *stream)
 {
     StreamAgent *agent = &display->stream_agents[stream - display->base.worker->streams_buf];
     stream->refs++;
@@ -2831,54 +2824,12 @@ static void red_dispaly_create_stream(DisplayChannel *display, Stream *stream)
     red_pipe_add(&display->base, &agent->create_item);
 }
 
-static AVCodecContext *red_init_video_encoder(int width, int height)
-{
-    AVCodec *codec;
-    AVCodecContext *ctx;
-    int r;
-
-    codec = avcodec_find_encoder(CODEC_ID_MJPEG);
-
-    if (!codec) {
-        red_printf("codec not found");
-        return NULL;
-    }
-
-    if (!(ctx = avcodec_alloc_context())) {
-        red_printf("alloc ctx failed");
-        return NULL;
-    }
-    ctx->bit_rate = get_bit_rate(width, height);
-    ASSERT(width % 2 == 0);
-    ASSERT(height % 2 == 0);
-    ctx->width = width;
-    ctx->height = height;
-    ctx->time_base = (AVRational){1, MAX_FPS};
-    ctx->gop_size = 10;
-    ctx->max_b_frames = 0;
-    ctx->pix_fmt = PIX_FMT_YUVJ420P;
-
-    pthread_mutex_lock(&avcodec_lock);
-    r = avcodec_open(ctx, codec);
-    pthread_mutex_unlock(&avcodec_lock);
-    if (r < 0) {
-        red_printf("avcodec open failed");
-        av_free(ctx);
-        return NULL;
-    }
-    return ctx;
-}
-
 static void red_create_stream(RedWorker *worker, Drawable *drawable)
 {
-    AVCodecContext *av_ctx;
     Stream *stream;
-    AVFrame *frame;
-    uint8_t* frame_buf;
     SpiceRect* src_rect;
     int stream_width;
     int stream_height;
-    int pict_size;
 
     ASSERT(!drawable->stream);
 
@@ -2891,24 +2842,7 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
     stream_width = SPICE_ALIGN(src_rect->right - src_rect->left, 2);
     stream_height = SPICE_ALIGN(src_rect->bottom - src_rect->top, 2);
 
-    if (!(av_ctx = red_init_video_encoder(stream_width, stream_height))) {
-        goto error_1;
-    }
-
-    if (!(frame = avcodec_alloc_frame())) {
-        goto error_2;
-    }
-
-    if ((pict_size = avpicture_get_size(av_ctx->pix_fmt, stream_width, stream_height)) < 0) {
-        goto error_3;
-    }
-
-    frame_buf = spice_malloc(pict_size);
-
-    if (avpicture_fill((AVPicture *)frame, frame_buf, av_ctx->pix_fmt, stream_width,
-                       stream_height) < 0) {
-        goto error_4;
-    }
+    stream->mjpeg_encoder = mjpeg_encoder_new(stream_width, stream_height);
 
     ring_add(&worker->streams, &stream->link);
     stream->current = drawable;
@@ -2919,36 +2853,17 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
     stream->dest_area = drawable->qxl_drawable->bbox;
 #endif
     stream->refs = 1;
-    stream->av_ctx = av_ctx;
-    stream->bit_rate = av_ctx->bit_rate;
-    stream->av_frame = frame;
-    stream->frame_buf = frame_buf;
-    stream->frame_buf_end = frame_buf + pict_size;
+    stream->bit_rate = get_bit_rate(stream_width, stream_height);
     QXLImage *qxl_image = (QXLImage *)get_virt(worker, drawable->qxl_drawable->u.copy.src_bitmap,
                                                sizeof(QXLImage), drawable->group_id);
     stream->top_down = !!(qxl_image->bitmap.flags & SPICE_BITMAP_FLAGS_TOP_DOWN);
     drawable->stream = stream;
 
     if (worker->display_channel) {
-        red_dispaly_create_stream(worker->display_channel, stream);
+        red_display_create_stream(worker->display_channel, stream);
     }
 
     return;
-
-error_4:
-    free(frame_buf);
-
-error_3:
-    av_free(frame);
-
-error_2:
-    pthread_mutex_lock(&avcodec_lock);
-    avcodec_close(av_ctx);
-    pthread_mutex_unlock(&avcodec_lock);
-    av_free(av_ctx);
-
-error_1:
-    red_free_stream(worker, stream);
 }
 
 static void red_disply_start_streams(DisplayChannel *display_channel)
@@ -2958,7 +2873,7 @@ static void red_disply_start_streams(DisplayChannel *display_channel)
 
     while ((item = ring_next(ring, item))) {
         Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
-        red_dispaly_create_stream(display_channel, stream);
+        red_display_create_stream(display_channel, stream);
     }
 }
 
@@ -3100,7 +3015,6 @@ static inline int red_is_next_stream_frame(RedWorker *worker, Drawable *candidat
 static void reset_rate(StreamAgent *stream_agent)
 {
     Stream *stream = stream_agent->stream;
-    AVCodecContext *new_ctx;
     int rate;
 
     rate = get_bit_rate(stream->width, stream->height);
@@ -3108,19 +3022,7 @@ static void reset_rate(StreamAgent *stream_agent)
         return;
     }
 
-    int stream_width = SPICE_ALIGN(stream->width, 2);
-    int stream_height = SPICE_ALIGN(stream->height, 2);
-
-    new_ctx = red_init_video_encoder(stream_width, stream_height);
-    if (!new_ctx) {
-        red_printf("craete ctx failed");
-        return;
-    }
-
-    avcodec_close(stream->av_ctx);
-    av_free(stream->av_ctx);
-    stream->av_ctx = new_ctx;
-    stream->bit_rate = rate;
+    /* MJpeg has no rate limiting anyway, so do nothing */
 }
 
 static inline void pre_stream_item_swap(RedWorker *worker, Stream *stream)
@@ -7058,17 +6960,148 @@ static void red_display_unshare_stream_buf(DisplayChannel *display_channel)
 {
 }
 
-#define YUV32
-#include "red_yuv.h"
-#undef YUV32
+static int red_rgb32bpp_to_24 (RedWorker *worker, const SpiceRect *src,
+                               const SpiceBitmap *image,
+                               uint8_t *frame, size_t frame_stride,
+                               long phys_delta, int memslot_id, int id,
+                               Stream *stream, uint32_t group_id)
+{
+    QXLDataChunk *chunk;
+    uint32_t image_stride;
+    uint8_t *frame_row;
+    int offset;
+    int i, x;
+
+    offset = 0;
+    chunk = (QXLDataChunk *)(image->data + phys_delta);
+    image_stride = image->stride;
+
+    const int skip_lines = stream->top_down ? src->top : image->y - (src->bottom - 0);
+    for (i = 0; i < skip_lines; i++) {
+        red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, memslot_id,
+                           group_id);
+    }
+
+    const int image_height = src->bottom - src->top;
+    const int image_width = src->right - src->left;
+    for (i = 0; i < image_height; i++) {
+        uint32_t *src_line =
+            (uint32_t *)red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta,
+                                           memslot_id, group_id);
+
+        if (!src_line) {
+            return FALSE;
+        }
+
+        src_line += src->left;
+
+        frame_row = frame;
+        for (x = 0; x < image_width; x++) {
+            uint32_t pixel = *src_line++;
+            *frame_row++ = (pixel >> 16) & 0xff;
+            *frame_row++ = (pixel >>  8) & 0xff;
+            *frame_row++ = (pixel >>  0) & 0xff;
+        }
+
+        frame += frame_stride;
+    }
 
-#define YUV24
-#include "red_yuv.h"
-#undef YUV24
+    return TRUE;
+}
 
-#define YUV16
-#include "red_yuv.h"
-#undef YUV16
+static int red_rgb24bpp_to_24 (RedWorker *worker, const SpiceRect *src,
+                               const SpiceBitmap *image,
+                               uint8_t *frame, size_t frame_stride,
+                               long phys_delta, int memslot_id, int id,
+                               Stream *stream, uint32_t group_id)
+{
+    QXLDataChunk *chunk;
+    uint32_t image_stride;
+    uint8_t *frame_row;
+    int offset;
+    int i;
+
+    offset = 0;
+    chunk = (QXLDataChunk *)(image->data + phys_delta);
+    image_stride = image->stride;
+
+    const int skip_lines = stream->top_down ? src->top : image->y - (src->bottom - 0);
+    for (i = 0; i < skip_lines; i++) {
+        red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, memslot_id,
+                           group_id);
+    }
+
+    const int image_height = src->bottom - src->top;
+    const int image_width = src->right - src->left;
+    for (i = 0; i < image_height; i++) {
+        uint8_t *src_line =
+            (uint8_t *)red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta,
+                                           memslot_id, group_id);
+
+        if (!src_line) {
+            return FALSE;
+        }
+
+        src_line += src->left * 3;
+
+        frame_row = frame;
+        memcpy (frame_row, src_line, image_width * 3);
+        frame += frame_stride;
+    }
+
+    return TRUE;
+}
+
+static int red_rgb16bpp_to_24 (RedWorker *worker, const SpiceRect *src,
+                               const SpiceBitmap *image,
+                               uint8_t *frame, size_t frame_stride,
+                               long phys_delta, int memslot_id, int id,
+                               Stream *stream, uint32_t group_id)
+{
+    QXLDataChunk *chunk;
+    uint32_t image_stride;
+    uint8_t *frame_row;
+    int offset;
+    int i, x;
+
+    offset = 0;
+    chunk = (QXLDataChunk *)(image->data + phys_delta);
+    image_stride = image->stride;
+
+    const int skip_lines = stream->top_down ? src->top : image->y - (src->bottom - 0);
+    for (i = 0; i < skip_lines; i++) {
+        red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, memslot_id,
+                           group_id);
+    }
+
+    const int image_height = src->bottom - src->top;
+    const int image_width = src->right - src->left;
+    for (i = 0; i < image_height; i++) {
+        uint16_t *src_line =
+            (uint16_t *)red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta,
+                                           memslot_id, group_id);
+
+        if (!src_line) {
+            return FALSE;
+        }
+
+        src_line += src->left;
+
+        frame_row = frame;
+        for (x = 0; x < image_width; x++) {
+            uint16_t pixel = *src_line++;
+            *frame_row++ = ((pixel >> 7) & 0xf8) | ((pixel >> 12) & 0x7);
+            *frame_row++ = ((pixel >> 2) & 0xf8) | ((pixel >> 7) & 0x7);
+            *frame_row++ = ((pixel << 3) & 0xf8) | ((pixel >> 2) & 0x7);
+        }
+
+        frame += frame_stride;
+    }
+
+    return TRUE;
+}
+
+#define PADDING 8 /* old ffmpeg padding */
 
 static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable *drawable)
 {
@@ -7077,6 +7110,8 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
     RedChannel *channel;
     RedWorker* worker;
     unsigned long data;
+    uint8_t *frame;
+    size_t frame_stride;
     int n;
 
     ASSERT(stream);
@@ -7088,7 +7123,7 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
                                      sizeof(QXLImage), drawable->group_id);
 
     if (qxl_image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP ||
-                                            (qxl_image->bitmap.flags & QXL_BITMAP_DIRECT)) {
+        (qxl_image->bitmap.flags & QXL_BITMAP_DIRECT)) {
         return FALSE;
     }
 
@@ -7100,32 +7135,34 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
     }
 
     data = qxl_image->bitmap.data;
+    frame = mjpeg_encoder_get_frame(stream->mjpeg_encoder);
+    frame_stride = mjpeg_encoder_get_frame_stride(stream->mjpeg_encoder);
 
     switch (qxl_image->bitmap.format) {
     case SPICE_BITMAP_FMT_32BIT:
-        if (!red_rgb_to_yuv420_32bpp(worker, &drawable->qxl_drawable->u.copy.src_area,
-                                     &qxl_image->bitmap, stream->av_frame,
-                                     get_virt_delta(worker, data, drawable->group_id),
-                                     get_memslot_id(worker, data),
-                                     stream - worker->streams_buf, stream, drawable->group_id)) {
+        if (!red_rgb32bpp_to_24(worker, &drawable->qxl_drawable->u.copy.src_area,
+                                &qxl_image->bitmap, frame, frame_stride,
+                                get_virt_delta(worker, data, drawable->group_id),
+                                get_memslot_id(worker, data),
+                                stream - worker->streams_buf, stream, drawable->group_id)) {
             return FALSE;
         }
         break;
     case SPICE_BITMAP_FMT_16BIT:
-        if (!red_rgb_to_yuv420_16bpp(worker, &drawable->qxl_drawable->u.copy.src_area,
-                                     &qxl_image->bitmap, stream->av_frame,
-                                     get_virt_delta(worker, data, drawable->group_id),
-                                     get_memslot_id(worker, data),
-                                     stream - worker->streams_buf, stream, drawable->group_id)) {
+        if (!red_rgb16bpp_to_24(worker, &drawable->qxl_drawable->u.copy.src_area,
+                                &qxl_image->bitmap, frame, frame_stride,
+                                get_virt_delta(worker, data, drawable->group_id),
+                                get_memslot_id(worker, data),
+                                stream - worker->streams_buf, stream, drawable->group_id)) {
             return FALSE;
         }
         break;
     case SPICE_BITMAP_FMT_24BIT:
-        if (!red_rgb_to_yuv420_24bpp(worker, &drawable->qxl_drawable->u.copy.src_area,
-                                     &qxl_image->bitmap, stream->av_frame,
-                                     get_virt_delta(worker, data, drawable->group_id),
-                                     get_memslot_id(worker, data),
-                                     stream - worker->streams_buf, stream, drawable->group_id)) {
+        if (!red_rgb24bpp_to_24(worker, &drawable->qxl_drawable->u.copy.src_area,
+                                &qxl_image->bitmap, frame, frame_stride,
+                                get_virt_delta(worker, data, drawable->group_id),
+                                get_memslot_id(worker, data),
+                                stream - worker->streams_buf, stream, drawable->group_id)) {
             return FALSE;
         }
         break;
@@ -7133,75 +7170,34 @@ static inline int red_send_stream_data(DisplayChannel *display_channel, Drawable
         red_printf_some(1000, "unsupported format %d", qxl_image->bitmap.format);
         return FALSE;
     }
-#if 1
-    uint32_t min_buf_size = stream->av_ctx->width * stream->av_ctx->height * sizeof(uint32_t) / 2;
-    min_buf_size += FF_MIN_BUFFER_SIZE;
-    if (display_channel->send_data.stream_outbuf_size < min_buf_size) {
+
+    while ((n = mjpeg_encoder_encode_frame(stream->mjpeg_encoder,
+                                           display_channel->send_data.stream_outbuf,
+                                           display_channel->send_data.stream_outbuf_size - PADDING)) == 0) {
         uint8_t *new_buf;
+        size_t new_size;
 
-        new_buf = spice_malloc(min_buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
+        new_size = display_channel->send_data.stream_outbuf_size * 2;
+        new_buf = spice_malloc(new_size);
 
         red_display_unshare_stream_buf(display_channel);
         free(display_channel->send_data.stream_outbuf);
         display_channel->send_data.stream_outbuf = new_buf;
-        display_channel->send_data.stream_outbuf_size = min_buf_size;
+        display_channel->send_data.stream_outbuf_size = new_size;
         red_display_share_stream_buf(display_channel);
     }
-    n = avcodec_encode_video(stream->av_ctx, display_channel->send_data.stream_outbuf,
-                             display_channel->send_data.stream_outbuf_size,
-                             stream->av_frame);
-
-    if (n <= 0) {
-        red_printf("avcodec_encode_video failed");
-        return FALSE;
-    }
 
-    if (n > display_channel->send_data.stream_outbuf_size) {
-        PANIC("buf error");
-    }
-#else
-    for (;;) {
-        n = avcodec_encode_video(stream->av_ctx, display_channel->send_data.stream_outbuf,
-                                 display_channel->send_data.stream_outbuf_size,
-                                 stream->av_frame);
-        if (n < 0) {
-            uint8_t *new_buf;
-            size_t max_size;
-            size_t new_size;
-
-            max_size = stream->av_ctx->width * stream->av_ctx->height * sizeof(uint32_t);
-            max_size += MAX(1024, max_size / 10);
-
-            if (display_channel->send_data.stream_outbuf_size == max_size) {
-                return FALSE;
-            }
-
-            new_size = display_channel->send_data.stream_outbuf_size * 2;
-            new_size = MIN(new_size, max_size);
-
-            new_buf = spice_malloc(new_size + FF_INPUT_BUFFER_PADDING_SIZE);
-            red_printf("new streaming video buf size %u", new_size);
-            red_display_unshare_stream_buf(display_channel);
-            free(display_channel->send_data.stream_outbuf);
-            display_channel->send_data.stream_outbuf = new_buf;
-            display_channel->send_data.stream_outbuf_size = new_size;
-            red_display_share_stream_buf(display_channel);
-            continue;
-        }
-        ASSERT(n <= display_channel->send_data.stream_outbuf_size);
-        break;
-    }
- #endif
     channel->send_data.header.type = SPICE_MSG_DISPLAY_STREAM_DATA;
+
     SpiceMsgDisplayStreamData* stream_data = &display_channel->send_data.u.stream_data;
     add_buf(channel, BUF_TYPE_RAW, stream_data, sizeof(SpiceMsgDisplayStreamData), 0, 0);
     add_buf(channel, BUF_TYPE_RAW, display_channel->send_data.stream_outbuf,
-            n + FF_INPUT_BUFFER_PADDING_SIZE, 0, 0);
+            n + PADDING, 0, 0);
 
     stream_data->id = stream - worker->streams_buf;
     stream_data->multi_media_time = drawable->qxl_drawable->mm_time;
     stream_data->data_size = n;
-    stream_data->ped_size = FF_INPUT_BUFFER_PADDING_SIZE;
+    stream_data->ped_size = PADDING;
     display_begin_send_massage(display_channel, NULL);
     agent->lats_send_time = time_now;
     return TRUE;
@@ -8797,9 +8793,9 @@ static void handle_new_display_channel(RedWorker *worker, RedsStreamContext *pee
     display_channel->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
     red_display_init_streams(display_channel);
 
-    stream_buf_size = FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE;
+    stream_buf_size = 32*1024;
     display_channel->send_data.stream_outbuf = spice_malloc(stream_buf_size);
-    display_channel->send_data.stream_outbuf_size = FF_MIN_BUFFER_SIZE;
+    display_channel->send_data.stream_outbuf_size = stream_buf_size;
     red_display_share_stream_buf(display_channel);
     red_display_init_glz_data(display_channel);
     worker->display_channel = display_channel;
@@ -9571,8 +9567,6 @@ void *red_worker_main(void *arg)
     }
 #endif
 
-    avcodec_init();
-    avcodec_register_all();
     red_init(&worker, (WorkerInitData *)arg);
     red_init_quic(&worker);
     red_init_lz(&worker);
diff --git a/server/red_yuv.h b/server/red_yuv.h
deleted file mode 100644
index 756717d..0000000
--- a/server/red_yuv.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
-   Copyright (C) 2009 Red Hat, Inc.
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#if defined(YUV32)
-#define PIXEL_SIZE 4
-#define R(pixel) (((uint8_t*)(pixel))[0])
-#define G(pixel) (((uint8_t*)(pixel))[1])
-#define B(pixel) (((uint8_t*)(pixel))[2])
-
-#define FUNC_NAME(name) name##_32bpp
-
-#elif defined(YUV24)
-#define PIXEL_SIZE 3
-#define R(pixel) (((uint8_t*)(pixel))[0])
-#define G(pixel) (((uint8_t*)(pixel))[1])
-#define B(pixel) (((uint8_t*)(pixel))[2])
-
-#define FUNC_NAME(name) name##_24bpp
-
-#elif defined(YUV16)
-#define PIXEL_SIZE 2
-#define PIX16(pixel) (*(uint16_t*)(pixel))
-
-#define R(pixel) ((PIX16(pixel) << 3) & 0xff)
-#define G(pixel) ((PIX16(pixel) >> 2) & 0xff)
-#define B(pixel) ((PIX16(pixel) >> 7) & 0xff)
-
-#define FUNC_NAME(name) name##_16bpp
-
-#else
-#error "invalid format."
-#endif
-
-#define Y(pixel) (((66 * R(pixel) + 129 * G(pixel) + 25 * B(pixel) + 128) >> 8) + 16)
-#define U(pixel) (((-38 * R(pixel) - 74 * G(pixel) + 112 * B(pixel) + 128) >> 8) + 128)
-#define V(pixel) (((112 * R(pixel) - 94 * G(pixel) - 18 * B(pixel) + 128) >> 8) + 128)
-
-static inline void FUNC_NAME(red_rgb_to_yuv420_line)(const uint8_t* line0, const uint8_t* line1,
-                                                     const uint32_t width, uint8_t* y, uint8_t *u,
-                                                     uint8_t *v, int y_stride)
-{
-    int i;
-
-    // Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
-    // Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
-    // Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
-
-    for (i = 0; i < width / 2; i++) {
-        *y = Y(line0);
-        *(y + 1) = Y(line0 + PIXEL_SIZE);
-        *(y + y_stride) = Y(line1);
-        *(y + y_stride + 1) = Y(line1 + PIXEL_SIZE);
-
-        u[i] = (U(line0) + U(line0 + PIXEL_SIZE) + U(line1) + U(line1 + PIXEL_SIZE)) / 4;
-        v[i] = (V(line0) + V(line0 + PIXEL_SIZE) + V(line1) + V(line1 + PIXEL_SIZE)) / 4;
-
-        line0 += 2 * PIXEL_SIZE;
-        line1 += 2 * PIXEL_SIZE;
-        y += 2;
-    }
-
-    if ((width & 1)) {
-        *y = Y(line0);
-        *(y + 1) = *y;
-        *(y + y_stride) = Y(line1);
-        *(y + y_stride + 1) = *(y + y_stride);
-        u[i] = (U(line0) + U(line1)) / 2;
-        v[i] = (V(line0) + V(line1)) / 2;
-    }
-}
-
-static inline int FUNC_NAME(red_rgb_to_yuv420)(RedWorker *worker, const SpiceRect *src,
-                                               const SpiceBitmap *image, AVFrame *frame,
-                                               long phys_delta, int memslot_id, int id,
-                                               Stream *stream, uint32_t group_id)
-{
-    QXLDataChunk *chunk;
-    uint32_t image_stride;
-    int y_stride;
-    uint8_t* y;
-    uint8_t* u;
-    uint8_t* v;
-    int offset;
-    int i;
-
-    y = frame->data[0];
-    u = frame->data[1];
-    v = frame->data[2];
-    y_stride = frame->linesize[0];
-
-    offset = 0;
-    chunk = (QXLDataChunk *)(image->data + phys_delta);
-    image_stride = image->stride;
-
-    const int skip_lines = stream->top_down ? src->top : image->y - (src->bottom - 0);
-    for (i = 0; i < skip_lines; i++) {
-        red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta, memslot_id,
-                           group_id);
-    }
-
-    const int image_hight = src->bottom - src->top;
-    const int image_width = src->right - src->left;
-    for (i = 0; i < image_hight / 2; i++) {
-        uint8_t* line0 = red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta,
-                                            memslot_id, group_id);
-        uint8_t* line1 = red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta,
-                                            memslot_id, group_id);
-
-        if (!line0 || !line1) {
-            return FALSE;
-        }
-
-        line0 += src->left * PIXEL_SIZE;
-        line1 += src->left * PIXEL_SIZE;
-
-        FUNC_NAME(red_rgb_to_yuv420_line)(line0, line1, image_width, y, u, v, y_stride);
-
-        y += 2 * y_stride;
-        u += frame->linesize[1];
-        v += frame->linesize[2];
-    }
-
-    if ((image_hight & 1)) {
-        uint8_t* line = red_get_image_line(worker, &chunk, &offset, image_stride, phys_delta,
-                                           memslot_id, group_id);
-        if (!line) {
-            return FALSE;
-        }
-        line += src->left * PIXEL_SIZE;
-        FUNC_NAME(red_rgb_to_yuv420_line)(line, line, image_width, y, u, v, y_stride);
-    }
-    return TRUE;
-}
-
-
-#undef R
-#undef G
-#undef B
-#undef Y
-#undef U
-#undef V
-#undef FUNC_NAME
-#undef PIXEL_SIZE
-#undef PIX16
-
commit 18485cef06283c17ddd98fd5411b71bcb64201a3
Author: Alexander Larsson <alexl at redhat.com>
Date:   Thu Apr 8 16:35:10 2010 +0200

    Free the jpeg decoder with the stream

diff --git a/client/mjpeg_decoder.cpp b/client/mjpeg_decoder.cpp
index 21804fb..df0dbad 100644
--- a/client/mjpeg_decoder.cpp
+++ b/client/mjpeg_decoder.cpp
@@ -94,6 +94,7 @@ MJpegDecoder::MJpegDecoder(int width, int height,
 
 MJpegDecoder::~MJpegDecoder()
 {
+    jpeg_destroy_decompress(&_cinfo);
     delete [] _scanline;
     if (_data) {
         delete [] _data;


More information about the Spice-commits mailing list