Coverage Report

Created: 2026-01-25 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavutil/log.c
Line
Count
Source
1
/*
2
 * log functions
3
 * Copyright (c) 2003 Michel Bardiaux
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
/**
23
 * @file
24
 * logging functions
25
 */
26
27
#include "config.h"
28
29
#if HAVE_UNISTD_H
30
#include <unistd.h>
31
#endif
32
#if HAVE_IO_H
33
#include <io.h>
34
#endif
35
#include <inttypes.h>
36
#include <stdarg.h>
37
#include <stdatomic.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include "bprint.h"
42
#include "common.h"
43
#include "internal.h"
44
#include "log.h"
45
#include "thread.h"
46
#include "time.h"
47
#include "time_internal.h"
48
49
static AVMutex mutex = AV_MUTEX_INITIALIZER;
50
51
#define LINE_SZ 1024
52
53
#if HAVE_VALGRIND_VALGRIND_H && CONFIG_VALGRIND_BACKTRACE
54
#include <valgrind/valgrind.h>
55
/* this is the log level at which valgrind will output a full backtrace */
56
#define BACKTRACE_LOGLEVEL AV_LOG_ERROR
57
#endif
58
59
static atomic_int av_log_level = AV_LOG_INFO;
60
static atomic_int av_log_flags = 0;
61
62
0
#define NB_LEVELS 8
63
#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
64
#include <windows.h>
65
static const uint8_t color[16 + AV_CLASS_CATEGORY_NB] = {
66
    [AV_LOG_PANIC  /8] = 12,
67
    [AV_LOG_FATAL  /8] = 12,
68
    [AV_LOG_ERROR  /8] = 12,
69
    [AV_LOG_WARNING/8] = 14,
70
    [AV_LOG_INFO   /8] =  7,
71
    [AV_LOG_VERBOSE/8] = 10,
72
    [AV_LOG_DEBUG  /8] = 10,
73
    [AV_LOG_TRACE  /8] = 8,
74
    [16+AV_CLASS_CATEGORY_NA              ] =  7,
75
    [16+AV_CLASS_CATEGORY_INPUT           ] = 13,
76
    [16+AV_CLASS_CATEGORY_OUTPUT          ] =  5,
77
    [16+AV_CLASS_CATEGORY_MUXER           ] = 13,
78
    [16+AV_CLASS_CATEGORY_DEMUXER         ] =  5,
79
    [16+AV_CLASS_CATEGORY_ENCODER         ] = 11,
80
    [16+AV_CLASS_CATEGORY_DECODER         ] =  3,
81
    [16+AV_CLASS_CATEGORY_FILTER          ] = 10,
82
    [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] =  9,
83
    [16+AV_CLASS_CATEGORY_SWSCALER        ] =  7,
84
    [16+AV_CLASS_CATEGORY_SWRESAMPLER     ] =  7,
85
    [16+AV_CLASS_CATEGORY_HWDEVICE        ] =  6,
86
    [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 13,
87
    [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT  ] = 5,
88
    [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 13,
89
    [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT  ] = 5,
90
    [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT       ] = 13,
91
    [16+AV_CLASS_CATEGORY_DEVICE_INPUT        ] = 5,
92
};
93
94
static int16_t background, attr_orig;
95
static HANDLE con;
96
#else
97
98
static const uint32_t color[16 + AV_CLASS_CATEGORY_NB] = {
99
    [AV_LOG_PANIC  /8] =  52 << 16 | 196 << 8 | 0x41,
100
    [AV_LOG_FATAL  /8] = 208 <<  8 | 0x41,
101
    [AV_LOG_ERROR  /8] = 196 <<  8 | 0x11,
102
    [AV_LOG_WARNING/8] = 226 <<  8 | 0x03,
103
    [AV_LOG_INFO   /8] = 253 <<  8 | 0x09,
104
    [AV_LOG_VERBOSE/8] =  40 <<  8 | 0x02,
105
    [AV_LOG_DEBUG  /8] =  34 <<  8 | 0x02,
106
    [AV_LOG_TRACE  /8] =  34 <<  8 | 0x07,
107
    [16+AV_CLASS_CATEGORY_NA              ] = 250 << 8 | 0x09,
108
    [16+AV_CLASS_CATEGORY_INPUT           ] = 219 << 8 | 0x15,
109
    [16+AV_CLASS_CATEGORY_OUTPUT          ] = 201 << 8 | 0x05,
110
    [16+AV_CLASS_CATEGORY_MUXER           ] = 213 << 8 | 0x15,
111
    [16+AV_CLASS_CATEGORY_DEMUXER         ] = 207 << 8 | 0x05,
112
    [16+AV_CLASS_CATEGORY_ENCODER         ] =  51 << 8 | 0x16,
113
    [16+AV_CLASS_CATEGORY_DECODER         ] =  39 << 8 | 0x06,
114
    [16+AV_CLASS_CATEGORY_FILTER          ] = 155 << 8 | 0x12,
115
    [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 192 << 8 | 0x14,
116
    [16+AV_CLASS_CATEGORY_SWSCALER        ] = 153 << 8 | 0x14,
117
    [16+AV_CLASS_CATEGORY_SWRESAMPLER     ] = 147 << 8 | 0x14,
118
    [16+AV_CLASS_CATEGORY_HWDEVICE        ] = 214 << 8 | 0x13,
119
    [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 213 << 8 | 0x15,
120
    [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT  ] = 207 << 8 | 0x05,
121
    [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 213 << 8 | 0x15,
122
    [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT  ] = 207 << 8 | 0x05,
123
    [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT       ] = 213 << 8 | 0x15,
124
    [16+AV_CLASS_CATEGORY_DEVICE_INPUT        ] = 207 << 8 | 0x05,
125
};
126
127
#endif
128
static int use_color = -1;
129
130
#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
131
static void win_console_puts(const char *str)
132
{
133
    const uint8_t *q = str;
134
    uint16_t line[LINE_SZ];
135
136
    while (*q) {
137
        uint16_t *buf = line;
138
        DWORD nb_chars = 0;
139
        DWORD written;
140
141
        while (*q && nb_chars < LINE_SZ - 1) {
142
            uint32_t ch;
143
            uint16_t tmp;
144
145
            GET_UTF8(ch, *q ? *q++ : 0, ch = 0xfffd; goto continue_on_invalid;)
146
continue_on_invalid:
147
            PUT_UTF16(ch, tmp, *buf++ = tmp; nb_chars++;)
148
        }
149
150
        WriteConsoleW(con, line, nb_chars, &written, NULL);
151
    }
152
}
153
#endif
154
155
static void check_color_terminal(void)
156
0
{
157
0
    char *term = getenv("TERM");
158
159
#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
160
    CONSOLE_SCREEN_BUFFER_INFO con_info;
161
    DWORD dummy;
162
    con = GetStdHandle(STD_ERROR_HANDLE);
163
    if (con != INVALID_HANDLE_VALUE && !GetConsoleMode(con, &dummy))
164
        con = INVALID_HANDLE_VALUE;
165
    if (con != INVALID_HANDLE_VALUE) {
166
        GetConsoleScreenBufferInfo(con, &con_info);
167
        attr_orig  = con_info.wAttributes;
168
        background = attr_orig & 0xF0;
169
    }
170
#endif
171
172
0
    if (getenv("AV_LOG_FORCE_NOCOLOR")) {
173
0
        use_color = 0;
174
0
    } else if (getenv("AV_LOG_FORCE_COLOR")) {
175
0
        use_color = 1;
176
0
    } else {
177
#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
178
        use_color = (con != INVALID_HANDLE_VALUE);
179
#elif HAVE_ISATTY
180
0
        use_color = (term && isatty(2));
181
#else
182
        use_color = 0;
183
#endif
184
0
    }
185
186
0
    if (getenv("AV_LOG_FORCE_256COLOR") || term && strstr(term, "256color"))
187
0
        use_color *= 256;
188
0
}
189
190
static void ansi_fputs(int level, int tint, const char *str, int local_use_color)
191
0
{
192
0
    if (local_use_color == 1) {
193
0
        fprintf(stderr,
194
0
                "\033[%"PRIu32";3%"PRIu32"m%s\033[0m",
195
0
                (color[level] >> 4) & 15,
196
0
                color[level] & 15,
197
0
                str);
198
0
    } else if (tint && use_color == 256) {
199
0
        fprintf(stderr,
200
0
                "\033[48;5;%"PRIu32"m\033[38;5;%dm%s\033[0m",
201
0
                (color[level] >> 16) & 0xff,
202
0
                tint,
203
0
                str);
204
0
    } else if (local_use_color == 256) {
205
0
        fprintf(stderr,
206
0
                "\033[48;5;%"PRIu32"m\033[38;5;%"PRIu32"m%s\033[0m",
207
0
                (color[level] >> 16) & 0xff,
208
0
                (color[level] >> 8) & 0xff,
209
0
                str);
210
0
    } else
211
0
        fputs(str, stderr);
212
0
}
213
214
static void colored_fputs(int level, int tint, const char *str)
215
0
{
216
0
    int local_use_color;
217
0
    if (!*str)
218
0
        return;
219
220
0
    if (use_color < 0)
221
0
        check_color_terminal();
222
223
0
    if (level == AV_LOG_INFO/8) local_use_color = 0;
224
0
    else                        local_use_color = use_color;
225
226
#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE
227
    if (con != INVALID_HANDLE_VALUE) {
228
        if (local_use_color)
229
            SetConsoleTextAttribute(con, background | color[level]);
230
        win_console_puts(str);
231
        if (local_use_color)
232
            SetConsoleTextAttribute(con, attr_orig);
233
    } else {
234
        ansi_fputs(level, tint, str, local_use_color);
235
    }
236
#else
237
0
    ansi_fputs(level, tint, str, local_use_color);
238
0
#endif
239
240
0
}
241
242
const char *av_default_item_name(void *ptr)
243
0
{
244
0
    return (*(AVClass **) ptr)->class_name;
245
0
}
246
247
AVClassCategory av_default_get_category(void *ptr)
248
0
{
249
0
    return (*(AVClass **) ptr)->category;
250
0
}
251
252
0
static void sanitize(uint8_t *line){
253
0
    while(*line){
254
0
        if(*line < 0x08 || (*line > 0x0D && *line < 0x20))
255
0
            *line='?';
256
0
        line++;
257
0
    }
258
0
}
259
260
0
static int get_category(void *ptr){
261
0
    AVClass *avc = *(AVClass **) ptr;
262
0
    if(    !avc
263
0
        || (avc->version&0xFF)<100
264
0
        ||  avc->version < (51 << 16 | 59 << 8)
265
0
        ||  avc->category >= AV_CLASS_CATEGORY_NB) return AV_CLASS_CATEGORY_NA + 16;
266
267
0
    if(avc->get_category)
268
0
        return avc->get_category(ptr) + 16;
269
270
0
    return avc->category + 16;
271
0
}
272
273
static const char *get_level_str(int level)
274
0
{
275
0
    switch (level) {
276
0
    case AV_LOG_QUIET:
277
0
        return "quiet";
278
0
    case AV_LOG_DEBUG:
279
0
        return "debug";
280
0
    case AV_LOG_TRACE:
281
0
        return "trace";
282
0
    case AV_LOG_VERBOSE:
283
0
        return "verbose";
284
0
    case AV_LOG_INFO:
285
0
        return "info";
286
0
    case AV_LOG_WARNING:
287
0
        return "warning";
288
0
    case AV_LOG_ERROR:
289
0
        return "error";
290
0
    case AV_LOG_FATAL:
291
0
        return "fatal";
292
0
    case AV_LOG_PANIC:
293
0
        return "panic";
294
0
    default:
295
0
        return "";
296
0
    }
297
0
}
298
299
static const char *item_name(void *obj, const AVClass *cls)
300
0
{
301
0
    return (cls->item_name ? cls->item_name : av_default_item_name)(obj);
302
0
}
303
304
static void format_date_now(AVBPrint* bp_time, int include_date)
305
0
{
306
0
    struct tm *ptm, tmbuf;
307
0
    const int64_t time_us = av_gettime();
308
0
    const int64_t time_ms = time_us / 1000;
309
0
    const time_t time_s   = time_ms / 1000;
310
0
    const int millisec    = time_ms - (time_s * 1000);
311
0
    ptm                   = localtime_r(&time_s, &tmbuf);
312
0
    if (ptm) {
313
0
        if (include_date)
314
0
            av_bprint_strftime(bp_time, "%Y-%m-%d ", ptm);
315
316
0
        av_bprint_strftime(bp_time, "%H:%M:%S", ptm);
317
0
        av_bprintf(bp_time, ".%03d ", millisec);
318
0
    }
319
0
}
320
321
static void format_line(void *avcl, int level, const char *fmt, va_list vl,
322
                        AVBPrint part[5], int *print_prefix, int type[2])
323
0
{
324
0
    AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
325
0
    av_bprint_init(part+0, 0, AV_BPRINT_SIZE_AUTOMATIC);
326
0
    av_bprint_init(part+1, 0, AV_BPRINT_SIZE_AUTOMATIC);
327
0
    av_bprint_init(part+2, 0, AV_BPRINT_SIZE_AUTOMATIC);
328
0
    av_bprint_init(part+3, 0, 65536);
329
0
    av_bprint_init(part+4, 0, AV_BPRINT_SIZE_AUTOMATIC);
330
0
    int flags = atomic_load_explicit(&av_log_flags, memory_order_relaxed);
331
332
0
    if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16;
333
0
    if (*print_prefix && avc) {
334
0
        if (avc->parent_log_context_offset) {
335
0
            AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) +
336
0
                                   avc->parent_log_context_offset);
337
0
            if (parent && *parent) {
338
0
                av_bprintf(part+0, "[%s @ %p] ",
339
0
                           item_name(parent, *parent), parent);
340
0
                if(type) type[0] = get_category(parent);
341
0
            }
342
0
        }
343
0
        av_bprintf(part+1, "[%s @ %p] ",
344
0
                   item_name(avcl, avc), avcl);
345
0
        if(type) type[1] = get_category(avcl);
346
0
    }
347
348
0
    if (*print_prefix && (level > AV_LOG_QUIET) && (flags & (AV_LOG_PRINT_TIME | AV_LOG_PRINT_DATETIME)))
349
0
        format_date_now(&part[4], flags & AV_LOG_PRINT_DATETIME);
350
351
0
    if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL))
352
0
        av_bprintf(part+2, "[%s] ", get_level_str(level));
353
354
0
    av_vbprintf(part+3, fmt, vl);
355
356
0
    if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) {
357
0
        char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0;
358
0
        *print_prefix = lastc == '\n' || lastc == '\r';
359
0
    }
360
0
}
361
362
void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl,
363
                        char *line, int line_size, int *print_prefix)
364
0
{
365
0
    av_log_format_line2(ptr, level, fmt, vl, line, line_size, print_prefix);
366
0
}
367
368
int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl,
369
                        char *line, int line_size, int *print_prefix)
370
0
{
371
0
    AVBPrint part[5];
372
0
    int ret;
373
374
0
    format_line(ptr, level, fmt, vl, part, print_prefix, NULL);
375
0
    ret = snprintf(line, line_size, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
376
0
    av_bprint_finalize(part+3, NULL);
377
0
    return ret;
378
0
}
379
380
void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl)
381
1.36k
{
382
1.36k
    static int print_prefix = 1;
383
1.36k
    static int count;
384
1.36k
    static char prev[LINE_SZ];
385
1.36k
    AVBPrint part[5];
386
1.36k
    char line[LINE_SZ];
387
1.36k
    static int is_atty;
388
1.36k
    int type[2];
389
1.36k
    unsigned tint = 0;
390
391
1.36k
    if (level >= 0) {
392
1.36k
        tint = level & 0xff00;
393
1.36k
        level &= 0xff;
394
1.36k
    }
395
396
1.36k
    if (level > atomic_load_explicit(&av_log_level, memory_order_relaxed))
397
1.36k
        return;
398
0
    ff_mutex_lock(&mutex);
399
400
0
    format_line(ptr, level, fmt, vl, part, &print_prefix, type);
401
0
    snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);
402
403
0
#if HAVE_ISATTY
404
0
    if (!is_atty)
405
0
        is_atty = isatty(2) ? 1 : -1;
406
0
#endif
407
408
0
    if (print_prefix && (atomic_load_explicit(&av_log_flags, memory_order_relaxed) & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev) &&
409
0
        *line && line[strlen(line) - 1] != '\r'){
410
0
        count++;
411
0
        if (is_atty == 1)
412
0
            fprintf(stderr, "    Last message repeated %d times\r", count);
413
0
        goto end;
414
0
    }
415
0
    if (count > 0) {
416
0
        fprintf(stderr, "    Last message repeated %d times\n", count);
417
0
        count = 0;
418
0
    }
419
0
    strcpy(prev, line);
420
421
0
    sanitize(part[4].str);
422
0
    colored_fputs(7, 0, part[4].str);
423
0
    sanitize(part[0].str);
424
0
    colored_fputs(type[0], 0, part[0].str);
425
0
    sanitize(part[1].str);
426
0
    colored_fputs(type[1], 0, part[1].str);
427
0
    sanitize(part[2].str);
428
0
    colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str);
429
0
    sanitize(part[3].str);
430
0
    colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str);
431
432
#if CONFIG_VALGRIND_BACKTRACE
433
    if (level <= BACKTRACE_LOGLEVEL)
434
        VALGRIND_PRINTF_BACKTRACE("%s", "");
435
#endif
436
0
end:
437
0
    av_bprint_finalize(part+3, NULL);
438
0
    ff_mutex_unlock(&mutex);
439
0
}
440
441
static atomic_uintptr_t av_log_callback = (uintptr_t)av_log_default_callback;
442
443
void av_log(void* avcl, int level, const char *fmt, ...)
444
1.36k
{
445
1.36k
    va_list vl;
446
1.36k
    va_start(vl, fmt);
447
1.36k
    av_vlog(avcl, level, fmt, vl);
448
1.36k
    va_end(vl);
449
1.36k
}
450
451
void av_log_once(void* avcl, int initial_level, int subsequent_level, int *state, const char *fmt, ...)
452
0
{
453
0
    va_list vl;
454
0
    va_start(vl, fmt);
455
0
    av_vlog(avcl, *state ? subsequent_level : initial_level, fmt, vl);
456
0
    va_end(vl);
457
0
    *state = 1;
458
0
}
459
460
void av_vlog(void* avcl, int level, const char *fmt, va_list vl)
461
1.36k
{
462
1.36k
    AVClass* avc = avcl ? *(AVClass **) avcl : NULL;
463
1.36k
    void (*log_callback)(void*, int, const char*, va_list) =
464
1.36k
        (void *)atomic_load_explicit(&av_log_callback, memory_order_relaxed);
465
1.36k
    if (avc && avc->version >= (50 << 16 | 15 << 8 | 2) &&
466
1.36k
        avc->log_level_offset_offset && level >= AV_LOG_FATAL)
467
0
        level += *(int *) (((uint8_t *) avcl) + avc->log_level_offset_offset);
468
1.36k
    if (log_callback)
469
1.36k
        log_callback(avcl, level, fmt, vl);
470
1.36k
}
471
472
int av_log_get_level(void)
473
0
{
474
0
    return atomic_load_explicit(&av_log_level, memory_order_relaxed);
475
0
}
476
477
void av_log_set_level(int level)
478
0
{
479
0
    atomic_store_explicit(&av_log_level, level, memory_order_relaxed);
480
0
}
481
482
void av_log_set_flags(int arg)
483
0
{
484
0
    atomic_store_explicit(&av_log_flags, arg, memory_order_relaxed);
485
0
}
486
487
int av_log_get_flags(void)
488
0
{
489
0
    return atomic_load_explicit(&av_log_flags, memory_order_relaxed);
490
0
}
491
492
void av_log_set_callback(void (*callback)(void*, int, const char*, va_list))
493
0
{
494
0
    atomic_store_explicit(&av_log_callback, (uintptr_t)callback, memory_order_relaxed);
495
0
}
496
497
static void missing_feature_sample(int sample, void *avc, const char *msg,
498
                                   va_list argument_list)
499
0
{
500
0
    av_vlog(avc, AV_LOG_WARNING, msg, argument_list);
501
0
    av_log(avc, AV_LOG_WARNING, " is not implemented. Update your FFmpeg "
502
0
           "version to the newest one from Git. If the problem still "
503
0
           "occurs, it means that your file has a feature which has not "
504
0
           "been implemented.\n");
505
0
    if (sample)
506
0
        av_log(avc, AV_LOG_WARNING, "If you want to help, upload a sample "
507
0
               "of this file to https://streams.videolan.org/upload/ "
508
0
               "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n");
509
0
}
510
511
void avpriv_request_sample(void *avc, const char *msg, ...)
512
0
{
513
0
    va_list argument_list;
514
515
0
    va_start(argument_list, msg);
516
0
    missing_feature_sample(1, avc, msg, argument_list);
517
0
    va_end(argument_list);
518
0
}
519
520
void avpriv_report_missing_feature(void *avc, const char *msg, ...)
521
0
{
522
0
    va_list argument_list;
523
524
0
    va_start(argument_list, msg);
525
0
    missing_feature_sample(0, avc, msg, argument_list);
526
    va_end(argument_list);
527
0
}