9 #define MARKER_CHAR 0xff
10 #define STUFF_MARKER 0x00
12 int unstuff_reference(uint8_t* dst, const uint8_t* src, size_t len)
14 size_t bytes_written = 0;
16 for (unsigned i = 0; i < len; ++i, ++dst, ++src, ++bytes_written) {
18 if (*src == MARKER_CHAR) {
19 if (i == len - 1 || src[1] != STUFF_MARKER) {
23 // Skip the stuff byte.
28 assert(bytes_written <= len);
32 int unstuff_fast(uint8_t* dst, const uint8_t* src, size_t len)
34 size_t bytes_read = 0;
35 size_t bytes_written = 0;
37 while (len - bytes_read >= 0) {
38 // Find the first marker byte in the rest of the stream.
39 const uint8_t* ptr = memchr(src, MARKER_CHAR, len - bytes_read);
41 // No marker bytes left.
42 size_t len_to_copy = len - bytes_read;
43 memcpy(dst, src, len_to_copy);
44 bytes_written += len_to_copy;
48 const size_t len_to_copy = ptr - src + 1;
49 memcpy(dst, src, len_to_copy);
53 bytes_read += len_to_copy;
54 bytes_written += len_to_copy;
56 assert(bytes_read <= len);
57 if (bytes_read == len) {
61 if (*src != STUFF_MARKER) {
72 int unstuff_sse41(uint8_t* dst, const uint8_t* src, size_t len)
74 __m128i marker_search = _mm_set1_epi8(MARKER_CHAR);
76 size_t bytes_read = 0;
77 size_t bytes_written = 0;
78 while (len - bytes_read >= 16) {
79 __m128i data = _mm_lddqu_si128((const __m128i*)src);
81 // The store here is safe (if there's stuff bytes, the data
82 // will simply get overwritten in the slow path); fire it off
83 // here so it can run in parallel with the compare.
84 _mm_storeu_si128((__m128i*)dst, data);
86 __m128i eq_mask = _mm_cmpeq_epi8(data, marker_search);
87 if (_mm_test_all_zeros(eq_mask, eq_mask)) {
88 // Fast path; no stuff byte found.
96 // We found a stuff byte. If it was the last byte, we just
97 // defer that to the next chunk. Apart from that, we just keep
98 // going one by one byte. We could perhaps speed this up with
99 // the data from eq_mask(), but we're not doing that yet.
100 size_t len_this_chunk = (src[15] == 0xff ? 15 : 16);
101 for (unsigned j = 0; j < len_this_chunk; ++j, ++dst, ++src, ++bytes_written) {
104 if (*src == MARKER_CHAR) {
106 if (src[1] != STUFF_MARKER) {
110 // Skip the stuff byte.
114 bytes_read += len_this_chunk;
117 // Do the final bytes via the reference path.
118 int ret = unstuff_reference(dst, src, len - bytes_read);
122 return bytes_written + ret;