Пример #1
0
void
gen75_update_avc_frame_store_index(
    VADriverContextP              ctx,
    struct decode_state          *decode_state,
    VAPictureParameterBufferH264 *pic_param,
    GenFrameStore                 frame_store[MAX_GEN_REFERENCE_FRAMES]
)
{
    int i, n;

    /* Construct the Frame Store array, in compact form. i.e. empty or
       invalid entries are discarded. */
    for (i = 0, n = 0; i < ARRAY_ELEMS(decode_state->reference_objects); i++) {
        struct object_surface * const obj_surface =
            decode_state->reference_objects[i];
        if (!obj_surface)
            continue;

        GenFrameStore * const fs = &frame_store[n];
        fs->surface_id = obj_surface->base.id;
        fs->obj_surface = obj_surface;
        fs->frame_store_id = n++;
    }

    /* Any remaining entry is marked as invalid */
    for (; n < MAX_GEN_REFERENCE_FRAMES; n++) {
        GenFrameStore * const fs = &frame_store[n];
        fs->surface_id = VA_INVALID_ID;
        fs->obj_surface = NULL;
        fs->frame_store_id = -1;
    }
}
Пример #2
0
uint32_t image_rgba_format(
    int          bits_per_pixel,
    int          is_msb_first,
    unsigned int red_mask,
    unsigned int green_mask,
    unsigned int blue_mask,
    unsigned int alpha_mask
)
{
    static const struct {
        int             fourcc;
        unsigned char   bits_per_pixel;
        unsigned char   is_msb_first;
        unsigned int    red_mask;
        unsigned int    green_mask;
        unsigned int    blue_mask;
        unsigned int    alpha_mask;
    }
#define BE 1
#define LE 0
#ifdef WORDS_BIGENDIAN
#define NE BE
#define OE LE
#else
#define NE LE
#define OE BE
#endif
    pixfmts[] = {
        { IMAGE_FORMAT_NE(ABGR, RGBA),
          32, NE, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
        { IMAGE_FORMAT_NE(ABGR, RGBA),
          32, OE, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff },
        { IMAGE_FORMAT_NE(ARGB, BGRA),
          32, NE, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
        { IMAGE_FORMAT_NE(ARGB, BGRA),
          32, OE, 0x0000ff00, 0x00ff0000, 0xff000000, 0x000000ff },
        { IMAGE_FORMAT_NE(RGBA, ABGR),
          32, NE, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff },
        { IMAGE_FORMAT_NE(RGBA, ABGR),
          32, OE, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
    };
    int i;
    for (i = 0; i < ARRAY_ELEMS(pixfmts); i++) {
        if (pixfmts[i].bits_per_pixel == bits_per_pixel &&
            pixfmts[i].is_msb_first   == is_msb_first   &&
            pixfmts[i].red_mask       == red_mask       &&
            pixfmts[i].green_mask     == green_mask     &&
            pixfmts[i].blue_mask      == blue_mask      &&
            pixfmts[i].alpha_mask     == alpha_mask)
            return pixfmts[i].fourcc;
    }
    return 0;
}
// vaQueryConfigProfiles
VAStatus
vdpau_QueryConfigProfiles(
    VADriverContextP    ctx,
    VAProfile          *profile_list,
    int                *num_profiles
)
{
    VDPAU_DRIVER_DATA_INIT;

    static const VAProfile va_profiles[] = {
        VAProfileMPEG2Simple,
        VAProfileMPEG2Main,
        VAProfileMPEG4Simple,
        VAProfileMPEG4AdvancedSimple,
        VAProfileMPEG4Main,
        VAProfileH264Baseline,
        VAProfileH264Main,
        VAProfileH264High,
        VAProfileVC1Simple,
        VAProfileVC1Main,
        VAProfileVC1Advanced
    };

    int i, n = 0;
    for (i = 0; i < ARRAY_ELEMS(va_profiles); i++) {
        VAProfile profile = va_profiles[i];
        VdpDecoderProfile vdp_profile = get_VdpDecoderProfile(profile);
        if (is_supported_profile(driver_data, vdp_profile))
            profile_list[n++] = profile;
    }

    /* If the assert fails then VDPAU_MAX_PROFILES needs to be bigger */
    ASSERT(n <= VDPAU_MAX_PROFILES);
    if (num_profiles)
        *num_profiles = n;

    return VA_STATUS_SUCCESS;
}
Пример #4
0
VOID
media_destroy_context (struct object_heap *heap, struct object_base *obj)
{
  struct object_context *obj_context = (struct object_context *) obj;
  INT i;

  if (obj_context->hw_context)
    {
      obj_context->hw_context->destroy (obj_context->hw_context);
      obj_context->hw_context = NULL;
    }

  if (obj_context->codec_type == CODEC_ENC)
    {
      MEDIA_DRV_ASSERT (obj_context->codec_state.encode.num_slice_params <=
			obj_context->codec_state.encode.max_slice_params);
      media_release_buffer_store (&obj_context->codec_state.encode.pic_param);
      media_release_buffer_store (&obj_context->codec_state.encode.seq_param);
      media_release_buffer_store (&obj_context->codec_state.encode.q_matrix);
      for (i = 0; i < obj_context->codec_state.encode.num_slice_params; i++)
	media_release_buffer_store (&obj_context->codec_state.encode.
				    slice_params[i]);

      media_drv_free_memory (obj_context->codec_state.encode.slice_params);

      MEDIA_DRV_ASSERT (obj_context->codec_state.encode.
			num_slice_params_ext <=
			obj_context->codec_state.encode.max_slice_params_ext);
      media_release_buffer_store (&obj_context->codec_state.encode.
				  pic_param_ext);
      media_release_buffer_store (&obj_context->codec_state.encode.
				  seq_param_ext);
      media_release_buffer_store (&obj_context->codec_state.
				  encode.frame_update_param);

      for (i = 0;
	   i <
	   ARRAY_ELEMS (obj_context->codec_state.encode.packed_header_param);
	   i++)
	media_release_buffer_store (&obj_context->codec_state.encode.
				    packed_header_param[i]);

      for (i = 0;
	   i <
	   ARRAY_ELEMS (obj_context->codec_state.encode.packed_header_data);
	   i++)
	media_release_buffer_store (&obj_context->codec_state.encode.
				    packed_header_data[i]);

      for (i = 0;
	   i < ARRAY_ELEMS (obj_context->codec_state.encode.misc_param); i++)
	media_release_buffer_store (&obj_context->codec_state.encode.
				    misc_param[i]);

      for (i = 0; i < obj_context->codec_state.encode.num_slice_params_ext;
	   i++)
	media_release_buffer_store (&obj_context->codec_state.encode.
				    slice_params_ext[i]);

      media_drv_free_memory (obj_context->codec_state.encode.
			     slice_params_ext);
    }
    else if (obj_context->codec_type == CODEC_DEC)
    {
      media_release_buffer_store(&obj_context->codec_state.decode.pic_param);
      media_release_buffer_store(&obj_context->codec_state.decode.iq_matrix);
      media_release_buffer_store(&obj_context->codec_state.decode.bit_plane);
      media_release_buffer_store(&obj_context->codec_state.decode.huffman_table);

      for (i = 0; i < obj_context->codec_state.decode.num_slice_params; i++) {
        media_release_buffer_store(&obj_context->codec_state.decode.slice_params[i]);
        media_release_buffer_store(&obj_context->codec_state.decode.slice_datas[i]);
      }

      media_drv_free_memory (obj_context->codec_state.decode.slice_params);
      media_drv_free_memory (obj_context->codec_state.decode.slice_datas);
    }

  media_drv_free_memory (obj_context->render_targets);
  object_heap_free (heap, obj);
}
Пример #5
0
int vaapi_exit(void)
{
    VAAPIContext * const vaapi = vaapi_get_context();
    unsigned int i;

    if (!vaapi)
        return 0;

#if USE_GLX
    if (display_type() == DISPLAY_GLX)
        vaapi_glx_destroy_surface();
#endif

    destroy_buffers(vaapi->display, &vaapi->pic_param_buf_id, 1);
    destroy_buffers(vaapi->display, &vaapi->iq_matrix_buf_id, 1);
    destroy_buffers(vaapi->display, &vaapi->bitplane_buf_id, 1);
    destroy_buffers(vaapi->display, vaapi->slice_buf_ids, vaapi->n_slice_buf_ids);

    if (vaapi->subpic_flags) {
        free(vaapi->subpic_flags);
        vaapi->subpic_flags = NULL;
    }

    if (vaapi->subpic_formats) {
        free(vaapi->subpic_formats);
        vaapi->subpic_formats = NULL;
        vaapi->n_subpic_formats = 0;
    }

    if (vaapi->image_formats) {
        free(vaapi->image_formats);
        vaapi->image_formats = NULL;
        vaapi->n_image_formats = 0;
    }

    if (vaapi->entrypoints) {
        free(vaapi->entrypoints);
        vaapi->entrypoints = NULL;
        vaapi->n_entrypoints = 0;
    }

    if (vaapi->profiles) {
        free(vaapi->profiles);
        vaapi->profiles = NULL;
        vaapi->n_profiles = 0;
    }

    if (vaapi->slice_params) {
        free(vaapi->slice_params);
        vaapi->slice_params = NULL;
        vaapi->slice_params_alloc = 0;
        vaapi->n_slice_params = 0;
    }

    if (vaapi->slice_buf_ids) {
        free(vaapi->slice_buf_ids);
        vaapi->slice_buf_ids = NULL;
        vaapi->n_slice_buf_ids = 0;
    }

    if (vaapi->subpic_image.image_id != VA_INVALID_ID) {
        vaDestroyImage(vaapi->display, vaapi->subpic_image.image_id);
        vaapi->subpic_image.image_id = VA_INVALID_ID;
    }

    for (i = 0; i < ARRAY_ELEMS(vaapi->subpic_ids); i++) {
        if (vaapi->subpic_ids[i] != VA_INVALID_ID) {
            vaDestroySubpicture(vaapi->display, vaapi->subpic_ids[i]);
            vaapi->subpic_ids[i] = VA_INVALID_ID;
        }
    }

    if (vaapi->surface_id) {
        vaDestroySurfaces(vaapi->display, &vaapi->surface_id, 1);
        vaapi->surface_id = 0;
    }

    if (vaapi->context_id) {
        vaDestroyContext(vaapi->display, vaapi->context_id);
        vaapi->context_id = 0;
    }

    if (vaapi->config_id) {
        vaDestroyConfig(vaapi->display, vaapi->config_id);
        vaapi->config_id = 0;
    }

    if (vaapi->display) {
        vaTerminate(vaapi->display);
        vaapi->display = NULL;
    }

    free(vaapi_context);
    return 0;
}
Пример #6
0
int vaapi_init(VADisplay display)
{
#if 0
    CommonContext * common = common_get_context();
#endif
    VAAPIContext *vaapi;
    int major_version, minor_version;
    int i, num_display_attrs, max_display_attrs;
    VADisplayAttribute *display_attrs;
    VAStatus status;

    if (vaapi_context)
        return 0;

    if (!display)
        return -1;
    D(bug("VA display %p\n", display));

    status = vaInitialize(display, &major_version, &minor_version);
    if (!vaapi_check_status(status, "vaInitialize()"))
        return -1;
    D(bug("VA API version %d.%d\n", major_version, minor_version));

    max_display_attrs = vaMaxNumDisplayAttributes(display);
    display_attrs = malloc(max_display_attrs * sizeof(display_attrs[0]));
    if (!display_attrs)
        return -1;

    num_display_attrs = 0; /* XXX: workaround old GMA500 bug */
    status = vaQueryDisplayAttributes(display, display_attrs, &num_display_attrs);
    if (!vaapi_check_status(status, "vaQueryDisplayAttributes()")) {
        free(display_attrs);
        return -1;
    }
    D(bug("%d display attributes available\n", num_display_attrs));
    for (i = 0; i < num_display_attrs; i++) {
        VADisplayAttribute * const display_attr = &display_attrs[i];
        D(bug("  %-32s (%s/%s) min %d max %d value 0x%x\n",
              string_of_VADisplayAttribType(display_attr->type),
              (display_attr->flags & VA_DISPLAY_ATTRIB_GETTABLE) ? "get" : "---",
              (display_attr->flags & VA_DISPLAY_ATTRIB_SETTABLE) ? "set" : "---",
              display_attr->min_value,
              display_attr->max_value,
              display_attr->value));
    }
    free(display_attrs);

#if 0
    if (common->use_vaapi_background_color) {
        VADisplayAttribute attr;
        attr.type  = VADisplayAttribBackgroundColor;
        attr.value = common->vaapi_background_color;
        status = vaSetDisplayAttributes(display, &attr, 1);
        if (!vaapi_check_status(status, "vaSetDisplayAttributes()"))
            return -1;
    }
#endif

    if ((vaapi = calloc(1, sizeof(*vaapi))) == NULL)
        return -1;
    vaapi->display               = display;
    vaapi->subpic_image.image_id = VA_INVALID_ID;
    for (i = 0; i < ARRAY_ELEMS(vaapi->subpic_ids); i++)
        vaapi->subpic_ids[i]     = VA_INVALID_ID;

    vaapi_context = vaapi;
    return 0;
}
Пример #7
0
static VAStatus
intel_decoder_check_avc_parameter(VADriverContextP ctx,
                                  VAProfile h264_profile,
                                  struct decode_state *decode_state)
{
    struct i965_driver_data *i965 = i965_driver_data(ctx);
    VAPictureParameterBufferH264 *pic_param = (VAPictureParameterBufferH264 *)decode_state->pic_param->buffer;
    VAStatus va_status;
    struct object_surface *obj_surface;	
    int i;
    VASliceParameterBufferH264 *slice_param, *next_slice_param, *next_slice_group_param;
    int j;

    assert(!(pic_param->CurrPic.flags & VA_PICTURE_H264_INVALID));
    assert(pic_param->CurrPic.picture_id != VA_INVALID_SURFACE);

    if (pic_param->CurrPic.flags & VA_PICTURE_H264_INVALID ||
        pic_param->CurrPic.picture_id == VA_INVALID_SURFACE)
        goto error;

    assert(pic_param->CurrPic.picture_id == decode_state->current_render_target);

    if (pic_param->CurrPic.picture_id != decode_state->current_render_target)
        goto error;

    if ((h264_profile != VAProfileH264Baseline)) {
       if (pic_param->num_slice_groups_minus1 ||
           pic_param->pic_fields.bits.redundant_pic_cnt_present_flag) {
           WARN_ONCE("Unsupported the FMO/ASO constraints!!!\n");
           goto error;
       }
    }

    /* Fill in the reference objects array with the actual VA surface
       objects with 1:1 correspondance with any entry in ReferenceFrames[],
       i.e. including "holes" for invalid entries, that are expanded
       to NULL in the reference_objects[] array */
    for (i = 0; i < ARRAY_ELEMS(pic_param->ReferenceFrames); i++) {
        const VAPictureH264 * const va_pic = &pic_param->ReferenceFrames[i];

        obj_surface = NULL;
        if (!(va_pic->flags & VA_PICTURE_H264_INVALID) &&
            va_pic->picture_id != VA_INVALID_ID) {
            obj_surface = SURFACE(pic_param->ReferenceFrames[i].picture_id);
            if (!obj_surface)
                return VA_STATUS_ERROR_INVALID_SURFACE;

            /*
             * Sometimes a dummy frame comes from the upper layer
             * library, call i965_check_alloc_surface_bo() to make
             * sure the store buffer is allocated for this reference
             * frame
             */
            va_status = avc_ensure_surface_bo(ctx, decode_state, obj_surface,
                pic_param);
            if (va_status != VA_STATUS_SUCCESS)
                return va_status;
        }
        decode_state->reference_objects[i] = obj_surface;
    }

    for (j = 0; j < decode_state->num_slice_params; j++) {
        assert(decode_state->slice_params && decode_state->slice_params[j]->buffer);
        slice_param = (VASliceParameterBufferH264 *)decode_state->slice_params[j]->buffer;

        if (j == decode_state->num_slice_params - 1)
            next_slice_group_param = NULL;
        else
            next_slice_group_param = (VASliceParameterBufferH264 *)decode_state->slice_params[j + 1]->buffer;

        for (i = 0; i < decode_state->slice_params[j]->num_elements; i++) {

            if (i < decode_state->slice_params[j]->num_elements - 1)
                next_slice_param = slice_param + 1;
            else
                next_slice_param = next_slice_group_param;

            if (next_slice_param != NULL) {
                /* If the mb position of next_slice is less than or equal to the current slice,
                 * discard the current frame.
                 */
                if (next_slice_param->first_mb_in_slice <= slice_param->first_mb_in_slice) {
                    next_slice_param = NULL;
                    WARN_ONCE("!!!incorrect slice_param. The first_mb_in_slice of next_slice is less"
                               " than or equal to that in current slice\n");
                    goto error;
                }
            }
        }
    }

    return VA_STATUS_SUCCESS;

error:
    return VA_STATUS_ERROR_INVALID_PARAMETER;
}
Пример #8
0
void
intel_update_avc_frame_store_index(
    VADriverContextP              ctx,
    struct decode_state          *decode_state,
    VAPictureParameterBufferH264 *pic_param,
    GenFrameStore                 frame_store[MAX_GEN_REFERENCE_FRAMES],
    GenFrameStoreContext         *fs_ctx
)
{
    GenFrameStore *free_refs[MAX_GEN_REFERENCE_FRAMES];
    uint32_t used_refs = 0, add_refs = 0;
    uint64_t age;
    int i, n, num_free_refs;

    /* Detect changes of access unit */
    const int poc = avc_get_picture_poc(&pic_param->CurrPic);
    if (fs_ctx->age == 0 || fs_ctx->prev_poc != poc)
        fs_ctx->age++;
    fs_ctx->prev_poc = poc;
    age = fs_ctx->age;

    /* Tag entries that are still available in our Frame Store */
    for (i = 0; i < ARRAY_ELEMS(decode_state->reference_objects); i++) {
        struct object_surface * const obj_surface =
            decode_state->reference_objects[i];
        if (!obj_surface)
            continue;

        GenAvcSurface * const avc_surface = obj_surface->private_data;
        if (!avc_surface)
            continue;
        if (avc_surface->frame_store_id >= 0) {
            GenFrameStore * const fs =
                &frame_store[avc_surface->frame_store_id];
            if (fs->surface_id == obj_surface->base.id) {
                fs->obj_surface = obj_surface;
                fs->ref_age = age;
                used_refs |= 1 << fs->frame_store_id;
                continue;
            }
        }
        add_refs |= 1 << i;
    }

    /* Build and sort out the list of retired candidates. The resulting
       list is ordered by increasing age when they were last used */
    for (i = 0, n = 0; i < MAX_GEN_REFERENCE_FRAMES; i++) {
        if (!(used_refs & (1 << i))) {
            GenFrameStore * const fs = &frame_store[i];
            fs->obj_surface = NULL;
            free_refs[n++] = fs;
        }
    }
    num_free_refs = n;
    qsort(&free_refs[0], n, sizeof(free_refs[0]), compare_avc_ref_store_func);

    /* Append the new reference frames */
    for (i = 0, n = 0; i < ARRAY_ELEMS(decode_state->reference_objects); i++) {
        struct object_surface * const obj_surface =
            decode_state->reference_objects[i];
        if (!obj_surface || !(add_refs & (1 << i)))
            continue;

        GenAvcSurface * const avc_surface = obj_surface->private_data;
        if (!avc_surface)
            continue;
        if (n < num_free_refs) {
            GenFrameStore * const fs = free_refs[n++];
            fs->surface_id = obj_surface->base.id;
            fs->obj_surface = obj_surface;
            fs->frame_store_id = fs - frame_store;
            fs->ref_age = age;
            avc_surface->frame_store_id = fs->frame_store_id;
            continue;
        }
        WARN_ONCE("No free slot found for DPB reference list!!!\n");
    }
}
Пример #9
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",
        "rgb",
        "bgr",
        "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;
    // 处理sp字符串
    if (idx == 15) idx = 9;
    if (idx == 16) 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 == 15) fmt_idx = 9;
    if (fmt_idx == 16) fmt_idx = 11;
    // 这里打印的是最大匹配的
    if (fmt_idx != -2)
        str_debug("fmt[%d]: %s(=%s)\n", fmt_idx, c_fmt, fmt_str[fmt_idx]);

    if (idx != -1 && fmt_idx == -2) fmt_idx = idx;
    if (fmt_idx != -2)
        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");
}