FFmpeg源码阅读:错误码

FFmpeg源码阅读:错误码

FFmpeg 的错误码是错误诊断和推测的工具,是一个 int 型的负数值,以 AVERROR_开头,定义在
libavutil/error.h中。

例如,如果打印错误码:

  1. AVERROR_EOF-541478725
  2. AVERROR_HTTP_NOT_FOUND-875574520.
  3. AVERROR_INVALIDDATA-1094995529

AVERROR宏

FFmpeg 的错误码是 POSIX 错误码的负值。

/* error handling */
#if EDOM > 0
#define AVERROR(e) (-(e))   ///< Returns a negative error code from a POSIX error code, to return from library functions.
#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value.
#else
/* Some platforms have E* and errno already negated. */
#define AVERROR(e) (e)
#define AVUNERROR(e) (e)
#endif

av_strerror

位于libavutil/error.h中。将错误码转换成文字描述信息。

函数原型:

int av_strerror(int errnum, char *errbuf, size_t errbuf_size);

函数参数:errnum是错误码,errbuf是错误信息,errbuf_size是错误信息的长度。
函数返回值:成功返回 0;失败返回负值。

 int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
 {
     int ret = 0, i;
     const struct error_entry *entry = NULL;

     for (i = 0; i < FF_ARRAY_ELEMS(error_entries); i++) {
         if (errnum == error_entries[i].num) {
             entry = &error_entries[i];
             break;
         }
     }
     if (entry) {
         av_strlcpy(errbuf, entry->str, errbuf_size);
     } else {
 #if HAVE_STRERROR_R
         ret = AVERROR(strerror_r(AVUNERROR(errnum), errbuf, errbuf_size));
 #else
         ret = -1;
 #endif
         if (ret < 0)
             snprintf(errbuf, errbuf_size, "Error number %d occurred", errnum);
     }

     return ret;
 }

FF_ARRAY_ELEMS宏用于求数组中元素个数。函数通过依次比较 errnum 和 error_entries 中每个 error_entry 的 num 字段,如果匹配,则获取错误信息, error_entry结构如下。

 struct error_entry {
     int num;
     const char *tag;
     const char *str;
 };

error_entries 在 error.c 中,定义为一个静态全局变量。ERROR_TAG宏通过拼接AVERROR_和 tag 名,构成错误码的宏,比如上面的AVERROR_HTTP_NOT_FOUND

 #define ERROR_TAG(tag) AVERROR_##tag, #tag
 #define EERROR_TAG(tag) AVERROR(tag), #tag
 #define AVERROR_INPUT_AND_OUTPUT_CHANGED (AVERROR_INPUT_CHANGED | AVERROR_OUTPUT_CHANGED)
 static const struct error_entry error_entries[] = {
     { ERROR_TAG(BSF_NOT_FOUND),      "Bitstream filter not found"                     },
     { ERROR_TAG(BUG),                "Internal bug, should not have happened"         },
     { ERROR_TAG(BUG2),               "Internal bug, should not have happened"         },
     ...
 };

av_err2str也可以获得错误字符串,本身是一个宏,通过调用av_make_error_string,再调用 av_strerror 函数,函数参数是错误码,函数返回值是 err_buf

 /**
  * Fill the provided buffer with a string containing an error string
  * corresponding to the AVERROR code errnum.
  *
  * @param errbuf         a buffer
  * @param errbuf_size    size in bytes of errbuf
  * @param errnum         error code to describe
  * @return the buffer in input, filled with the error description
  * @see av_strerror()
  */
 static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum)
 {
     av_strerror(errnum, errbuf, errbuf_size);
     return errbuf;
 }
 /**
  * Convenience macro, the return value should be used only directly in
  * function arguments but never stand-alone.
  */
 #define av_err2str(errnum) \
     av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum)

FFmpeg 的错误码

libavutil/common.h 中,FFmpeg 的错误码通过以下宏生成:

#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d))
#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))
#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24))

宏 MKTAG 将 4 个 char 字符通过位移,组成一个 int型的正整数(4字节,32位),FFERRTAG宏再对其结果取负数。MKTAG对字符d做(unsigned)转换,由于ASCII码占用一个字节里的后7位,最前面的一位统一规定为 0,这样只要宏 MKTAG 的最后一个参数是 ASCII 码,就能保证转换后的数字是一个整数。如果需要大端排列,使用MKBETAG。

FFmpeg 错误码列表如:error.h

错误码的解析

将十进制的错误码转换为十六进制,然后对照 ASCII 码看下错误码(如果使用Mac电脑,可以直接用计算器):

例如,-875574520十六进制表示为-0x343034F8。0x34 对应 ASCII 码中 52 ,也就是4,0x30 对应 48 ,也就是0。【34 30 34】合在一起就是 404。

再比如,-1094995529,十六进制表示为 -0x41444E49,在 ACSII 中,0x41 对应 'A'、0x44 对应 'D'、0x4E 对应 'N , 0x49 对应 'I'。是 AVERROR_INVALIDDATA 定义的 FFERRTAG('I','N','D','A')

FFmpeg源码阅读:错误码