Coverage Report

Created: 2026-08-14 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-vp9.c
Line
Count
Source
1
/* packet-vp9.c
2
 * Routines for VP9 dissection
3
 * Copyright 2023, Noan Perrot <noan.perrot@gmail.com>
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * SPDX-License-Identifier: GPL-2.0-or-later
10
 */
11
12
/*
13
 * vp9-bitstream-specification-v0.6-20160331-draft - VP9 Bitstream & Decoding Process Specification
14
 * draft-ietf-payload-vp9-16 - RTP Payload Format for VP9 Video
15
 */
16
17
#include "config.h"
18
#define WS_LOG_DOMAIN "vp9"
19
#include <wireshark.h>
20
21
#include <epan/packet.h> /* Required dissection API header */
22
#include <epan/expert.h> /* Include only as needed */
23
#include <epan/prefs.h>  /* Include only as needed */
24
25
#define STRING_SIZE 50
26
112
#define VP9_1_BIT_MASK 0x80
27
16
#define VP9_2_BIT_MASK 0x40
28
16
#define VP9_3_BIT_MASK 0x20
29
16
#define VP9_4_BIT_MASK 0x10
30
16
#define VP9_5_BIT_MASK 0x08
31
16
#define VP9_6_BIT_MASK 0x04
32
16
#define VP9_7_BIT_MASK 0x02
33
16
#define VP9_8_BIT_MASK 0x01
34
#define VP9_2_BITS_MASK 0xC0
35
48
#define VP9_3_BITS_MASK 0xE0
36
48
#define VP9_7_BITS_MASK 0xFE
37
#define VP9_8_BITS_MASK 0xFF
38
#define VP9_16_BITS_MASK 0xFFFF
39
32
#define VP9_EXTENDED_PID 0x7FFF
40
41
static int proto_vp9;
42
43
static int hf_vp9_pld_i_bit;
44
static int hf_vp9_pld_p_bit;
45
static int hf_vp9_pld_l_bit;
46
static int hf_vp9_pld_f_bit;
47
static int hf_vp9_pld_b_bit;
48
static int hf_vp9_pld_e_bit;
49
static int hf_vp9_pld_v_bit;
50
static int hf_vp9_pld_z_bit;
51
static int hf_vp9_pld_u_bit;
52
static int hf_vp9_pld_m_bit;
53
static int hf_vp9_pld_d_bit;
54
static int hf_vp9_pld_n_bit;
55
static int hf_vp9_pld_y_bit;
56
static int hf_vp9_pld_g_bit;
57
static int hf_vp9_pld_pg_bits;
58
static int hf_vp9_pld_n_s_bits;
59
static int hf_vp9_pld_n_g_bits;
60
static int hf_vp9_pld_sid_bits;
61
static int hf_vp9_pld_pid_bits;
62
static int hf_vp9_pld_tid_bits;
63
static int hf_vp9_pld_width_bits;
64
static int hf_vp9_pld_height_bits;
65
static int hf_vp9_pld_n_s_numbers;
66
static int hf_vp9_pld_p_diff_bits;
67
static int hf_vp9_pld_tl0picidx_bits;
68
static int hf_vp9_pld_pg_extended_bits;
69
static int hf_vp9_pld_pid_extended_bits;
70
71
static int ett_vp9;
72
static int ett_vp9_descriptor;
73
74
static int *ett[] = {
75
    &ett_vp9,
76
    &ett_vp9_descriptor
77
};
78
79
static int
80
dissect_vp9(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, void *data _U_)
81
0
{
82
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "VP9");
83
84
0
    proto_item *vp9_item = proto_tree_add_item(tree, proto_vp9, tvb, 0, -1, ENC_NA);
85
0
    proto_tree *vp9_tree = proto_item_add_subtree(vp9_item, ett_vp9);
86
87
0
    proto_item *vp9_descriptor_item;
88
0
    proto_tree *vp9_descriptor_tree = proto_tree_add_subtree(vp9_tree, tvb, 0, 1, ett_vp9_descriptor, &vp9_descriptor_item, "Payload Descriptor");
89
90
0
    unsigned offset = 0;
91
92
    /*
93
          0 1 2 3 4 5 6 7
94
         +-+-+-+-+-+-+-+-+
95
         |I|P|L|F|B|E|V|Z| (REQUIRED)
96
         +-+-+-+-+-+-+-+-+
97
    */
98
0
    uint8_t i = tvb_get_uint8(tvb, offset) & VP9_1_BIT_MASK;
99
0
    uint8_t p = tvb_get_uint8(tvb, offset) & VP9_2_BIT_MASK;
100
0
    uint8_t l = tvb_get_uint8(tvb, offset) & VP9_3_BIT_MASK;
101
0
    uint8_t f = tvb_get_uint8(tvb, offset) & VP9_4_BIT_MASK;
102
0
    uint8_t v = tvb_get_uint8(tvb, offset) & VP9_7_BIT_MASK;
103
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_i_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
104
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_p_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
105
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_l_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
106
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_f_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
107
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_b_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
108
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_e_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
109
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_v_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
110
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_z_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
111
112
0
    offset++;
113
114
    /*
115
         +-+-+-+-+-+-+-+-+
116
    I:   |M| PICTURE ID  | (REQUIRED)
117
         +-+-+-+-+-+-+-+-+
118
    M:   | EXTENDED PID  | (RECOMMENDED)
119
         +-+-+-+-+-+-+-+-+
120
    */
121
0
    uint8_t m = tvb_get_uint8(tvb, offset) & VP9_1_BIT_MASK;
122
0
    proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_m_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
123
0
    if (f)
124
0
    {
125
        //  Flexible mode
126
0
        if (m == i)
127
0
        {
128
0
            if (m)
129
0
            {
130
                //  Extended PID
131
0
                proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_pid_extended_bits, tvb, offset, 2, ENC_BIG_ENDIAN);
132
0
                offset += 2;
133
0
            }
134
0
            else
135
0
            {
136
                //  PID
137
0
                proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_pid_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
138
0
                offset++;
139
0
            }
140
0
        }
141
0
        else
142
0
        {
143
            //  Malformed packet
144
0
        }
145
0
    }
146
0
    else
147
0
    {
148
        //  Non-flexible mode
149
0
        if (m == i)
150
0
        {
151
0
            if (m)
152
0
            {
153
                //  Extended PID
154
0
                proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_pg_extended_bits, tvb, offset, 2, ENC_BIG_ENDIAN);
155
0
                offset += 2;
156
0
            }
157
0
            else
158
0
            {
159
                //  PID
160
0
                proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_pg_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
161
0
                offset++;
162
0
            }
163
0
        }
164
0
        else
165
0
        {
166
            //  Malformed packet
167
0
        }
168
0
    }
169
170
    /*
171
         +-+-+-+-+-+-+-+-+
172
    L:   | TID |U| SID |D| (Conditionally RECOMMENDED)
173
         +-+-+-+-+-+-+-+-+
174
    */
175
0
    if (l)
176
0
    {
177
        //  Layer indices present
178
0
        proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_tid_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
179
0
        proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_u_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
180
0
        proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_sid_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
181
0
        proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_d_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
182
0
        offset++;
183
184
0
        if (f)
185
0
        {
186
            //  1 octet is present for the layer indices
187
0
            proto_item_set_len(vp9_descriptor_item, 4);
188
0
        }
189
0
        else
190
0
        {
191
            //  2 octets are present for the layer indices
192
0
            proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_tl0picidx_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
193
0
            proto_item_set_len(vp9_descriptor_item, 5);
194
0
            offset++;
195
0
        }
196
0
    }
197
198
    /*
199
          +-+-+-+-+-+-+-+-+                             -\
200
     P,F: | P_DIFF      |N| (Conditionally REQUIRED)    - up to 3 times
201
          +-+-+-+-+-+-+-+-+                             -/
202
    */
203
0
    if (p && f)
204
0
    {
205
0
        uint8_t n = tvb_get_uint8(tvb, offset) & (VP9_1_BIT_MASK >> 7);
206
0
        int idx = 0;
207
0
        int max_p_diff = 3;
208
0
        while (n && idx < max_p_diff)
209
0
        {
210
0
            proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_p_diff_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
211
0
            proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_n_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
212
0
            proto_item_set_len(vp9_descriptor_item, 6);
213
0
            offset++;
214
0
            n = tvb_get_uint8(tvb, offset) & (VP9_1_BIT_MASK >> 7);
215
0
            idx++;
216
0
            if (n && idx == max_p_diff)
217
0
            {
218
                //  Malformed packet
219
0
            }
220
0
        }
221
0
    }
222
223
    /*
224
           +-+-+-+-+-+-+-+-+
225
      V:   | SS            |
226
           | ..            |
227
           +-+-+-+-+-+-+-+-+
228
    */
229
0
    if (v)
230
0
    {
231
        /*
232
             +-+-+-+-+-+-+-+-+
233
        V:   | N_S |Y|G|-|-|-|
234
             +-+-+-+-+-+-+-+-+
235
        */
236
0
        proto_item* n_s_numbers_field;
237
0
        uint8_t n_s = (tvb_get_uint8(tvb, offset) & (VP9_3_BITS_MASK)) >> 5;
238
0
        uint8_t y = tvb_get_uint8(tvb, offset) & (VP9_1_BIT_MASK >> 3);
239
0
        uint8_t g = tvb_get_uint8(tvb, offset) & (VP9_1_BIT_MASK >> 4);
240
0
        uint8_t number_of_spatial_layers = n_s + 1;
241
242
0
        proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_n_s_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
243
0
        n_s_numbers_field = proto_tree_add_uint(vp9_descriptor_tree, hf_vp9_pld_n_s_numbers, tvb, offset, 1, number_of_spatial_layers);
244
0
        proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_y_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
245
0
        proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_g_bit, tvb, offset, 1, ENC_BIG_ENDIAN);
246
0
        proto_item_set_generated(n_s_numbers_field);
247
248
0
        offset++;
249
250
        /*
251
             +-+-+-+-+-+-+-+-+              -\
252
        Y:   |     WIDTH     | (OPTIONAL)    .
253
             +               +               .
254
             |               | (OPTIONAL)    .
255
             +-+-+-+-+-+-+-+-+               . - N_S + 1 times
256
             |     HEIGHT    | (OPTIONAL)    .
257
             +               +               .
258
             |               | (OPTIONAL)    .
259
             +-+-+-+-+-+-+-+-+              -/
260
        */
261
0
        uint8_t spatial_layer = 0;
262
0
        while (spatial_layer < number_of_spatial_layers)
263
0
        {
264
0
            if (y)
265
0
            {
266
                //  TODO: Add subtree for spatial layers
267
0
                proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_width_bits, tvb, offset, 2, ENC_BIG_ENDIAN);
268
0
                offset += 2;
269
0
                proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_height_bits, tvb, offset, 2, ENC_BIG_ENDIAN);
270
0
                offset += 2;
271
0
            }
272
0
            spatial_layer++;
273
0
        }
274
275
        /*
276
             +-+-+-+-+-+-+-+-+
277
        G:   |      N_G      | (OPTIONAL)
278
             +-+-+-+-+-+-+-+-+
279
        */
280
0
        if (g)
281
0
        {
282
            /*
283
                     +-+-+-+-+-+-+-+-+                            -\
284
            N_G:     | TID |U| R |-|-| (OPTIONAL)                 .
285
                     +-+-+-+-+-+-+-+-+              -\            . - N_G times
286
                     |    P_DIFF     | (OPTIONAL)    . - R times  .
287
                     +-+-+-+-+-+-+-+-+              -/            -/
288
            */
289
0
            proto_tree_add_item(vp9_descriptor_tree, hf_vp9_pld_n_g_bits, tvb, offset, 1, ENC_BIG_ENDIAN);
290
0
            offset++;
291
            //  TODO: handle N_G
292
0
        }
293
0
    }
294
295
0
    return tvb_captured_length(tvb);
296
0
}
297
298
void proto_register_vp9(void)
299
16
{
300
16
    static hf_register_info hf[] = {
301
16
        {&hf_vp9_pld_i_bit,
302
16
         {"Picture ID present (I)", "vp9.pld.i",
303
16
          FT_BOOLEAN, 8,
304
16
          NULL, VP9_1_BIT_MASK,
305
16
          NULL, HFILL}},
306
16
        {&hf_vp9_pld_p_bit,
307
16
         {"Inter-picture predicted frame (P)", "vp9.pld.p",
308
16
          FT_BOOLEAN, 8,
309
16
          NULL, VP9_2_BIT_MASK,
310
16
          NULL, HFILL}},
311
16
        {&hf_vp9_pld_l_bit,
312
16
         {"Layer indices present (L)", "vp9.pld.l",
313
16
          FT_BOOLEAN, 8,
314
16
          NULL, VP9_3_BIT_MASK,
315
16
          NULL, HFILL}},
316
16
        {&hf_vp9_pld_f_bit,
317
16
         {"Flexible mode (F)", "vp9.pld.f",
318
16
          FT_BOOLEAN, 8,
319
16
          NULL, VP9_4_BIT_MASK,
320
16
          NULL, HFILL}},
321
16
        {&hf_vp9_pld_b_bit,
322
16
         {"Start of a frame (B)", "vp9.pld.b",
323
16
          FT_BOOLEAN, 8,
324
16
          NULL, VP9_5_BIT_MASK,
325
16
          NULL, HFILL}},
326
16
        {&hf_vp9_pld_e_bit,
327
16
         {"End of a frame (E)", "vp9.pld.e",
328
16
          FT_BOOLEAN, 8,
329
16
          NULL, VP9_6_BIT_MASK,
330
16
          NULL, HFILL}},
331
16
        {&hf_vp9_pld_v_bit,
332
16
         {"Scalability structure (SS) data present (V)", "vp9.pld.v",
333
16
          FT_BOOLEAN, 8,
334
16
          NULL, VP9_7_BIT_MASK,
335
16
          NULL, HFILL}},
336
16
        {&hf_vp9_pld_z_bit,
337
16
         {"Not a reference frame for upper spatial layers (Z)", "vp9.pld.z",
338
16
          FT_BOOLEAN, 8,
339
16
          NULL, VP9_8_BIT_MASK,
340
16
          NULL, HFILL}},
341
16
        {&hf_vp9_pld_m_bit,
342
16
         {"Extension flag (M)", "vp9.pld.m",
343
16
          FT_BOOLEAN, 8,
344
16
          NULL, VP9_1_BIT_MASK,
345
16
          NULL, HFILL}},
346
16
        {&hf_vp9_pld_pid_bits,
347
16
         {"Picture ID (PID)", "vp9.pld.pid",
348
16
          FT_UINT8, BASE_DEC,
349
16
          NULL, VP9_7_BITS_MASK >> 1,
350
16
          NULL, HFILL}},
351
16
        {&hf_vp9_pld_pid_extended_bits,
352
16
         {"Picture ID (PID) Extended", "vp9.pld.pid_ext",
353
16
          FT_UINT16, BASE_DEC,
354
16
          NULL, VP9_EXTENDED_PID,
355
16
          NULL, HFILL}},
356
16
        {&hf_vp9_pld_pg_bits,
357
16
         {"Picture Group Index (PG)", "vp9.pld.pg",
358
16
          FT_UINT8, BASE_DEC,
359
16
          NULL, VP9_7_BITS_MASK >> 1,
360
16
          NULL, HFILL}},
361
16
        {&hf_vp9_pld_pg_extended_bits,
362
16
         {"Picture Group Index (PG) Extended", "vp9.pld.pg_ext",
363
16
          FT_UINT16, BASE_DEC,
364
16
          NULL, VP9_EXTENDED_PID,
365
16
          NULL, HFILL}},
366
16
        {&hf_vp9_pld_tid_bits,
367
16
         {"Temporal layer ID", "vp9.pld.tid",
368
16
          FT_UINT8, BASE_DEC,
369
16
          NULL, VP9_3_BITS_MASK,
370
16
          NULL, HFILL}},
371
16
        {&hf_vp9_pld_u_bit,
372
16
         {"Switching up point (U)", "vp9.pld.u",
373
16
          FT_BOOLEAN, 8,
374
16
          NULL, VP9_1_BIT_MASK >> 3,
375
16
          NULL, HFILL}},
376
16
        {&hf_vp9_pld_sid_bits,
377
16
         {"Spatial Layer ID", "vp9.pld.sid",
378
16
          FT_UINT8, BASE_DEC,
379
16
          NULL, VP9_3_BITS_MASK >> 4,
380
16
          NULL, HFILL}},
381
16
        {&hf_vp9_pld_d_bit,
382
16
         {"Inter-layer dependency used (D)", "vp9.pld.d",
383
16
          FT_BOOLEAN, 8,
384
16
          NULL, VP9_1_BIT_MASK >> 7,
385
16
          NULL, HFILL}},
386
16
        {&hf_vp9_pld_tl0picidx_bits,
387
16
         {"Temporal layer zero index", "vp9.pld.tl0picidx",
388
16
          FT_UINT8, BASE_DEC,
389
16
          NULL, 0,
390
16
          NULL, HFILL}},
391
16
        {&hf_vp9_pld_p_diff_bits,
392
16
         {"Reference index (P_DIFF)", "vp9.pld.p_diff",
393
16
          FT_UINT8, BASE_DEC,
394
16
          NULL, VP9_7_BITS_MASK,
395
16
          NULL, HFILL}},
396
16
        {&hf_vp9_pld_n_bit,
397
16
         {"Additional reference index (N)", "vp9.pld.n",
398
16
          FT_BOOLEAN, 8,
399
16
          NULL, VP9_1_BIT_MASK >> 7,
400
16
          NULL, HFILL}},
401
16
        {&hf_vp9_pld_n_s_bits,
402
16
         {"Spatial layers minus 1 (N_S)", "vp9.pld.n_s",
403
16
          FT_UINT8, BASE_DEC,
404
16
          NULL, VP9_3_BITS_MASK,
405
16
          NULL, HFILL}},
406
16
        {&hf_vp9_pld_n_s_numbers,
407
16
         {"Number of spatial layers", "vp9.pld.spatial_layers_number",
408
16
          FT_UINT8, BASE_DEC,
409
16
          NULL, 0,
410
16
          NULL, HFILL}},
411
16
        {&hf_vp9_pld_y_bit,
412
16
         {"Spatial layer's frame resolution present (Y)", "vp9.pld.y",
413
16
          FT_BOOLEAN, 8,
414
16
          NULL, VP9_1_BIT_MASK >> 3,
415
16
          NULL, HFILL}},
416
16
        {&hf_vp9_pld_g_bit,
417
16
         {"PG description flag (G)", "vp9.pld.g",
418
16
          FT_BOOLEAN, 8,
419
16
          NULL, VP9_1_BIT_MASK >> 4,
420
16
          NULL, HFILL}},
421
16
        {&hf_vp9_pld_height_bits,
422
16
         {"Height", "vp9.pld.height",
423
16
          FT_UINT16, BASE_DEC,
424
16
          NULL, 0,
425
16
          NULL, HFILL}},
426
16
        {&hf_vp9_pld_width_bits,
427
16
         {"Width", "vp9.pld.width",
428
16
          FT_UINT16, BASE_DEC,
429
16
          NULL, 0,
430
16
          NULL, HFILL}},
431
16
        {&hf_vp9_pld_n_g_bits,
432
16
         {"Number of pictures (N_G)", "vp9.pld.n_g",
433
16
          FT_UINT8, BASE_DEC,
434
16
          NULL, 0,
435
16
          NULL, HFILL}}};
436
437
16
    proto_vp9 = proto_register_protocol("VP9", "VP9", "vp9");
438
439
16
    proto_register_field_array(proto_vp9, hf, array_length(hf));
440
16
    proto_register_subtree_array(ett, array_length(ett));
441
16
}
442
443
void proto_reg_handoff_vp9(void)
444
16
{
445
16
    static dissector_handle_t vp9_handle;
446
447
16
    vp9_handle = register_dissector("vp9", dissect_vp9, proto_vp9);
448
449
16
    dissector_add_string("rtp_dyn_payload_type", "vp9", vp9_handle);
450
16
    dissector_add_uint_range_with_preference("rtp.pt", "", vp9_handle);
451
16
}
452
453
/*
454
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
455
 *
456
 * Local variables:
457
 * c-basic-offset: 4
458
 * tab-width: 8
459
 * indent-tabs-mode: nil
460
 * End:
461
 *
462
 * vi: set shiftwidth=4 tabstop=8 expandtab:
463
 * :indentSize=4:tabSize=8:noTabs=true:
464
 */