[Spice-devel] [spice-server 1/3] encoders: Introduce RedChunkIterator

Li Zhijian lizhijian at cn.fujitsu.com
Mon Sep 12 09:52:31 UTC 2016



On 09/09/2016 09:37 PM, Christophe Fergeau wrote:
> This will be used by the GStreamer/mjpeg encoders to get linear data out
> of a SpiceChunks (which is an array of (binary data, size)).
> ---
>  server/Makefile.am                     |   2 +
>  server/red-chunk-iterator.c            | 144 ++++++++++++++++++++++++++
>  server/red-chunk-iterator.h            |  46 +++++++++
>  server/tests/Makefile.am               |   9 +-
>  server/tests/test-red-chunk-iterator.c | 179 +++++++++++++++++++++++++++++++++
>  5 files changed, 378 insertions(+), 2 deletions(-)
>  create mode 100644 server/red-chunk-iterator.c
>  create mode 100644 server/red-chunk-iterator.h
>  create mode 100644 server/tests/test-red-chunk-iterator.c
>
> diff --git a/server/Makefile.am b/server/Makefile.am
> index d31a9e8..ac576c9 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -156,6 +156,8 @@ libserver_la_SOURCES =				\
>  	dcc-private.h				\
>  	image-encoders.c					\
>  	image-encoders.h					\
> +	red-chunk-iterator.c			\
> +	red-chunk-iterator.h			\
>  	$(NULL)
>
>  if HAVE_LZ4
> diff --git a/server/red-chunk-iterator.c b/server/red-chunk-iterator.c
> new file mode 100644
> index 0000000..07b05b2
> --- /dev/null
> +++ b/server/red-chunk-iterator.c
> @@ -0,0 +1,144 @@
> +/*
> +   Copyright (C) 2016 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see <http://www.gnu.org/licenses/>.
> +*/
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#if defined(HAVE_GSTREAMER_1_0)
> +#include <gst/gst.h>
> +#endif
> +
> +#include "red-chunk-iterator.h"
> +
> +void red_chunk_iterator_init(RedChunkIterator *chunk_iterator, SpiceChunks *chunks)
> +{
> +    memset(chunk_iterator, 0, sizeof(RedChunkIterator));
> +    chunk_iterator->chunks = chunks;
> +}
> +
> +static SpiceChunk *red_chunk_iterator_get_current_chunk(RedChunkIterator *chunk_iterator)
> +{
> +    if (chunk_iterator->chunks->num_chunks <= chunk_iterator->current_chunk_index)
> +    {
> +        return NULL;
> +    }
> +
> +    return &chunk_iterator->chunks->chunk[chunk_iterator->current_chunk_index];
> +}
> +
> +static SpiceChunk *red_chunk_iterator_next_chunk(RedChunkIterator *chunk_iterator)
> +{
> +    if (chunk_iterator->current_chunk_index < chunk_iterator->chunks->num_chunks) {
> +        chunk_iterator->current_chunk_index++;
> +    }
> +    chunk_iterator->current_chunk_offset = 0;
> +
> +    return red_chunk_iterator_get_current_chunk(chunk_iterator);
> +}
> +
> +gboolean red_chunk_iterator_skip_bytes(RedChunkIterator *chunk_iterator, gsize skip_bytes)
> +{
> +    SpiceChunk *current_chunk = red_chunk_iterator_get_current_chunk(chunk_iterator);
> +
> +    while ((current_chunk != NULL) && (skip_bytes >= current_chunk->len - chunk_iterator->current_chunk_offset)) {

This line seems exceed 100 characters


> +        skip_bytes -= (current_chunk->len - chunk_iterator->current_chunk_offset);
> +        current_chunk = red_chunk_iterator_next_chunk(chunk_iterator);
> +    }
> +    chunk_iterator->current_chunk_offset += skip_bytes;
> +    return (current_chunk != NULL);
> +}
> +
> +static gsize
> +red_chunk_iterator_get_data_one_chunk(RedChunkIterator *chunk_iterator, guint8 *dst, gsize bytes_count)
exceed 100 characters

if we can introduce the checkpatch.pl like QEMU would be cool. :)

Thanks
Zhijian

> +{
> +    SpiceChunk *current_chunk = red_chunk_iterator_get_current_chunk(chunk_iterator);
> +    uint8_t *src;
> +    gsize copied_len;
> +
> +    if (current_chunk == NULL) {
> +        return 0;
> +    }
> +    /* FIXME: check alignemnt ? */
> +    /* do some checks on bytes_count before copying */
> +    copied_len = MIN(bytes_count, current_chunk->len - chunk_iterator->current_chunk_offset);
> +    src = current_chunk->data + chunk_iterator->current_chunk_offset;
> +    memcpy(dst, src, copied_len);
> +    red_chunk_iterator_skip_bytes(chunk_iterator, copied_len);
> +
> +    return copied_len;
> +}
> +
> +gsize red_chunk_iterator_get_data(RedChunkIterator *chunk_iterator, guint8 *dst, gsize bytes_count)
> +{
> +    gsize total_copied = 0;
> +
> +    while (total_copied < bytes_count) {
> +        gsize copied_bytes;
> +
> +        copied_bytes = red_chunk_iterator_get_data_one_chunk(chunk_iterator, dst,
> +                                                             bytes_count - total_copied);
> +        if (copied_bytes == 0) {
> +            break;
> +        }
> +        total_copied += copied_bytes;
> +        dst += copied_bytes;
> +    }
> +
> +    return total_copied;
> +}
> +
> +gsize red_chunk_iterator_peek_data(RedChunkIterator *chunk_iterator, guint8 *dst, gsize bytes_count)
> +{
> +    const gsize initial_chunk_index = chunk_iterator->current_chunk_index;
> +    const gsize initial_chunk_offset = chunk_iterator->current_chunk_offset;
> +    gsize bytes_copied;
> +
> +    bytes_copied = red_chunk_iterator_get_data(chunk_iterator, dst, bytes_count);
> +
> +    chunk_iterator->current_chunk_index = initial_chunk_index;
> +    chunk_iterator->current_chunk_offset = initial_chunk_offset;
> +
> +    return bytes_copied;
> +}
> +
> +#if defined(HAVE_GSTREAMER_1_0)
> +GstMemory *red_chunk_iterator_get_current_chunk_as_gst(RedChunkIterator *chunk_iterator,
> +                                                       gsize bytes_count, gpointer user_data,
> +                                                       GDestroyNotify notify)
> +{
> +    SpiceChunk *current_chunk = red_chunk_iterator_get_current_chunk(chunk_iterator);
> +    GstMemory *memory;
> +    gsize data_len;
> +
> +    if (current_chunk == NULL) {
> +        return NULL;
> +    }
> +
> +    data_len = current_chunk->len - chunk_iterator->current_chunk_offset;
> +    if (bytes_count != 0) {
> +        data_len = MIN(data_len, bytes_count);
> +    }
> +    memory = gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY,
> +                                    current_chunk->data,
> +                                    current_chunk->len,
> +                                    chunk_iterator->current_chunk_offset, data_len,
> +                                    user_data, notify);
> +    red_chunk_iterator_skip_bytes(chunk_iterator, data_len);
> +
> +    return memory;
> +}
> +#endif
> diff --git a/server/red-chunk-iterator.h b/server/red-chunk-iterator.h
> new file mode 100644
> index 0000000..54b23c8
> --- /dev/null
> +++ b/server/red-chunk-iterator.h
> @@ -0,0 +1,46 @@
> +/*
> +   Copyright (C) 2016 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see <http://www.gnu.org/licenses/>.
> +*/
> +
> +#ifndef _H_RED_CHUNK_ITERATOR
> +#define _H_RED_CHUNK_ITERATOR
> +
> +#if defined(HAVE_GSTREAMER_1_0)
> +#include <gst/gst.h>
> +#endif
> +
> +#include "red-channel.h"
> +#include "spice-qxl.h"
> +
> +typedef struct RedChunkIterator RedChunkIterator;
> +
> +typedef struct RedChunkIterator {
> +    SpiceChunks *chunks;
> +    gsize current_chunk_index; /* Index of the chunk to use */
> +    gsize current_chunk_offset; /* Byte offset within current chunk */
> +} RedChunkIterator;
> +
> +void red_chunk_iterator_init(RedChunkIterator *chunk_iterator, SpiceChunks *chunks);
> +gboolean red_chunk_iterator_skip_bytes(RedChunkIterator *chunk_iterator, gsize skip_bytes);
> +gsize red_chunk_iterator_get_data(RedChunkIterator *chunk_iterator, guint8 *dst, gsize bytes_count);
> +gsize red_chunk_iterator_peek_data(RedChunkIterator *chunk_iterator, guint8 *dst, gsize bytes_count);
> +#if defined(HAVE_GSTREAMER_1_0)
> +GstMemory *red_chunk_iterator_get_current_chunk_as_gst(RedChunkIterator *chunk_iterator,
> +                                                       gsize bytes_count, gpointer user_data,
> +                                                       GDestroyNotify notify);
> +#endif
> +
> +#endif
> diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
> index 59a1fac..4c911f5 100644
> --- a/server/tests/Makefile.am
> +++ b/server/tests/Makefile.am
> @@ -8,7 +8,9 @@ AM_CPPFLAGS =					\
>  	-I$(top_srcdir)/server/tests		\
>  	$(COMMON_CFLAGS)			\
>  	$(GLIB2_CFLAGS)				\
> -	$(GOBJECT2_CFLAGS)				\
> +	$(GOBJECT2_CFLAGS)			\
> +	$(GSTREAMER_0_10_CFLAGS)		\
> +	$(GSTREAMER_1_0_CFLAGS)			\
>  	$(SMARTCARD_CFLAGS)			\
>  	$(SPICE_NONPKGCONFIG_CFLAGS)		\
>  	$(SPICE_PROTOCOL_CFLAGS)		\
> @@ -33,7 +35,9 @@ LDADD =								\
>  	$(top_builddir)/server/libserver.la			\
>  	$(GLIB2_LIBS)						\
>  	$(GOBJECT2_LIBS)					\
> -	$(SPICE_NONPKGCONFIG_LIBS)		                \
> +	$(GSTREAMER_0_10_LIBS)					\
> +	$(GSTREAMER_1_0_LIBS)					\
> +	$(SPICE_NONPKGCONFIG_LIBS)				\
>  	$(NULL)
>
>  TESTS =						\
> @@ -42,6 +46,7 @@ TESTS =						\
>  	stream-test				\
>  	test-loop				\
>  	test-qxl-parsing			\
> +	test-red-chunk-iterator			\
>  	$(NULL)
>
>  noinst_PROGRAMS =				\
> diff --git a/server/tests/test-red-chunk-iterator.c b/server/tests/test-red-chunk-iterator.c
> new file mode 100644
> index 0000000..93d8646
> --- /dev/null
> +++ b/server/tests/test-red-chunk-iterator.c
> @@ -0,0 +1,179 @@
> +/*
> +   Copyright (C) 2016 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library 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
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see <http://www.gnu.org/licenses/>.
> +*/
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <glib.h>
> +
> +#include "red-chunk-iterator.h"
> +
> +typedef struct { uint32_t len; uint8_t data[5]; } TestChunk;
> +
> +static gboolean spice_chunks_add_chunk(SpiceChunks *chunks, gsize chunk_index,
> +                                       uint8_t data[], gsize len)
> +{
> +    if (chunk_index >= chunks->num_chunks) {
> +        return FALSE;
> +    }
> +    //g_warn_if_fail(chunks->chunk[chunk_index].len == 0);
> +
> +    chunks->chunk[chunk_index].len = len;
> +    chunks->chunk[chunk_index].data = data;
> +    chunks->data_size += len;
> +
> +    return TRUE;
> +}
> +
> +
> +TestChunk test_chunks[4] = {
> +    { .len = 3, .data = { 0x01, 0x02, 0x03 } },
> +    { .len = 1, .data = { 0x04 } },
> +    { .len = 5, .data = { 0x05, 0x06, 0x07, 0x08, 0x09 } },
> +    { .len = 2, .data = { 0x0a, 0x0b } },
> +};
> +
> +static SpiceChunks *build_test_chunks(void)
> +{
> +    SpiceChunks *chunks;
> +    gsize num_chunks = G_N_ELEMENTS(test_chunks);
> +
> +    chunks = spice_chunks_new(num_chunks);
> +    chunks->data_size = 0;
> +    for (unsigned int i = 0; i < num_chunks; i++) {
> +        spice_chunks_add_chunk(chunks, i, test_chunks[i].data, test_chunks[i].len);
> +    }
> +
> +    return chunks;
> +}
> +
> +static void check_iterator_read(RedChunkIterator *iterator, guint skipped_count, guint read_size)
> +{
> +    unsigned int current_val = skipped_count + 1;
> +
> +    while (current_val < iterator->chunks->data_size) {
> +        uint8_t data[read_size];
> +        gsize copied;
> +
> +        copied = red_chunk_iterator_get_data(iterator, data, read_size);
> +        g_assert_cmpuint(copied, <=, read_size);
> +        if (copied != read_size) {
> +            g_assert_cmpuint(current_val - 1 + copied, ==, iterator->chunks->data_size);
> +        }
> +        for (unsigned int i = 0; i < copied; i++) {
> +            g_assert_cmpuint(current_val, ==, data[i]);
> +            current_val++;
> +        }
> +    }
> +}
> +
> +static void test_red_chunk_iterator(void)
> +{
> +    SpiceChunks *chunks;
> +
> +    chunks = build_test_chunks();
> +
> +    for (unsigned int skip = 0; skip <= chunks->data_size; skip++) {
> +        for (unsigned int read_size = 1; read_size <= chunks->data_size; read_size++) {
> +            RedChunkIterator iterator;
> +            red_chunk_iterator_init(&iterator, chunks);
> +
> +            red_chunk_iterator_skip_bytes(&iterator, skip);
> +            check_iterator_read(&iterator, skip, 3);
> +        }
> +    }
> +
> +    spice_chunks_destroy(chunks);
> +}
> +
> +static void test_red_chunk_iterator_skip(void)
> +{
> +    SpiceChunks *chunks;
> +    RedChunkIterator iterator;
> +
> +    chunks = build_test_chunks();
> +
> +    red_chunk_iterator_init(&iterator, chunks);
> +    red_chunk_iterator_skip_bytes(&iterator, 1);
> +    red_chunk_iterator_skip_bytes(&iterator, 3);
> +    check_iterator_read(&iterator, 4, 3);
> +
> +    red_chunk_iterator_init(&iterator, chunks);
> +    red_chunk_iterator_skip_bytes(&iterator, 1);
> +    red_chunk_iterator_skip_bytes(&iterator, 1);
> +    red_chunk_iterator_skip_bytes(&iterator, 3);
> +    check_iterator_read(&iterator, 5, 3);
> +
> +    red_chunk_iterator_init(&iterator, chunks);
> +    red_chunk_iterator_skip_bytes(&iterator, 1);
> +    red_chunk_iterator_skip_bytes(&iterator, 4);
> +    check_iterator_read(&iterator, 5, 3);
> +
> +    red_chunk_iterator_init(&iterator, chunks);
> +    red_chunk_iterator_skip_bytes(&iterator, 1);
> +    red_chunk_iterator_skip_bytes(&iterator, 5);
> +    check_iterator_read(&iterator, 6, 3);
> +
> +    spice_chunks_destroy(chunks);
> +}
> +
> +#if defined(HAVE_GSTREAMER_1_0)
> +static void test_red_chunk_iterator_gst(void)
> +{
> +    SpiceChunks *chunks;
> +    RedChunkIterator iterator;
> +
> +    chunks = build_test_chunks();
> +
> +    red_chunk_iterator_init(&iterator, chunks);
> +    red_chunk_iterator_skip_bytes(&iterator, 1);
> +
> +    for (unsigned int i = 0; i < G_N_ELEMENTS(test_chunks); i++) {
> +        GstMemory *memory;
> +        GstMapInfo info;
> +        gsize offset = 0;
> +
> +        if (i == 0) {
> +            offset = 1;
> +        }
> +        memory = red_chunk_iterator_get_current_chunk_as_gst(&iterator, 0, NULL, NULL);
> +        g_assert_true(gst_memory_map(memory, &info, GST_MAP_READ));
> +        g_assert_cmpuint(test_chunks[i].len - offset, ==, info.size);
> +        g_assert_cmpuint(memcmp(test_chunks[i].data + offset, info.data, info.size), ==, 0);
> +        gst_memory_unmap(memory, &info);
> +        gst_memory_unref(memory);
> +    }
> +
> +    spice_chunks_destroy(chunks);
> +}
> +#endif
> +
> +int main(int argc, char **argv)
> +{
> +#if defined(HAVE_GSTREAMER_1_0)
> +    gst_init(&argc, &argv);
> +#endif
> +    g_test_init(&argc, &argv, NULL);
> +
> +    g_test_add_func("/spice-server/red-chunk-iterator", test_red_chunk_iterator);
> +    g_test_add_func("/spice-server/red-chunk-iterator-skip", test_red_chunk_iterator_skip);
> +#if defined(HAVE_GSTREAMER_1_0) || defined(HAVE_GSTREAMER_0_10)
> +    g_test_add_func("/spice-server/red-chunk-iterator-gst", test_red_chunk_iterator_gst);
> +#endif
> +
> +    return g_test_run();
> +}
>

-- 
Best regards.
Li Zhijian (8555)




More information about the Spice-devel mailing list