在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,新編譯的庫即可正常連結。