我的YUV播放器MFC小笔记:解析文件名称

为了方便播放器直接播放,也为实现所谓智能识别文件分辨率和格式,对文件名称进行解析,代码如下:

1
#define ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))

// 从文件名称解析分辨率及YUV格式
void find_resolution(char* filename, int& fmt_idx, int& width, int& height)
{
#define str_debug
int i = 0;
int j = 0;
int len = 0;
int pos = 0;
char* tmp = NULL;
char* p = NULL;
char c_width[8] = {0};
char c_height[8] = {0};
char c_fmt[8] = {0};
char c_res[8] = {0};
char c_file[128] = {0};

const char* fmt_str[] = {
    "yuv420",
    "yv12",
    "yuv422",
    "yv16",
    "yuv444",
    "yuyv",
    "yvyu",
    "uyvy",
    "vyuy",
    "nv12",
    "nv21",
    "nv16",
    "nv61",
    "yuv420sp",
    "yuv422sp",
};

const char* res_str[] = {
    "cif",
    "qcif",
    "480p",
    "720p",
    "1080p",
};
const char* wh_str[] = {
    "352x288",
    "176x144",
    "720x480",
    "1280x720",
    "1920x1080",
};

int idx = -1;
fmt_idx = -2; // trick...

#if 0
len = strlen(filename);
str_debug(“org string len:%d %s\b”, len, filename);
#endif

// 查找后缀名
tmp = strrchr(filename, '.');
if (tmp != NULL)
{
    strncpy(c_file, filename, tmp-filename);
    pos = strlen(tmp+1);
    //str_debug("find ext: %s(%d) %s %s %d\n", tmp+1, pos, filename, c_file, tmp-filename);
    // 查找格式字符串
    for (i = 0; i < ARRAY_ELEMS(fmt_str); i++)
    {
        p = strstr(tmp+1, fmt_str[i]);
        if (p != NULL)
        {
            strncpy(c_fmt, p, strlen(fmt_str[i]));
            idx = i;
        }
    }
}
else
{
    strcpy(c_file, filename);
}
str_debug("second string:%s \n", c_file);
if (idx == 0 && pos != 1) idx = -1;
if (idx == 13) idx = 9;
if (idx == 14) idx = 11;
// 这里打印的是最大匹配的
if (idx != -1)
    str_debug("fmt(externsion)[%d]: %s(=%s)\n", idx, c_fmt, fmt_str[idx]);    

// 查找格式字符串
for (i = 0; i < ARRAY_ELEMS(fmt_str); i++)
{
    p = strstr(c_file, fmt_str[i]);
    //str_debug("p: %s\n", p);
    if (p != NULL)
    {
        strncpy(c_fmt, p, strlen(fmt_str[i]));
        fmt_idx = i;
    }
}
if (fmt_idx == 13) fmt_idx = 9;
if (fmt_idx == 14) fmt_idx = 11;
// 这里打印的是最大匹配的
if (fmt_idx != -1)
    str_debug("fmt[%d]: %s(=%s)\n", fmt_idx, c_fmt, fmt_str[fmt_idx]);

if (idx != -1 && fmt_idx == -1) fmt_idx = idx;
if (fmt_idx != -1)
    str_debug("---final fmt[%d]: %s(=%s)---\n", fmt_idx, c_fmt, fmt_str[fmt_idx]);

fmt_idx+=1;

// 查找分辨率字符串
for (i = 0; i < ARRAY_ELEMS(res_str); i++)
{
    //str_debug("res--: %s\n", res_str[i]);
    p = strstr(c_file, res_str[i]);
    if (p != NULL)
    {
        strncpy(c_res, p, strlen(res_str[i]));
        idx = i;
        //str_debug("res: %s\n", c_res);
    }
}

if (idx != -1)
{
    sscanf(wh_str[idx], "%dx%d", &width, &height);
    str_debug("res[%d]: %s %d %d\n", idx, c_res, width, height);
}
//////////////////////

//  解析宽高
len = strlen(c_file);
pos = strcspn(c_file, "xX");
if (len == pos) // 没有找到直接返回
{
    str_debug("---final width: %d height: %d---\n", width, height);
    return;
}
tmp = c_file + pos;
str_debug("find1 x[%d len: %d] %s\n", pos, len, tmp);

//return;
p = c_file;
len = len - pos + 1;
j = pos;
// 找到'x'前面的数字
for (i = 0; i < len && j > 0; i++)
{
    str_debug("pos: %d %c\n", j, p[j]);
    if (!isdigit(p[--j]))
    {
        j++;
        break;
    }
}
str_debug("before x i:%d j: %d tmp: %s\n", i, j, p+j);
strncpy(c_width, p+j, i);
width = atoi(c_width);
str_debug("c_width: %s %d\n", c_width, width);

// 找到'x'后面的数字
p = c_file + pos+1; // 跳过'x'
len = p - c_file;
str_debug("after find x[%d] %s\n", pos, p);
for (i = 0; i < len; i++)
{
    if (!isdigit(p[i]))
        break;
}
strncpy(c_height, p, i);
height = atoi(c_height);
str_debug("c_height: %s %d\n", c_height, height);

if (idx == -1 && (width == 0 || height == 0))
    width = height = -1;
if (idx != -1 && (width == 0 || height == 0))
    sscanf(wh_str[idx], "%dx%d", &width, &height);
str_debug("---final width: %d height: %d---\n", width, height);

str_debug("\n");

}

```
YUV格式排列是根据界面上YUV格式的顺序,当找到一个格式时,则返回其索引时,直接使用即可。至于宽高,则使用strcspn函数来查找“x”前后的数字。一个简单功能代码,占用差不多200行代码,一来是技术问题,二来有很多逻辑处理,如YUV格式,可以在文件名给出,也可以通过后缀名给出,分辨率可以直接用qcif、1080p这类的熟知的方法,也可以使用176x144这类的方式,另外还有处理同时存在不同的格式的优化级。当然,按正常使用情况下,这个函数是可以正常工作的。

李迟 2015.8.16 周日 上午