天天看點

在VS2019環境下靜态編輯ffmpeg遇到的問題

在ffmpeg編譯階段沒有報錯,但在程式中連結生成的靜态庫,卻報出以下錯誤

1>libavutil.a(log.o) : error LNK2019: unresolved external symbol ___iob_func referenced in function _av_log_default_callback

1>libavutil.a(snprintf.o) : error LNK2019: unresolved external symbol _vacopy referenced in function _avpriv_vsnprintf

1>libavutil.a(bprint.o) : error LNK2001: unresolved external symbol _vacopy

對于第一個錯誤,期原因是:在av_log_default_callback函數中使用了stderr,作為錯誤資訊的輸對象;但自VS2015後,VC系統對stderr等句柄作了重新定義:

#define stdin  (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))
           

而在vs2015之前的定義是:

​#define stdin  (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])
           

ffmpeg中貌似還是沿用vs2015之前的方案,是以隻要用"__acrt_iob_func(2)"替換掉log.c檔案中的所有"stderr",這個問題就不會出現。

這個問題網絡上也有其它的解決方法,但我試過之後貌似都不起作用。

第二和第三錯誤是同一個問題,找到VS中對vacopy函數的定義,在調用該函數的地方給它一個定義,就能蒙混過關。

檔案snprintf.c

// snprintf.c 檔案
// 新增加的自定義函數
void vacopy(va_list *pap, va_list ap)
{
    *pap = ap;
} 
int avpriv_vsnprintf(char *s, size_t n, const char *fmt,
                     va_list ap)
{
    int ret;
    va_list ap_copy;

    if (n == 0)
        return _vscprintf(fmt, ap);
    else if (n > INT_MAX)
        return AVERROR(EOVERFLOW);

    /* we use n - 1 here because if the buffer is not big enough, the MS
     * runtime libraries don't add a terminating zero at the end. MSDN
     * recommends to provide _snprintf/_vsnprintf() a buffer size that
     * is one less than the actual buffer, and zero it before calling
     * _snprintf/_vsnprintf() to workaround this problem.
     * See http://msdn.microsoft.com/en-us/library/1kt27hek(v=vs.80).aspx */
    memset(s, 0, n);
    vacopy(ap_copy, ap);
    ret = _vsnprintf(s, n - 1, fmt, ap_copy);
    va_end(ap_copy);
    if (ret == -1)
        ret = _vscprintf(fmt, ap);

    return ret;
}
           

檔案bprintf.c

// bprint.c 檔案
// 新增加的自定義函數,為避免和前面的加的函數沖突,改名為_vacopy
void _vacopy(va_list *pap, va_list ap)
{
    *pap = ap;
}

void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg)
{
    unsigned room;
    char *dst;
    int extra_len;
    va_list vl;

    while (1) {
        room = av_bprint_room(buf);
        dst = room ? buf->str + buf->len : NULL;
        _vacopy(vl, vl_arg);    // 這裡作了修改
        extra_len = vsnprintf(dst, room, fmt, vl);
        va_end(vl);
        if (extra_len <= 0)
            return;
        if (extra_len < room)
            break;
        if (av_bprint_alloc(buf, extra_len))
            break;
    }
    av_bprint_grow(buf, extra_len);
}
           

修改完成後,儲存檔案,重新靜态編譯ffmpeg,新編譯的庫即可正常連結。