summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/display_channel.cpp1
-rw-r--r--client/mjpeg_decoder.cpp14
-rw-r--r--common/linux/ffmpeg_inc.h.in12
-rw-r--r--common/win/ffmpeg_inc.h4
-rw-r--r--configure.ac14
-rw-r--r--server/Makefile.am7
-rw-r--r--server/mjpeg_encoder.c125
-rw-r--r--server/mjpeg_encoder.h35
-rw-r--r--server/red_worker.c376
-rw-r--r--server/red_yuv.h159
10 files changed, 358 insertions, 389 deletions
diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 6427ae4d..9219568a 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 df0dbad0..cf3e44d3 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 7e322b51..00000000
--- a/common/linux/ffmpeg_inc.h.in
+++ /dev/null
@@ -1,12 +0,0 @@
-
-#ifdef __GNUG__
-extern "C" {
-#endif
-
-#include "@AVCODEC_PREFIX@avcodec.h"
-
-#ifdef __GNUG__
-}
-#endif
-
-
diff --git a/common/win/ffmpeg_inc.h b/common/win/ffmpeg_inc.h
deleted file mode 100644
index 8d4473ff..00000000
--- 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 c75a16d8..e1f0c8ee 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 d09e2d20..5c4524a5 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 00000000..b0ae49f6
--- /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 00000000..4c966ab3
--- /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 723f5427..6fdc4fee 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 756717d5..00000000
--- 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
-