Coverage Report

Created: 2026-08-13 07:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/packetizer/startcode_helper.h
Line
Count
Source
1
/*****************************************************************************
2
 * startcode_helper.h: Startcodes helpers
3
 *****************************************************************************
4
 * Copyright (C) 2016 VideoLAN Authors
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as published by
8
 * the Free Software Foundation; either version 2.1 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with this program; if not, write to the Free Software Foundation,
18
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19
 *****************************************************************************/
20
#ifndef VLC_STARTCODE_HELPER_H_
21
#define VLC_STARTCODE_HELPER_H_
22
23
#include <vlc_cpu.h>
24
25
#ifdef CAN_COMPILE_SSE2
26
#  if defined __has_attribute
27
#    if __has_attribute(__vector_size__)
28
#      define HAS_ATTRIBUTE_VECTORSIZE
29
#    endif
30
#  endif
31
32
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
33
    typedef unsigned char v16qu __attribute__((__vector_size__(16)));
34
#  endif
35
#endif
36
37
/* Looks up efficiently for an AnnexB startcode 0x00 0x00 0x01
38
 * by using a 4 times faster trick than single byte lookup. */
39
40
2.34G
#define TRY_MATCH(p,a) {\
41
2.34G
     if (p[a+1] == 0) {\
42
1.32G
            if (p[a+0] == 0 && p[a+2] == 1)\
43
1.32G
                return a+p;\
44
1.32G
            if (p[a+2] == 0 && p[a+3] == 1)\
45
1.32G
                return a+p+1;\
46
1.32G
        }\
47
2.34G
        if (p[a+3] == 0) {\
48
1.19G
            if (p[a+2] == 0 && p[a+4] == 1)\
49
1.19G
                return a+p+2;\
50
1.19G
            if (p[a+4] == 0 && p[a+5] == 1)\
51
1.19G
                return a+p+3;\
52
1.19G
        }\
53
2.33G
    }
54
55
#ifdef CAN_COMPILE_SSE2
56
57
__attribute__ ((__target__ ("sse2")))
58
static inline const uint8_t * startcode_FindAnnexB_SSE2( const uint8_t *p, const uint8_t *end )
59
97.5M
{
60
    /* First align to 16 */
61
    /* Skipping this step and doing unaligned loads isn't faster */
62
97.5M
    const uint8_t *alignedend = p + 16 - ((intptr_t)p & 15);
63
985M
    for (end -= 3; p < alignedend && p <= end; p++) {
64
908M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
65
20.7M
            return p;
66
908M
    }
67
68
76.8M
    if( p == end )
69
102k
        return NULL;
70
71
76.7M
    alignedend = end - ((intptr_t) end & 15);
72
76.7M
    if( alignedend > p )
73
56.3M
    {
74
56.3M
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
75
56.3M
        const v16qu zeros = { 0 };
76
56.3M
#  endif
77
78
1.75G
        for( ; p < alignedend; p += 16)
79
1.70G
        {
80
1.70G
            uint32_t match;
81
1.70G
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
82
1.70G
            asm volatile(
83
1.70G
                "movdqa   0(%[v]),   %%xmm0\n"
84
1.70G
                "pcmpeqb %[czero],   %%xmm0\n"
85
1.70G
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
86
1.70G
                : [match]"=r"(match)
87
1.70G
                : [v]"r"(p), [czero]"x"(zeros)
88
1.70G
                : "xmm0"
89
1.70G
            );
90
#  else
91
            asm volatile(
92
                "movdqa   0(%[v]),   %%xmm0\n"
93
                "pxor      %%xmm1,   %%xmm1\n"
94
                "pcmpeqb   %%xmm1,   %%xmm0\n"
95
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
96
                : [match]"=r"(match)
97
                : [v]"r"(p)
98
                : "xmm0", "xmm1"
99
            );
100
#  endif
101
1.70G
            if( match & 0x000F )
102
1.70G
                TRY_MATCH(p, 0);
103
1.70G
            if( match & 0x00F0 )
104
1.70G
                TRY_MATCH(p, 4);
105
1.70G
            if( match & 0x0F00 )
106
1.70G
                TRY_MATCH(p, 8);
107
1.70G
            if( match & 0xF000 )
108
1.70G
                TRY_MATCH(p, 12);
109
1.70G
        }
110
56.3M
    }
111
112
647M
    for (; p <= end; p++) {
113
576M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
114
102k
            return p;
115
576M
    }
116
117
71.4M
    return NULL;
118
71.5M
}
h264.c:startcode_FindAnnexB_SSE2
Line
Count
Source
59
5.18M
{
60
    /* First align to 16 */
61
    /* Skipping this step and doing unaligned loads isn't faster */
62
5.18M
    const uint8_t *alignedend = p + 16 - ((intptr_t)p & 15);
63
43.1M
    for (end -= 3; p < alignedend && p <= end; p++) {
64
39.7M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
65
1.74M
            return p;
66
39.7M
    }
67
68
3.43M
    if( p == end )
69
75.7k
        return NULL;
70
71
3.36M
    alignedend = end - ((intptr_t) end & 15);
72
3.36M
    if( alignedend > p )
73
3.11M
    {
74
3.11M
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
75
3.11M
        const v16qu zeros = { 0 };
76
3.11M
#  endif
77
78
168M
        for( ; p < alignedend; p += 16)
79
166M
        {
80
166M
            uint32_t match;
81
166M
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
82
166M
            asm volatile(
83
166M
                "movdqa   0(%[v]),   %%xmm0\n"
84
166M
                "pcmpeqb %[czero],   %%xmm0\n"
85
166M
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
86
166M
                : [match]"=r"(match)
87
166M
                : [v]"r"(p), [czero]"x"(zeros)
88
166M
                : "xmm0"
89
166M
            );
90
#  else
91
            asm volatile(
92
                "movdqa   0(%[v]),   %%xmm0\n"
93
                "pxor      %%xmm1,   %%xmm1\n"
94
                "pcmpeqb   %%xmm1,   %%xmm0\n"
95
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
96
                : [match]"=r"(match)
97
                : [v]"r"(p)
98
                : "xmm0", "xmm1"
99
            );
100
#  endif
101
166M
            if( match & 0x000F )
102
166M
                TRY_MATCH(p, 0);
103
166M
            if( match & 0x00F0 )
104
166M
                TRY_MATCH(p, 4);
105
166M
            if( match & 0x0F00 )
106
165M
                TRY_MATCH(p, 8);
107
165M
            if( match & 0xF000 )
108
165M
                TRY_MATCH(p, 12);
109
165M
        }
110
3.11M
    }
111
112
26.1M
    for (; p <= end; p++) {
113
23.9M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
114
20.2k
            return p;
115
23.9M
    }
116
117
2.16M
    return NULL;
118
2.18M
}
Unexecuted instantiation: hxxx_sei.c:startcode_FindAnnexB_SSE2
Unexecuted instantiation: h264_nal.c:startcode_FindAnnexB_SSE2
Unexecuted instantiation: h264_slice.c:startcode_FindAnnexB_SSE2
hevc.c:startcode_FindAnnexB_SSE2
Line
Count
Source
59
23.2M
{
60
    /* First align to 16 */
61
    /* Skipping this step and doing unaligned loads isn't faster */
62
23.2M
    const uint8_t *alignedend = p + 16 - ((intptr_t)p & 15);
63
107M
    for (end -= 3; p < alignedend && p <= end; p++) {
64
98.0M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
65
13.9M
            return p;
66
98.0M
    }
67
68
9.33M
    if( p == end )
69
3.23k
        return NULL;
70
71
9.32M
    alignedend = end - ((intptr_t) end & 15);
72
9.32M
    if( alignedend > p )
73
5.37M
    {
74
5.37M
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
75
5.37M
        const v16qu zeros = { 0 };
76
5.37M
#  endif
77
78
418M
        for( ; p < alignedend; p += 16)
79
415M
        {
80
415M
            uint32_t match;
81
415M
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
82
415M
            asm volatile(
83
415M
                "movdqa   0(%[v]),   %%xmm0\n"
84
415M
                "pcmpeqb %[czero],   %%xmm0\n"
85
415M
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
86
415M
                : [match]"=r"(match)
87
415M
                : [v]"r"(p), [czero]"x"(zeros)
88
415M
                : "xmm0"
89
415M
            );
90
#  else
91
            asm volatile(
92
                "movdqa   0(%[v]),   %%xmm0\n"
93
                "pxor      %%xmm1,   %%xmm1\n"
94
                "pcmpeqb   %%xmm1,   %%xmm0\n"
95
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
96
                : [match]"=r"(match)
97
                : [v]"r"(p)
98
                : "xmm0", "xmm1"
99
            );
100
#  endif
101
415M
            if( match & 0x000F )
102
414M
                TRY_MATCH(p, 0);
103
414M
            if( match & 0x00F0 )
104
413M
                TRY_MATCH(p, 4);
105
413M
            if( match & 0x0F00 )
106
413M
                TRY_MATCH(p, 8);
107
413M
            if( match & 0xF000 )
108
413M
                TRY_MATCH(p, 12);
109
413M
        }
110
5.37M
    }
111
112
55.5M
    for (; p <= end; p++) {
113
48.1M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
114
21.5k
            return p;
115
48.1M
    }
116
117
7.41M
    return NULL;
118
7.43M
}
Unexecuted instantiation: hevc_nal.c:startcode_FindAnnexB_SSE2
mpeg4video.c:startcode_FindAnnexB_SSE2
Line
Count
Source
59
2.41M
{
60
    /* First align to 16 */
61
    /* Skipping this step and doing unaligned loads isn't faster */
62
2.41M
    const uint8_t *alignedend = p + 16 - ((intptr_t)p & 15);
63
15.4M
    for (end -= 3; p < alignedend && p <= end; p++) {
64
13.6M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
65
604k
            return p;
66
13.6M
    }
67
68
1.80M
    if( p == end )
69
1.02k
        return NULL;
70
71
1.80M
    alignedend = end - ((intptr_t) end & 15);
72
1.80M
    if( alignedend > p )
73
924k
    {
74
924k
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
75
924k
        const v16qu zeros = { 0 };
76
924k
#  endif
77
78
5.00M
        for( ; p < alignedend; p += 16)
79
4.49M
        {
80
4.49M
            uint32_t match;
81
4.49M
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
82
4.49M
            asm volatile(
83
4.49M
                "movdqa   0(%[v]),   %%xmm0\n"
84
4.49M
                "pcmpeqb %[czero],   %%xmm0\n"
85
4.49M
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
86
4.49M
                : [match]"=r"(match)
87
4.49M
                : [v]"r"(p), [czero]"x"(zeros)
88
4.49M
                : "xmm0"
89
4.49M
            );
90
#  else
91
            asm volatile(
92
                "movdqa   0(%[v]),   %%xmm0\n"
93
                "pxor      %%xmm1,   %%xmm1\n"
94
                "pcmpeqb   %%xmm1,   %%xmm0\n"
95
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
96
                : [match]"=r"(match)
97
                : [v]"r"(p)
98
                : "xmm0", "xmm1"
99
            );
100
#  endif
101
4.49M
            if( match & 0x000F )
102
4.37M
                TRY_MATCH(p, 0);
103
4.37M
            if( match & 0x00F0 )
104
4.26M
                TRY_MATCH(p, 4);
105
4.26M
            if( match & 0x0F00 )
106
4.16M
                TRY_MATCH(p, 8);
107
4.16M
            if( match & 0xF000 )
108
4.08M
                TRY_MATCH(p, 12);
109
4.08M
        }
110
924k
    }
111
112
8.31M
    for (; p <= end; p++) {
113
6.93M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
114
6.76k
            return p;
115
6.93M
    }
116
117
1.38M
    return NULL;
118
1.39M
}
mpegvideo.c:startcode_FindAnnexB_SSE2
Line
Count
Source
59
66.1M
{
60
    /* First align to 16 */
61
    /* Skipping this step and doing unaligned loads isn't faster */
62
66.1M
    const uint8_t *alignedend = p + 16 - ((intptr_t)p & 15);
63
817M
    for (end -= 3; p < alignedend && p <= end; p++) {
64
755M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
65
4.20M
            return p;
66
755M
    }
67
68
61.9M
    if( p == end )
69
22.7k
        return NULL;
70
71
61.9M
    alignedend = end - ((intptr_t) end & 15);
72
61.9M
    if( alignedend > p )
73
46.7M
    {
74
46.7M
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
75
46.7M
        const v16qu zeros = { 0 };
76
46.7M
#  endif
77
78
1.15G
        for( ; p < alignedend; p += 16)
79
1.11G
        {
80
1.11G
            uint32_t match;
81
1.11G
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
82
1.11G
            asm volatile(
83
1.11G
                "movdqa   0(%[v]),   %%xmm0\n"
84
1.11G
                "pcmpeqb %[czero],   %%xmm0\n"
85
1.11G
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
86
1.11G
                : [match]"=r"(match)
87
1.11G
                : [v]"r"(p), [czero]"x"(zeros)
88
1.11G
                : "xmm0"
89
1.11G
            );
90
#  else
91
            asm volatile(
92
                "movdqa   0(%[v]),   %%xmm0\n"
93
                "pxor      %%xmm1,   %%xmm1\n"
94
                "pcmpeqb   %%xmm1,   %%xmm0\n"
95
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
96
                : [match]"=r"(match)
97
                : [v]"r"(p)
98
                : "xmm0", "xmm1"
99
            );
100
#  endif
101
1.11G
            if( match & 0x000F )
102
1.11G
                TRY_MATCH(p, 0);
103
1.11G
            if( match & 0x00F0 )
104
1.11G
                TRY_MATCH(p, 4);
105
1.11G
            if( match & 0x0F00 )
106
1.11G
                TRY_MATCH(p, 8);
107
1.11G
            if( match & 0xF000 )
108
1.11G
                TRY_MATCH(p, 12);
109
1.11G
        }
110
46.7M
    }
111
112
557M
    for (; p <= end; p++) {
113
496M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
114
53.8k
            return p;
115
496M
    }
116
117
60.3M
    return NULL;
118
60.4M
}
vc1.c:startcode_FindAnnexB_SSE2
Line
Count
Source
59
486k
{
60
    /* First align to 16 */
61
    /* Skipping this step and doing unaligned loads isn't faster */
62
486k
    const uint8_t *alignedend = p + 16 - ((intptr_t)p & 15);
63
2.43M
    for (end -= 3; p < alignedend && p <= end; p++) {
64
2.18M
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
65
236k
            return p;
66
2.18M
    }
67
68
250k
    if( p == end )
69
0
        return NULL;
70
71
250k
    alignedend = end - ((intptr_t) end & 15);
72
250k
    if( alignedend > p )
73
246k
    {
74
246k
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
75
246k
        const v16qu zeros = { 0 };
76
246k
#  endif
77
78
4.38M
        for( ; p < alignedend; p += 16)
79
4.31M
        {
80
4.31M
            uint32_t match;
81
4.31M
#  ifdef HAS_ATTRIBUTE_VECTORSIZE
82
4.31M
            asm volatile(
83
4.31M
                "movdqa   0(%[v]),   %%xmm0\n"
84
4.31M
                "pcmpeqb %[czero],   %%xmm0\n"
85
4.31M
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
86
4.31M
                : [match]"=r"(match)
87
4.31M
                : [v]"r"(p), [czero]"x"(zeros)
88
4.31M
                : "xmm0"
89
4.31M
            );
90
#  else
91
            asm volatile(
92
                "movdqa   0(%[v]),   %%xmm0\n"
93
                "pxor      %%xmm1,   %%xmm1\n"
94
                "pcmpeqb   %%xmm1,   %%xmm0\n"
95
                "pmovmskb  %%xmm0,   %[match]\n" /* mask will be in reversed match order */
96
                : [match]"=r"(match)
97
                : [v]"r"(p)
98
                : "xmm0", "xmm1"
99
            );
100
#  endif
101
4.31M
            if( match & 0x000F )
102
4.26M
                TRY_MATCH(p, 0);
103
4.26M
            if( match & 0x00F0 )
104
4.21M
                TRY_MATCH(p, 4);
105
4.21M
            if( match & 0x0F00 )
106
4.17M
                TRY_MATCH(p, 8);
107
4.17M
            if( match & 0xF000 )
108
4.13M
                TRY_MATCH(p, 12);
109
4.13M
        }
110
246k
    }
111
112
370k
    for (; p <= end; p++) {
113
296k
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
114
386
            return p;
115
296k
    }
116
117
74.5k
    return NULL;
118
74.8k
}
119
120
#endif
121
122
/* That code is adapted from libav's ff_avc_find_startcode_internal
123
 * and i believe the trick originated from
124
 * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
125
 */
126
static inline const uint8_t * startcode_FindAnnexB_Bits( const uint8_t *p, const uint8_t *end )
127
0
{
128
0
    const uint8_t *a = p + 4 - ((intptr_t)p & 3);
129
130
0
    for (end -= 3; p < a && p <= end; p++) {
131
0
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
132
0
            return p;
133
0
    }
134
135
0
    for (end -= 3; p < end; p += 4) {
136
0
        uint32_t x;
137
0
        memcpy(&x, p, sizeof(x));
138
0
        if ((x - 0x01010101) & (~x) & 0x80808080)
139
0
        {
140
            /* matching DW isn't faster */
141
0
            TRY_MATCH(p, 0);
142
0
        }
143
0
    }
144
145
0
    for (end += 3; p <= end; p++) {
146
0
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
147
0
            return p;
148
0
    }
149
150
0
    return NULL;
151
0
}
Unexecuted instantiation: h264.c:startcode_FindAnnexB_Bits
Unexecuted instantiation: hxxx_sei.c:startcode_FindAnnexB_Bits
Unexecuted instantiation: h264_nal.c:startcode_FindAnnexB_Bits
Unexecuted instantiation: h264_slice.c:startcode_FindAnnexB_Bits
Unexecuted instantiation: hevc.c:startcode_FindAnnexB_Bits
Unexecuted instantiation: hevc_nal.c:startcode_FindAnnexB_Bits
Unexecuted instantiation: mpeg4video.c:startcode_FindAnnexB_Bits
Unexecuted instantiation: mpegvideo.c:startcode_FindAnnexB_Bits
Unexecuted instantiation: vc1.c:startcode_FindAnnexB_Bits
152
#undef TRY_MATCH
153
154
#ifdef CAN_COMPILE_SSE2
155
static inline const uint8_t * startcode_FindAnnexB( const uint8_t *p, const uint8_t *end )
156
97.5M
{
157
97.5M
    if (vlc_CPU_SSE2())
158
97.5M
        return startcode_FindAnnexB_SSE2(p, end);
159
0
    else
160
0
        return startcode_FindAnnexB_Bits(p, end);
161
97.5M
}
h264.c:startcode_FindAnnexB
Line
Count
Source
156
5.18M
{
157
5.18M
    if (vlc_CPU_SSE2())
158
5.18M
        return startcode_FindAnnexB_SSE2(p, end);
159
0
    else
160
0
        return startcode_FindAnnexB_Bits(p, end);
161
5.18M
}
Unexecuted instantiation: hxxx_sei.c:startcode_FindAnnexB
Unexecuted instantiation: h264_nal.c:startcode_FindAnnexB
Unexecuted instantiation: h264_slice.c:startcode_FindAnnexB
hevc.c:startcode_FindAnnexB
Line
Count
Source
156
23.2M
{
157
23.2M
    if (vlc_CPU_SSE2())
158
23.2M
        return startcode_FindAnnexB_SSE2(p, end);
159
0
    else
160
0
        return startcode_FindAnnexB_Bits(p, end);
161
23.2M
}
Unexecuted instantiation: hevc_nal.c:startcode_FindAnnexB
mpeg4video.c:startcode_FindAnnexB
Line
Count
Source
156
2.41M
{
157
2.41M
    if (vlc_CPU_SSE2())
158
2.41M
        return startcode_FindAnnexB_SSE2(p, end);
159
0
    else
160
0
        return startcode_FindAnnexB_Bits(p, end);
161
2.41M
}
mpegvideo.c:startcode_FindAnnexB
Line
Count
Source
156
66.1M
{
157
66.1M
    if (vlc_CPU_SSE2())
158
66.1M
        return startcode_FindAnnexB_SSE2(p, end);
159
0
    else
160
0
        return startcode_FindAnnexB_Bits(p, end);
161
66.1M
}
vc1.c:startcode_FindAnnexB
Line
Count
Source
156
486k
{
157
486k
    if (vlc_CPU_SSE2())
158
486k
        return startcode_FindAnnexB_SSE2(p, end);
159
0
    else
160
0
        return startcode_FindAnnexB_Bits(p, end);
161
486k
}
162
#else
163
    #define startcode_FindAnnexB startcode_FindAnnexB_Bits
164
#endif
165
166
#endif