当前位置: 首页 > Windows程序 > 正文

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

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

#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 周日 上午

本文固定链接: http://www.latelee.org/programming-under-windows/yuvplayer-find-resolution.html

如无特别说明,迟思堂工作室文章均为原创,转载请注明: 我的YUV播放器MFC小笔记:解析文件名称 | 迟思堂工作室

目前暂无评论

发表评论

*

快捷键:Ctrl+Enter