Initialize _kill_mark so we don't get spurious valgrind warnings

This commit is contained in:
Alexander Larsson 2010-04-08 17:09:32 +02:00
parent 18485cef06
commit de4306af33
10 changed files with 359 additions and 390 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -1,12 +0,0 @@
#ifdef __GNUG__
extern "C" {
#endif
#include "@AVCODEC_PREFIX@avcodec.h"
#ifdef __GNUG__
}
#endif

View File

@ -1,4 +0,0 @@
extern "C" {
#include "libavcodec/avcodec.h"
}

View File

@ -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

View File

@ -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 \

125
server/mjpeg_encoder.c Normal file
View File

@ -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;
}

35
server/mjpeg_encoder.h Normal file
View File

@ -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

View File

@ -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;
#define YUV24
#include "red_yuv.h"
#undef YUV24
offset = 0;
chunk = (QXLDataChunk *)(image->data + phys_delta);
image_stride = image->stride;
#define YUV16
#include "red_yuv.h"
#undef YUV16
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;
}
return TRUE;
}
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) {
uint8_t *new_buf;
new_buf = spice_malloc(min_buf_size + FF_INPUT_BUFFER_PADDING_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_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);

View File

@ -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