[Spice-commits] client/display_channel.cpp client/Makefile.am client/mjpeg_decoder.cpp client/mjpeg_decoder.h client/windows client/x11 configure.ac

Alexander Larsson alexl at kemper.freedesktop.org
Thu Apr 8 02:32:00 PDT 2010


 client/Makefile.am         |    2 
 client/display_channel.cpp |  175 ++++-----------------------------
 client/mjpeg_decoder.cpp   |  236 +++++++++++++++++++++++++++++++++++++++++++++
 client/mjpeg_decoder.h     |   72 +++++++++++++
 client/windows/redc.vcproj |   16 ++-
 client/x11/Makefile.am     |   16 +--
 configure.ac               |   13 ++
 7 files changed, 367 insertions(+), 163 deletions(-)

New commits:
commit 5059c304be3aeae6bf8c8b201f844afa77cf1323
Author: Alexander Larsson <alexl at redhat.com>
Date:   Wed Apr 7 10:42:57 2010 +0200

    Use libjpeg to decode mjpegs, not ffmpeg
    
    This is pretty straightforward, although there are two weird issues.
    The current encoder has two bugs in the yuv conversion. First of all
    it switches red and blue, due to something of an endianness issue. We
    keep this behavior by switching red and blue. Maybe we want to
    change this in the new protocol version since switching this may
    cause jpeg compression to be worse.
    
    Secondly, the old coder/decoder did rgb to/from yuv420 wrongly for
    jpeg, not using the "full scale" version of Y that is used in jpeg,
    but the other one where y goes from 16 to 235. (See jpeg/jfif
    reference on http://en.wikipedia.org/wiki/YCbCr for details.)
    The new decoder uses the full range in order to get better quality,
    which means old encoders will show slightly darker images.
    
    This completely removes all ffmpeg usage in the client

diff --git a/client/Makefile.am b/client/Makefile.am
index 887c7b5..81ad6db 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -49,6 +49,8 @@ RED_COMMON_SRCS =	 		\
 	mem.cpp				\
 	menu.cpp			\
 	menu.h				\
+	mjpeg_decoder.h			\
+	mjpeg_decoder.cpp		\
 	pixels_source.h			\
 	platform.h			\
 	playback_channel.cpp		\
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index d63726c..6427ae4 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -38,11 +38,9 @@
 #include "red_gdi_canvas.h"
 #endif
 #include "platform_utils.h"
-#include "ffmpeg_inc.h"
 #include "inputs_channel.h"
 #include "cursor_channel.h"
-
-static Mutex avcodec_mutex;
+#include "mjpeg_decoder.h"
 
 class CreatePrimarySurfaceEvent: public SyncEvent {
 public:
@@ -144,85 +142,6 @@ private:
     AutoRef<RedScreen> _screen;
 };
 
-#define CLIP_ARRAY_SIZE 1500
-#define CLIP_ARRAY_SHIFT 500
-
-static uint8_t clip_array[CLIP_ARRAY_SIZE];
-static uint8_t *clip_zero = &clip_array[CLIP_ARRAY_SHIFT];
-
-static void init_clip_array()
-{
-    int i;
-    for (i = 0; i < CLIP_ARRAY_SHIFT; i++) {
-        clip_array[i] = 0;
-    }
-
-    for (i = CLIP_ARRAY_SHIFT + 256; i < CLIP_ARRAY_SIZE; i++) {
-        clip_array[i] = 0xff;
-    }
-
-    for (i = 0; i < 256; i++) {
-        clip_zero[i] = i;
-    }
-}
-
-#define  CLIP(val) clip_zero[(int)(val)]
-
-#define R(pixel) (((uint8_t*)(pixel))[0])
-#define G(pixel) (((uint8_t*)(pixel))[1])
-#define B(pixel) (((uint8_t*)(pixel))[2])
-
-#define YUV_TO_RGB(pixel, y, u , v) {                           \
-    int Y = (y) - 16;                                           \
-    int U = (u) - 128;                                          \
-    int V = (v) - 128;                                          \
-    R(pixel) = CLIP((298 * Y + 409 * V + 128) >> 8);            \
-    G(pixel) = CLIP((298 * Y - 100 * U - 208 * V + 128) >> 8);  \
-    B(pixel) = CLIP((298 * Y + 516 * U + 128) >> 8);            \
-}
-
-static inline void yuv420_to_rgb(AVFrame* frame, uint8_t* data, uint32_t width, uint32_t height,
-                                 int stride, int top_down)
-{
-    ASSERT(width % 2 == 0);
-    ASSERT(height % 2 == 0);
-
-    /* turning it to be down to top */
-    if (top_down) {
-        data += stride * (height - 1);
-        stride = -stride;
-    }
-
-    // B = 1.164(Y - 16) + 2.018(U - 128)
-    // G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
-    // R = 1.164(Y - 16) + 1.596(V - 128)
-
-    uint8_t* y_line = frame->data[0];
-    uint8_t* u = frame->data[1];
-    uint8_t* v = frame->data[2];
-
-    uint32_t y_stride = frame->linesize[0];
-    uint32_t u_stride = frame->linesize[1];
-    uint32_t v_stride = frame->linesize[2];
-
-    for (unsigned int i = 0; i < height / 2; i++) {
-        uint8_t* now = data;
-        uint8_t* y = y_line;
-
-        for (unsigned int j = 0; j < width / 2; j++) {
-            YUV_TO_RGB(now, *y, u[j], v[j]);
-            YUV_TO_RGB(now + sizeof(uint32_t), *(y + 1), u[j], v[j]);
-            YUV_TO_RGB(now + stride, *(y + y_stride), u[j], v[j]);
-            YUV_TO_RGB(now + stride + sizeof(uint32_t), *(y + y_stride + 1), u[j], v[j]);
-            y += 2;
-            now += 2 * sizeof(uint32_t);
-        }
-        data += stride * 2;
-        y_line += y_stride * 2;
-        u += u_stride;
-        v += v_stride;
-    }
-}
 
 #define MAX_VIDEO_FRAMES 30
 #define MAX_OVER 15
@@ -243,8 +162,6 @@ public:
     void handle_update_mark(uint64_t update_mark);
     uint32_t handle_timer_update(uint32_t now);
 
-    static void init();
-
 private:
     void free_frame(uint32_t frame_index);
     void release_all_bufs();
@@ -259,8 +176,7 @@ private:
     RedClient& _client;
     Canvas& _canvas;
     DisplayChannel& _channel;
-    AVCodecContext* _ctx;
-    AVFrame* _frame;
+    MJpegDecoder *_mjpeg_decoder;
     int _stream_width;
     int _stream_height;
     int _stride;
@@ -339,8 +255,7 @@ VideoStream::VideoStream(RedClient& client, Canvas& canvas, DisplayChannel& chan
     : _client (client)
     , _canvas (canvas)
     , _channel (channel)
-    , _ctx (NULL)
-    , _frame (NULL)
+    , _mjpeg_decoder (NULL)
     , _stream_width (stream_width)
     , _stream_height (stream_height)
     , _stride (stream_width * sizeof(uint32_t))
@@ -354,34 +269,13 @@ VideoStream::VideoStream(RedClient& client, Canvas& canvas, DisplayChannel& chan
     , _update_time (0)
     , next (NULL)
 {
-    AVCodecContext* ctx = NULL;
-    AVCodec* codec;
-    AVFrame* frame = NULL;
-
-    enum CodecID type;
-
     memset(_frames, 0, sizeof(_frames));
     region_init(&_clip_region);
-    switch (codec_type) {
-    case SPICE_VIDEO_CODEC_TYPE_MJPEG:
-        type = CODEC_ID_MJPEG;
-        break;
-    default:
-        THROW("invalid vide codec type %u", codec_type);
+    if (codec_type != SPICE_VIDEO_CODEC_TYPE_MJPEG) {
+      THROW("invalid vide codec type %u", codec_type);
     }
 
-    if (!(codec = avcodec_find_decoder(type))) {
-        THROW("can't find codec %u", type);
-    }
-
-    if (!(ctx = avcodec_alloc_context())) {
-        THROW("alloc codec ctx failed");
-    }
     try {
-        if (!(frame = avcodec_alloc_frame())) {
-            THROW("alloc frame failed");
-        }
-
 #ifdef WIN32
         if (!create_bitmap(&_dc, &_prev_bitmap, &_uncompressed_data, &_stride,
                            stream_width, stream_height)) {
@@ -393,35 +287,37 @@ VideoStream::VideoStream(RedClient& client, Canvas& canvas, DisplayChannel& chan
         _pixmap.width = src_width;
         _pixmap.height = src_height;
 
+	_mjpeg_decoder = new MJpegDecoder(stream_width, stream_height, _stride, _uncompressed_data);
+
 #ifdef WIN32
         SetViewportOrgEx(_dc, 0, stream_height - src_height, NULL);
 #endif
-        _pixmap.data = _uncompressed_data + _stride * (src_height - 1);
-        _pixmap.stride = -_stride;
+
+	if (_top_down) {
+	    _pixmap.data = _uncompressed_data;
+	    _pixmap.stride = _stride;
+	} else {
+	    _pixmap.data = _uncompressed_data + _stride * (src_height - 1);
+	    _pixmap.stride = -_stride;
+	}
 
         set_clip(clip_type, num_clip_rects, clip_rects);
 
-        Lock lock(avcodec_mutex);
-        if (avcodec_open(ctx, codec) < 0) {
-            THROW("open avcodec failed");
-        }
     } catch (...) {
-        av_free(frame);
-        av_free(ctx);
+        if (_mjpeg_decoder) {
+            delete _mjpeg_decoder;
+            _mjpeg_decoder = NULL;
+        }
         release_all_bufs();
         throw;
     }
-    _frame = frame;
-    _ctx = ctx;
 }
 
 VideoStream::~VideoStream()
 {
-    if (_ctx) {
-        Lock lock(avcodec_mutex);
-        avcodec_close(_ctx);
-        av_free(_ctx);
-        av_free(_frame);
+    if (_mjpeg_decoder) {
+        delete _mjpeg_decoder;
+        _mjpeg_decoder = NULL;
     }
     release_all_bufs();
     region_destroy(&_clip_region);
@@ -493,20 +389,8 @@ void VideoStream::maintenance()
         uint8_t* data = tail->compressed_data;
         uint32_t length = tail->compressed_data_size;
         int got_picture = 0;
-        while (length > 0) {
-            int n = avcodec_decode_video(_ctx, _frame, &got_picture, data, length);
-            if (n < 0) {
-                THROW("decoding eror");
-            }
-            if (got_picture) {
-                yuv420_to_rgb(_frame, _uncompressed_data, _stream_width, _stream_height, _stride,
-                              _top_down);
-                ASSERT(length - n == 0);
-                break;
-            }
-            length -= n;
-            data += n;
-        }
+
+        got_picture =_mjpeg_decoder->decode_data(data, length);
         if (got_picture) {
 #ifdef WIN32
             _canvas.put_image(_dc, _pixmap, _dest, _clip);
@@ -560,9 +444,6 @@ uint32_t VideoStream::alloc_frame_slot()
 
 void VideoStream::push_data(uint32_t mm_time, uint32_t length, uint8_t* data, uint32_t ped_size)
 {
-    if (ped_size < FF_INPUT_BUFFER_PADDING_SIZE) {
-        THROW("insufficieant pedding");
-    }
     maintenance();
     uint32_t frame_slot = alloc_frame_slot();
     _frames[frame_slot].compressed_data = new uint8_t[length];
@@ -588,18 +469,10 @@ void VideoStream::set_clip(int type, uint32_t num_clip_rects, SpiceRect* clip_re
     _clip = &_clip_region;
 }
 
-void VideoStream::init()
-{
-    avcodec_init();
-    avcodec_register_all();
-    init_clip_array();
-}
-
 class AutoVStreamInit {
 public:
     AutoVStreamInit()
     {
-        VideoStream::init();
     }
 };
 
diff --git a/client/mjpeg_decoder.cpp b/client/mjpeg_decoder.cpp
new file mode 100644
index 0000000..21804fb
--- /dev/null
+++ b/client/mjpeg_decoder.cpp
@@ -0,0 +1,236 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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 WIN32
+#include "config.h"
+#endif
+
+#include "common.h"
+#include "debug.h"
+#include "utils.h"
+#include "mjpeg_decoder.h"
+
+enum {
+    STATE_READ_HEADER,
+    STATE_START_DECOMPRESS,
+    STATE_READ_SCANLINES,
+    STATE_FINISH_DECOMPRESS
+};
+
+extern "C" {
+
+    static void init_source(j_decompress_ptr cinfo)
+    {
+    }
+
+    static boolean fill_input_buffer(j_decompress_ptr cinfo)
+    {
+        return FALSE;
+    }
+
+    void mjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+    {
+        MJpegDecoder *decoder = (MJpegDecoder *)cinfo;
+        if (num_bytes > 0) {
+            if (cinfo->src->bytes_in_buffer >= (size_t)num_bytes) {
+                cinfo->src->next_input_byte += (size_t) num_bytes;
+                cinfo->src->bytes_in_buffer -= (size_t) num_bytes;
+            } else {
+                decoder->_extra_skip = num_bytes - cinfo->src->bytes_in_buffer;
+                cinfo->src->bytes_in_buffer = 0;
+            }
+        }
+    }
+
+    static void term_source (j_decompress_ptr cinfo)
+    {
+        return;
+    }
+}
+
+MJpegDecoder::MJpegDecoder(int width, int height,
+                           int stride,
+                           uint8_t *frame) :
+    _data(NULL)
+    , _data_size(0)
+    , _data_start(0)
+    , _data_end(0)
+    , _extra_skip(0)
+    , _width(width)
+    , _height(height)
+    , _stride(stride)
+    , _frame(frame)
+    , _y(0)
+    , _state(0)
+{
+    memset(&_cinfo, 0, sizeof(_cinfo));
+    _cinfo.err = jpeg_std_error (&_jerr);
+    jpeg_create_decompress (&_cinfo);
+
+    _cinfo.src = &_jsrc;
+    _cinfo.src->init_source = init_source;
+    _cinfo.src->fill_input_buffer = fill_input_buffer;
+    _cinfo.src->skip_input_data = mjpeg_skip_input_data;
+    _cinfo.src->resync_to_restart = jpeg_resync_to_restart;
+    _cinfo.src->term_source = term_source;
+
+    _scanline = new uint8_t[width * 3];
+}
+
+MJpegDecoder::~MJpegDecoder()
+{
+    delete [] _scanline;
+    if (_data) {
+        delete [] _data;
+    }
+}
+
+void MJpegDecoder::convert_scanline(void)
+{
+    uint32_t *row;
+    uint32_t c;
+    uint8_t *s;
+    int x;
+
+    ASSERT(_width % 2 == 0);
+    ASSERT(_height % 2 == 0);
+
+   row = (uint32_t *)(_frame + _y * _stride);
+    s = _scanline;
+    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;
+        s += 3;
+        *row++ = c;
+    }
+}
+
+bool MJpegDecoder::decode_data(uint8_t *data, size_t length)
+{
+    uint8_t *new_data;
+    size_t data_len;
+    int res;
+    bool got_picture;
+
+    got_picture = false;
+
+    if (_extra_skip > 0) {
+        if (_extra_skip >= length) {
+            _extra_skip -= length;
+            return false;
+        } else {
+            data += _extra_skip;
+            length -= _extra_skip;
+            _extra_skip = 0;
+        }
+    }
+
+    if (_data_size - _data_end < length) {
+        /* Can't fit in tail */
+
+        data_len = _data_end - _data_start;
+        if (_data_size - data_len < length) {
+            /* Can't fit at all, grow a bit */
+            _data_size = _data_size + length * 2;
+            new_data = new uint8_t[_data_size];
+            memcpy (new_data, _data + _data_start, data_len);
+            delete [] _data;
+            _data = new_data;
+        } else {
+            /* Just needs to compact */
+            memmove (_data, _data + _data_start, data_len);
+        }
+        _data_start = 0;
+        _data_end = data_len;
+    }
+
+    memcpy (_data + _data_end, data, length);
+    _data_end += length;
+
+    _jsrc.next_input_byte = _data + _data_start;
+    _jsrc.bytes_in_buffer = _data_end - _data_start;
+
+    switch (_state) {
+    case STATE_READ_HEADER:
+        res = jpeg_read_header(&_cinfo, TRUE);
+        if (res == JPEG_SUSPENDED) {
+            break;
+        }
+
+        _cinfo.do_fancy_upsampling = FALSE;
+        _cinfo.do_block_smoothing = FALSE;
+        _cinfo.out_color_space = JCS_RGB;
+
+        PANIC_ON(_cinfo.image_width != _width);
+        PANIC_ON(_cinfo.image_height != _height);
+
+        _state = STATE_START_DECOMPRESS;
+
+        /* fall through */
+    case STATE_START_DECOMPRESS:
+        res = jpeg_start_decompress (&_cinfo);
+
+        if (!res) {
+            break;
+        }
+
+        _state = STATE_READ_SCANLINES;
+
+        /* fall through */
+    case STATE_READ_SCANLINES:
+        res = 0;
+        while (_y < _height) {
+            res = jpeg_read_scanlines(&_cinfo, &_scanline, 1);
+
+            if (res == 0) {
+                break;
+            }
+
+            convert_scanline();
+            _y++;
+        }
+        if (res == 0) {
+            break;
+        }
+
+        _state = STATE_FINISH_DECOMPRESS;
+
+        /* fall through */
+    case STATE_FINISH_DECOMPRESS:
+        res = jpeg_finish_decompress (&_cinfo);
+
+        if (!res) {
+            break;
+        }
+
+        _y = 0;
+        _state = STATE_READ_HEADER;
+        got_picture = true;
+
+        break;
+    }
+
+    _data_start = _jsrc.next_input_byte - _data;
+    _data_end = _data_start + _jsrc.bytes_in_buffer;
+
+    return got_picture;
+}
diff --git a/client/mjpeg_decoder.h b/client/mjpeg_decoder.h
new file mode 100644
index 0000000..f517675
--- /dev/null
+++ b/client/mjpeg_decoder.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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_DECODER
+#define _H_MJPEG_DECODER
+
+#include "common.h"
+
+#ifdef WIN32
+/* We need some hacks to avoid warnings from the jpeg headers */
+#define XMD_H
+#undef FAR
+#endif
+extern "C" {
+#include <jpeglib.h>
+}
+
+extern "C" {
+    void mjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes);
+}
+
+class MJpegDecoder {
+public:
+    MJpegDecoder(int width, int height, int stride,
+                 uint8_t *frame);
+    ~MJpegDecoder();
+
+    bool decode_data(uint8_t *data, size_t length);
+
+private:
+
+    friend void mjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes);
+
+    void convert_scanline(void);
+
+    struct jpeg_decompress_struct _cinfo;
+    struct jpeg_error_mgr _jerr;
+    struct jpeg_source_mgr _jsrc;
+
+    uint8_t *_data;
+    size_t _data_size;
+    size_t _data_start;
+    size_t _data_end;
+    size_t _extra_skip;
+
+    int _width;
+    int _height;
+    int _stride;
+    uint8_t *_frame;
+
+    int _y;
+    uint8_t *_scanline;
+
+    int _state;
+};
+
+#endif
diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
index 18aca16..ae94135 100644
--- a/client/windows/redc.vcproj
+++ b/client/windows/redc.vcproj
@@ -42,7 +42,7 @@
 			<Tool
 				Name="VCCLCompilerTool"
 				Optimization="0"
-				AdditionalIncludeDirectories=".;..;..\..\common;..\..\..\spice-protocol;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\ffmpeg&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;"
+				AdditionalIncludeDirectories=".;..;..\..\common;..\..\..\spice-protocol;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;CAIRO_CANVAS_ACCESS_TEST;CAIRO_CANVAS_CACHE;RED_DEBUG;CAIRO_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
 				MinimalRebuild="false"
 				BasicRuntimeChecks="3"
@@ -65,7 +65,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="log4cppD.lib pixman-1D.lib libeay32MTd.lib ssleay32MTd.lib ws2_32.lib msimg32.lib winmm.lib avcodec-51.lib avutil-49.lib libcelt_0_5_1D.lib pthreadsD.lib version.lib CEGUIBase_Static_d.lib CEGUITGAImageCodec_Static_d.lib CEGUIExpatParser_Static_d.lib freetype235MT_D.lib libexpatMT_D.lib pcre_D.lib CEGUIFalagardWRBase_Static_d.lib"
+				AdditionalDependencies="log4cppD.lib pixman-1D.lib libeay32MTd.lib ssleay32MTd.lib ws2_32.lib msimg32.lib winmm.lib libcelt_0_5_1D.lib pthreadsD.lib version.lib CEGUIBase_Static_d.lib CEGUITGAImageCodec_Static_d.lib CEGUIExpatParser_Static_d.lib freetype235MT_D.lib libexpatMT_D.lib pcre_D.lib CEGUIFalagardWRBase_Static_d.lib libjpeg-static-mt-debug.lib"
 				OutputFile="$(OutDir)\spicec.exe"
 				LinkIncremental="2"
 				AdditionalLibraryDirectories="&quot;$(SPICE_LIBS)\lib&quot;"
@@ -124,7 +124,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalIncludeDirectories=".;..;..\..\..\spice-protocol;..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\ffmpeg&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;"
+				AdditionalIncludeDirectories=".;..;..\..\..\spice-protocol;..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;"
 				PreprocessorDefinitions="WIN32;_WINDOWS;CAIRO_CANVAS_ACCESS_TEST;CAIRO_CANVAS_CACHE;CAIRO_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;LOG4CPLUS_STATIC;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
 				RuntimeLibrary="0"
 				UsePrecompiledHeader="0"
@@ -144,7 +144,7 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
-				AdditionalDependencies="log4cpp.lib pixman-1.lib libeay32MT.lib ssleay32MT.lib ws2_32.lib msimg32.lib winmm.lib avcodec-51.lib avutil-49.lib libcelt_0_5_1.lib pthreads.lib version.lib CEGUIBase_Static.lib CEGUITGAImageCodec_Static.lib CEGUIExpatParser_Static.lib freetype235MT.lib libexpatMT.lib pcre.lib CEGUIFalagardWRBase_Static.lib"
+				AdditionalDependencies="log4cpp.lib pixman-1.lib libeay32MT.lib ssleay32MT.lib ws2_32.lib msimg32.lib winmm.lib libcelt_0_5_1.lib pthreads.lib version.lib CEGUIBase_Static.lib CEGUITGAImageCodec_Static.lib CEGUIExpatParser_Static.lib freetype235MT.lib libexpatMT.lib pcre.lib CEGUIFalagardWRBase_Static.lib libjpeg-static-mt.lib"
 				OutputFile="$(OutDir)\spicec.exe"
 				LinkIncremental="1"
 				AdditionalLibraryDirectories="&quot;$(SPICE_LIBS)\lib&quot;"
@@ -272,6 +272,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\mjpeg_decoder.cpp"
+				>
+			</File>
+			<File
 				RelativePath="..\monitor.cpp"
 				>
 			</File>
@@ -524,6 +528,10 @@
 				>
 			</File>
 			<File
+				RelativePath="..\mjpeg_decoder.h"
+				>
+			</File>
+			<File
 				RelativePath="..\monitor.h"
 				>
 			</File>
diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
index ee92b33..e5a3b77 100644
--- a/client/x11/Makefile.am
+++ b/client/x11/Makefile.am
@@ -12,7 +12,7 @@ INCLUDES = \
 	-DUSE_GLZ					\
 	-DUSE_OGL					\
 	-D__STDC_LIMIT_MACROS				\
-	-I. 						\
+	-I.						\
 	-I..						\
 	-I$(COMMON_DIR)					\
 	-I$(COMMON_DIR)/linux				\
@@ -20,7 +20,6 @@ INCLUDES = \
 	$(PROTOCOL_CFLAGS)				\
 	$(GL_CFLAGS)					\
 	$(ALSA_CFLAGS)					\
-	$(FFMPEG_CFLAGS)				\
 	$(PIXMAN_CFLAGS)				\
 	$(LOG4CPP_CFLAGS)				\
 	$(CELT051_CFLAGS)				\
@@ -33,7 +32,7 @@ INCLUDES = \
 	$(NULL)
 
 
-RED_COMMON_SRCS = 					\
+RED_COMMON_SRCS =					\
 	$(CLIENT_DIR)/application.cpp			\
 	$(CLIENT_DIR)/application.h			\
 	$(CLIENT_DIR)/audio_channels.h			\
@@ -77,6 +76,8 @@ RED_COMMON_SRCS = 					\
 	$(CLIENT_DIR)/mem.cpp				\
 	$(CLIENT_DIR)/menu.cpp				\
 	$(CLIENT_DIR)/menu.h				\
+	$(CLIENT_DIR)/mjpeg_decoder.h			\
+	$(CLIENT_DIR)/mjpeg_decoder.cpp			\
 	$(CLIENT_DIR)/pixels_source.h			\
 	$(CLIENT_DIR)/pixman_utils.cpp			\
 	$(CLIENT_DIR)/platform.h			\
@@ -111,9 +112,9 @@ RED_COMMON_SRCS = 					\
 	$(CLIENT_DIR)/tunnel_channel.h			\
 	$(CLIENT_DIR)/utils.cpp				\
 	$(CLIENT_DIR)/utils.h				\
-	$(CLIENT_DIR)/icon.h                    	\
-	$(CLIENT_DIR)/gui/softrenderer.h        	\
-	$(CLIENT_DIR)/gui/softrenderer.cpp      	\
+	$(CLIENT_DIR)/icon.h				\
+	$(CLIENT_DIR)/gui/softrenderer.h		\
+	$(CLIENT_DIR)/gui/softrenderer.cpp		\
 	$(CLIENT_DIR)/gui/softtexture.h			\
 	$(CLIENT_DIR)/gui/softtexture.cpp		\
 	$(CLIENT_DIR)/gui/resource_provider.h		\
@@ -160,15 +161,14 @@ spicec_LDFLAGS = \
 	$(CELT051_LIBS)					\
 	$(SSL_LIBS)					\
 	$(CEGUI_LIBS)					\
+	$(JPEG_LIBS)					\
 	$(SPICE_NONPKGCONFIG_LIBS)
 
 spicec_LDADD =						\
 	$(PIXMAN_LIBS)					\
-	$(FFMPEG_LIBS)					\
 	$(ALSA_LIBS)					\
 	$(GL_LIBS)					\
 	$(XRANDR_LIBS)					\
 	$(MISC_X_LIBS)					\
 	$(CEGUI_LIBS)					\
 	-lrt
-
diff --git a/configure.ac b/configure.ac
index c68d849..c75a16d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -224,6 +224,19 @@ AS_IF([test "$_cxxflags_is_set" = "yes"], [], [
     CXXFLAGS="-g -O2"
 ])
 
+AC_CHECK_LIB(jpeg, jpeg_destroy_decompress,
+    AC_MSG_CHECKING([for jpeglib.h])
+    AC_TRY_CPP(
+[#include <stdio.h>
+#undef PACKAGE
+#undef VERSION
+#undef HAVE_STDLIB_H
+#include <jpeglib.h>],
+        JPEG_LIBS='-ljpeg'
+        AC_MSG_RESULT($jpeg_ok),
+	AC_MSG_ERROR([jpeglib.h not found])),
+    AC_MSG_ERROR([libjpeg not found]))
+AC_SUBST(JPEG_LIBS)
 
 dnl ===========================================================================
 dnl check compiler flags


More information about the Spice-commits mailing list