--- server/gstreamer-encoder.c | 148 +++++++++++---------------------------------- 1 file changed, 36 insertions(+), 112 deletions(-) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index d5fa072..c9cd3fb 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -27,6 +27,7 @@ #include <gst/app/gstappsink.h> #include "red-common.h" +#include "red-chunk-iterator.h" #include "video-encoder.h" #include "utils.h" @@ -37,7 +38,6 @@ # define DO_ZERO_COPY #endif - typedef struct { SpiceBitmapFmt spice_format; char format[8]; @@ -1132,44 +1132,21 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder) return TRUE; } -/* A helper for the *_copy() functions */ -static int is_chunk_stride_aligned(const SpiceBitmap *bitmap, uint32_t index) -{ - SpiceChunks *chunks = bitmap->data; - if (chunks->chunk[index].len % bitmap->stride != 0) { - /* A line straddles two chunks. This is not supported */ - spice_warning("chunk %d/%d contains an incomplete line, cannot copy", - index, chunks->num_chunks); - return FALSE; - } - return TRUE; -} - /* A helper for push_raw_frame() */ static inline int line_copy(SpiceGstEncoder *encoder, const SpiceBitmap *bitmap, uint32_t chunk_offset, uint32_t stream_stride, uint32_t height, uint8_t *buffer) { uint8_t *dst = buffer; - SpiceChunks *chunks = bitmap->data; - uint32_t chunk_index = 0; + RedChunkIterator it; + + red_chunk_iterator_init(&it, bitmap->data); + red_chunk_iterator_skip_bytes(&it, chunk_offset); + g_assert(bitmap->stride >= stream_stride); for (int l = 0; l < height; l++) { - /* We may have to move forward by more than one chunk the first - * time around. This also protects us against 0-byte chunks. - */ - while (chunk_offset >= chunks->chunk[chunk_index].len) { - if (!is_chunk_stride_aligned(bitmap, chunk_index)) { - return FALSE; - } - chunk_offset -= chunks->chunk[chunk_index].len; - chunk_index++; - } - - /* Copy the line */ - uint8_t *src = chunks->chunk[chunk_index].data + chunk_offset; - memcpy(dst, src, stream_stride); + red_chunk_iterator_peek_data(&it, dst, stream_stride); dst += stream_stride; - chunk_offset += bitmap->stride; + red_chunk_iterator_skip_bytes(&it, bitmap->stride); } spice_return_val_if_fail(dst - buffer == stream_stride * height, FALSE); return TRUE; @@ -1214,56 +1191,34 @@ static void bitmap_wrapper_unref(gpointer data) /* A helper for push_raw_frame() */ -static inline int zero_copy(SpiceGstEncoder *encoder, - const SpiceBitmap *bitmap, gpointer bitmap_opaque, - GstBuffer *buffer, uint32_t *chunk_index, - uint32_t *chunk_offset, uint32_t *len) +static inline int zero_copy(SpiceGstEncoder *encoder, gpointer bitmap_opaque, + GstBuffer *buffer, RedChunkIterator *it, + uint32_t len) { - const SpiceChunks *chunks = bitmap->data; - while (*chunk_index < chunks->num_chunks && - *chunk_offset >= chunks->chunk[*chunk_index].len) { - if (!is_chunk_stride_aligned(bitmap, *chunk_index)) { - return FALSE; - } - *chunk_offset -= chunks->chunk[*chunk_index].len; - (*chunk_index)++; - } - int max_block_count = gst_buffer_get_max_memory(); - if (chunks->num_chunks - *chunk_index > max_block_count) { - /* There are more chunks than we can fit memory objects in a - * buffer. This will cause the buffer to merge memory objects to - * fit the extra chunks, which means doing wasteful memory copies. - * So use the zero-copy approach for the first max_mem-1 chunks, and - * let push_raw_frame() deal with the rest. - */ - max_block_count = *chunk_index + max_block_count - 1; - } else { - max_block_count = chunks->num_chunks; - } - BitmapWrapper *wrapper = NULL; - while (*len && *chunk_index < max_block_count) { - if (!is_chunk_stride_aligned(bitmap, *chunk_index)) { - return FALSE; - } + gsize copied_len = 0; + + for (unsigned int i = 0; i < max_block_count; i++) { if (wrapper) { g_atomic_int_inc(&wrapper->refs); } else { wrapper = bitmap_wrapper_new(encoder, bitmap_opaque); } - uint32_t thislen = MIN(chunks->chunk[*chunk_index].len - *chunk_offset, *len); - GstMemory *mem = gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, - chunks->chunk[*chunk_index].data, - chunks->chunk[*chunk_index].len, - *chunk_offset, thislen, - wrapper, bitmap_wrapper_unref); + GstMemory *mem = red_chunk_iterator_get_current_chunk_as_gst(it, len, wrapper, bitmap_wrapper_unref); + if (mem == NULL) { + /* We had less than "max_block_count" chunks, this is fine */ + break; + } gst_buffer_append_memory(buffer, mem); - *len -= thislen; - *chunk_offset = 0; - (*chunk_index)++; + + copied_len += gst_memory_get_sizes(mem, NULL, NULL); + len -= gst_memory_get_sizes(mem, NULL, NULL); + if (len == 0) { + break; + } } - return TRUE; + return copied_len; } #else static void clear_zero_copy_queue(SpiceGstEncoder *encoder, gboolean unref_queue) @@ -1272,39 +1227,6 @@ static void clear_zero_copy_queue(SpiceGstEncoder *encoder, gboolean unref_queue } #endif -/* A helper for push_raw_frame() */ -static inline int chunk_copy(SpiceGstEncoder *encoder, const SpiceBitmap *bitmap, - uint32_t chunk_index, uint32_t chunk_offset, - uint32_t len, uint8_t *dst) -{ - SpiceChunks *chunks = bitmap->data; - /* Skip chunks until we find the start of the frame */ - while (chunk_index < chunks->num_chunks && - chunk_offset >= chunks->chunk[chunk_index].len) { - if (!is_chunk_stride_aligned(bitmap, chunk_index)) { - return FALSE; - } - chunk_offset -= chunks->chunk[chunk_index].len; - chunk_index++; - } - - /* We can copy the frame chunk by chunk */ - while (len && chunk_index < chunks->num_chunks) { - if (!is_chunk_stride_aligned(bitmap, chunk_index)) { - return FALSE; - } - uint8_t *src = chunks->chunk[chunk_index].data + chunk_offset; - uint32_t thislen = MIN(chunks->chunk[chunk_index].len - chunk_offset, len); - memcpy(dst, src, thislen); - dst += thislen; - len -= thislen; - chunk_offset = 0; - chunk_index++; - } - spice_return_val_if_fail(len == 0, FALSE); - return TRUE; -} - #ifdef HAVE_GSTREAMER_0_10 /* Dummy structure to avoid too many #ifdef in the main codepaths */ typedef struct { @@ -1382,13 +1304,15 @@ static int push_raw_frame(SpiceGstEncoder *encoder, } } else { /* We can copy the bitmap chunk by chunk */ - uint32_t chunk_index = 0; -#ifdef DO_ZERO_COPY - if (!zero_copy(encoder, bitmap, bitmap_opaque, buffer, &chunk_index, - &chunk_offset, &len)) { - gst_buffer_unref(buffer); - return VIDEO_ENCODER_FRAME_UNSUPPORTED; + RedChunkIterator it; + red_chunk_iterator_init(&it, bitmap->data); + if (!red_chunk_iterator_skip_bytes(&it, chunk_offset)) { + return FALSE; } + +#ifdef DO_ZERO_COPY + len -= zero_copy(encoder, bitmap_opaque, buffer, &it, len); + /* len now contains the remaining number of bytes to copy. * However we must avoid any write to the GstBuffer object as it * would cause a copy of the read-only memory objects we just added. @@ -1401,8 +1325,8 @@ static int push_raw_frame(SpiceGstEncoder *encoder, if (!dst) { return VIDEO_ENCODER_FRAME_UNSUPPORTED; } - if (!chunk_copy(encoder, bitmap, chunk_index, chunk_offset, - len, dst)) { + len -= red_chunk_iterator_get_data(&it, dst, len); + if (len != 0) { unmap_and_release_memory(&map, buffer); return VIDEO_ENCODER_FRAME_UNSUPPORTED; } -- 2.7.4 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel