virDomainVideoDefParseXML(virDomainXMLOptionPtr xmlopt,
                          xmlNodePtr node,
                          xmlXPathContextPtr ctxt,
                          unsigned int flags)
{
    virDomainVideoDefPtr def;
    xmlNodePtr cur;
    VIR_XPATH_NODE_AUTORESTORE(ctxt);
    g_autofree char *type = NULL;
    g_autofree char *driver_name = NULL;
    g_autofree char *heads = NULL;
    g_autofree char *vram = NULL;
    g_autofree char *vram64 = NULL;
    g_autofree char *ram = NULL;
    g_autofree char *vgamem = NULL;
    g_autofree char *primary = NULL;

    if (!(def = virDomainVideoDefNew(xmlopt)))
        return NULL;

    ctxt->node = node;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (!type && !vram && !ram && !heads &&
                virXMLNodeNameEqual(cur, "model")) {
                xmlNodePtr child;
                type = virXMLPropString(cur, "type");
                ram = virXMLPropString(cur, "ram");
                vram = virXMLPropString(cur, "vram");
                vram64 = virXMLPropString(cur, "vram64");
                vgamem = virXMLPropString(cur, "vgamem");
                heads = virXMLPropString(cur, "heads");

                if ((primary = virXMLPropString(cur, "primary")) != NULL) {
                    ignore_value(virStringParseYesNo(primary, &def->primary));
                    VIR_FREE(primary);
                }

                child = cur->children;
                while (child != NULL) {
                    if (child->type == XML_ELEMENT_NODE) {
                        if (def->accel == NULL &&
                            virXMLNodeNameEqual(child, "acceleration")) {
                            if ((def->accel = virDomainVideoAccelDefParseXML(child)) == NULL)
                                goto error;
                        }
                        if (def->res == NULL &&
                            virXMLNodeNameEqual(child, "resolution")) {
                            if ((def->res = virDomainVideoResolutionDefParseXML(child)) == NULL)
                                goto error;
                        }
                    }
                    child = child->next;
                }
            }
            if (virXMLNodeNameEqual(cur, "driver")) {
                if (virDomainVirtioOptionsParseXML(cur, &def->virtio) < 0)
                    goto error;
                driver_name = virXMLPropString(cur, "name");
            }
        }
        cur = cur->next;
    }

    if (type) {
        if ((def->type = virDomainVideoTypeFromString(type)) < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown video model '%s'"), type);
            goto error;
        }
    } else {
        def->type = VIR_DOMAIN_VIDEO_TYPE_DEFAULT;
    }

    if (driver_name) {
        int backend;
        if ((backend = virDomainVideoBackendTypeFromString(driver_name)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown video driver '%s'"), driver_name);
            goto error;
        }
        def->backend = backend;
    } else {
        def->backend = VIR_DOMAIN_VIDEO_BACKEND_TYPE_DEFAULT;
    }

    if (ram) {
        if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("ram attribute only supported for type of qxl"));
            goto error;
        }
        if (virStrToLong_uip(ram, NULL, 10, &def->ram) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse video ram '%s'"), ram);
            goto error;
        }
    }

    if (vram) {
        if (virStrToLong_uip(vram, NULL, 10, &def->vram) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse video vram '%s'"), vram);
            goto error;
        }
    }

    if (vram64) {
        if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("vram64 attribute only supported for type of qxl"));
            goto error;
        }
        if (virStrToLong_uip(vram64, NULL, 10, &def->vram64) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse video vram64 '%s'"), vram64);
            goto error;
        }
    }

    if (vgamem) {
        if (def->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("vgamem attribute only supported for type of qxl"));
            goto error;
        }
        if (virStrToLong_uip(vgamem, NULL, 10, &def->vgamem) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("cannot parse video vgamem '%s'"), vgamem);
            goto error;
        }
    }

    if (heads) {
        if (virStrToLong_uip(heads, NULL, 10, &def->heads) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse video heads '%s'"), heads);
            goto error;
        }
    }

    if (virDomainDeviceInfoParseXML(xmlopt, node, &def->info, flags) < 0)
        goto error;

    def->driver = virDomainVideoDriverDefParseXML(node);

    return def;

 error:
    virDomainVideoDefFree(def);
    return NULL;
}