mfxStatus CVAAPIDeviceX11::RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * /*pmfxAlloc*/) { VAStatus va_res = VA_STATUS_SUCCESS; mfxStatus mfx_res = MFX_ERR_NONE; vaapiMemId * memId = NULL; VASurfaceID surface; Display* display = VAAPI_GET_X_DISPLAY(m_X11LibVA.GetXDisplay()); Window* window = VAAPI_GET_X_WINDOW(m_window); if(!window || !(*window)) mfx_res = MFX_ERR_NOT_INITIALIZED; // should MFX_ERR_NONE be returned below considuring situation as EOS? if ((MFX_ERR_NONE == mfx_res) && NULL == pSurface) mfx_res = MFX_ERR_NULL_PTR; if (MFX_ERR_NONE == mfx_res) { memId = (vaapiMemId*)(pSurface->Data.MemId); if (!memId || !memId->m_surface) mfx_res = MFX_ERR_NULL_PTR; } if (MFX_ERR_NONE == mfx_res) { VADisplay dpy = m_X11LibVA.GetVADisplay(); VADisplay rnddpy = m_X11LibVA.GetVADisplay(true); VASurfaceID rndsrf; void* ctx; surface = *memId->m_surface; va_res = m_X11LibVA.AcquireVASurface(&ctx, dpy, surface, rnddpy, &rndsrf); mfx_res = va_to_mfx_status(va_res); if (MFX_ERR_NONE != mfx_res) return mfx_res; MfxLoader::XLib_Proxy & x11lib = m_X11LibVA.GetX11(); x11lib.XResizeWindow(display, *window, pSurface->Info.CropW, pSurface->Info.CropH); MfxLoader::VA_X11Proxy & vax11lib = m_X11LibVA.GetVAX11(); va_res = vax11lib.vaPutSurface(rnddpy, rndsrf, *window, pSurface->Info.CropX, pSurface->Info.CropY, pSurface->Info.CropX + pSurface->Info.CropW, pSurface->Info.CropY + pSurface->Info.CropH, pSurface->Info.CropX, pSurface->Info.CropY, pSurface->Info.CropX + pSurface->Info.CropW, pSurface->Info.CropY + pSurface->Info.CropH, NULL, 0, VA_FRAME_PICTURE); mfx_res = va_to_mfx_status(va_res); x11lib.XSync(display, False); m_X11LibVA.ReleaseVASurface(ctx, dpy, surface, rnddpy, rndsrf); } return mfx_res; }
mfxStatus vaapiFrameAllocator::LockFrame(mfxMemId mid, mfxFrameData *ptr) { mfxStatus mfx_res = MFX_ERR_NONE; VAStatus va_res = VA_STATUS_SUCCESS; vaapiMemId* vaapi_mid = (vaapiMemId*)mid; mfxU8* pBuffer = 0; VASurfaceAttrib attrib; if (!vaapi_mid || !(vaapi_mid->m_surface)) return MFX_ERR_INVALID_HANDLE; mfxU32 mfx_fourcc = ConvertVP8FourccToMfxFourcc(vaapi_mid->m_fourcc); if (MFX_FOURCC_P8 == mfx_fourcc) // bitstream processing { VACodedBufferSegment *coded_buffer_segment; if (vaapi_mid->m_fourcc == MFX_FOURCC_VP8_SEGMAP) va_res = m_libva->vaMapBuffer(m_dpy, *(vaapi_mid->m_surface), (void **)(&pBuffer)); else va_res = m_libva->vaMapBuffer(m_dpy, *(vaapi_mid->m_surface), (void **)(&coded_buffer_segment)); mfx_res = va_to_mfx_status(va_res); if (MFX_ERR_NONE == mfx_res) { if (vaapi_mid->m_fourcc == MFX_FOURCC_VP8_SEGMAP) ptr->Y = pBuffer; else ptr->Y = (mfxU8*)coded_buffer_segment->buf; } } else // Image processing { va_res = m_libva->vaSyncSurface(m_dpy, *(vaapi_mid->m_surface)); mfx_res = va_to_mfx_status(va_res); if (MFX_ERR_NONE == mfx_res) { va_res = m_libva->vaDeriveImage(m_dpy, *(vaapi_mid->m_surface), &(vaapi_mid->m_image)); mfx_res = va_to_mfx_status(va_res); } if (MFX_ERR_NONE == mfx_res) { va_res = m_libva->vaMapBuffer(m_dpy, vaapi_mid->m_image.buf, (void **) &pBuffer); mfx_res = va_to_mfx_status(va_res); } if (MFX_ERR_NONE == mfx_res) { switch (vaapi_mid->m_image.format.fourcc) { case VA_FOURCC_NV12: if (mfx_fourcc == MFX_FOURCC_NV12) { ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0]; ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0]; ptr->U = pBuffer + vaapi_mid->m_image.offsets[1]; ptr->V = ptr->U + 1; } else mfx_res = MFX_ERR_LOCK_MEMORY; break; case VA_FOURCC_YV12: if (mfx_fourcc == MFX_FOURCC_YV12) { ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0]; ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0]; ptr->V = pBuffer + vaapi_mid->m_image.offsets[1]; ptr->U = pBuffer + vaapi_mid->m_image.offsets[2]; } else mfx_res = MFX_ERR_LOCK_MEMORY; break; case VA_FOURCC_YUY2: if (mfx_fourcc == MFX_FOURCC_YUY2) { ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0]; ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0]; ptr->U = ptr->Y + 1; ptr->V = ptr->Y + 3; } else mfx_res = MFX_ERR_LOCK_MEMORY; break; case VA_FOURCC_UYVY: if (mfx_fourcc == MFX_FOURCC_UYVY) { ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0]; ptr->U = pBuffer + vaapi_mid->m_image.offsets[0]; ptr->Y = ptr->U + 1; ptr->V = ptr->U + 2; } else mfx_res = MFX_ERR_LOCK_MEMORY; break; case VA_FOURCC_ARGB: if (mfx_fourcc == MFX_FOURCC_RGB4) { ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0]; ptr->B = pBuffer + vaapi_mid->m_image.offsets[0]; ptr->G = ptr->B + 1; ptr->R = ptr->B + 2; ptr->A = ptr->B + 3; } else mfx_res = MFX_ERR_LOCK_MEMORY; break; case VA_FOURCC_P208: if (mfx_fourcc == MFX_FOURCC_NV12) { ptr->Pitch = (mfxU16)vaapi_mid->m_image.pitches[0]; ptr->Y = pBuffer + vaapi_mid->m_image.offsets[0]; } else mfx_res = MFX_ERR_LOCK_MEMORY; break; default: mfx_res = MFX_ERR_LOCK_MEMORY; break; } } } return mfx_res; }
mfxStatus vaapiFrameAllocator::AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response) { mfxStatus mfx_res = MFX_ERR_NONE; VAStatus va_res = VA_STATUS_SUCCESS; unsigned int va_fourcc = 0; VASurfaceID* surfaces = NULL; VASurfaceAttrib attrib; vaapiMemId *vaapi_mids = NULL, *vaapi_mid = NULL; mfxMemId* mids = NULL; mfxU32 fourcc = request->Info.FourCC; mfxU16 surfaces_num = request->NumFrameSuggested, numAllocated = 0, i = 0; bool bCreateSrfSucceeded = false; memset(response, 0, sizeof(mfxFrameAllocResponse)); // VP8 hybrid driver has weird requirements for allocation of surfaces/buffers for VP8 encoding // to comply with them additional logic is required to support regular and VP8 hybrid allocation pathes mfxU32 mfx_fourcc = ConvertVP8FourccToMfxFourcc(fourcc); va_fourcc = ConvertMfxFourccToVAFormat(mfx_fourcc); if (!va_fourcc || ((VA_FOURCC_NV12 != va_fourcc) && (VA_FOURCC_YV12 != va_fourcc) && (VA_FOURCC_YUY2 != va_fourcc) && (VA_FOURCC_UYVY != va_fourcc) && (VA_FOURCC_ARGB != va_fourcc) && (VA_FOURCC_P208 != va_fourcc))) { return MFX_ERR_MEMORY_ALLOC; } if (!surfaces_num) { return MFX_ERR_MEMORY_ALLOC; } if (MFX_ERR_NONE == mfx_res) { surfaces = (VASurfaceID*)calloc(surfaces_num, sizeof(VASurfaceID)); vaapi_mids = (vaapiMemId*)calloc(surfaces_num, sizeof(vaapiMemId)); mids = (mfxMemId*)calloc(surfaces_num, sizeof(mfxMemId)); if ((NULL == surfaces) || (NULL == vaapi_mids) || (NULL == mids)) mfx_res = MFX_ERR_MEMORY_ALLOC; } if (MFX_ERR_NONE == mfx_res) { if( VA_FOURCC_P208 != va_fourcc ) { unsigned int format; attrib.type = VASurfaceAttribPixelFormat; attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; attrib.value.type = VAGenericValueTypeInteger; attrib.value.value.i = va_fourcc; format = va_fourcc; if (fourcc == MFX_FOURCC_VP8_NV12) { // special configuration for NV12 surf allocation for VP8 hybrid encoder is required attrib.type = (VASurfaceAttribType)VASurfaceAttribUsageHint; attrib.value.value.i = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER; } else if (fourcc == MFX_FOURCC_VP8_MBDATA) { // special configuration for MB data surf allocation for VP8 hybrid encoder is required attrib.value.value.i = VA_FOURCC_P208; format = VA_FOURCC_P208; } else if (va_fourcc == VA_FOURCC_NV12) { format = VA_RT_FORMAT_YUV420; } else if (va_fourcc == VA_FOURCC_UYVY) { format = VA_RT_FORMAT_YUV422; } va_res = m_libva->vaCreateSurfaces(m_dpy, format, request->Info.Width, request->Info.Height, surfaces, surfaces_num, &attrib, 1); mfx_res = va_to_mfx_status(va_res); bCreateSrfSucceeded = (MFX_ERR_NONE == mfx_res); } else { VAContextID context_id = request->AllocId; int codedbuf_size; int width32 = 32 * ((request->Info.Width + 31) >> 5); int height32 = 32 * ((request->Info.Height + 31) >> 5); VABufferType codedbuf_type; if (fourcc == MFX_FOURCC_VP8_SEGMAP) { codedbuf_size = request->Info.Width * request->Info.Height; codedbuf_type = (VABufferType)VAEncMacroblockMapBufferType; } else { codedbuf_size = static_cast<int>((width32 * height32) * 400LL / (16 * 16)); codedbuf_type = VAEncCodedBufferType; } for (numAllocated = 0; numAllocated < surfaces_num; numAllocated++) { VABufferID coded_buf; va_res = m_libva->vaCreateBuffer(m_dpy, context_id, codedbuf_type, codedbuf_size, 1, NULL, &coded_buf); mfx_res = va_to_mfx_status(va_res); if (MFX_ERR_NONE != mfx_res) break; surfaces[numAllocated] = coded_buf; } } } if ((MFX_ERR_NONE == mfx_res) && (request->Type & MFX_MEMTYPE_EXPORT_FRAME)) { if (m_export_mode == vaapiAllocatorParams::DONOT_EXPORT) { mfx_res = MFX_ERR_UNKNOWN; } for (i=0; i < surfaces_num; ++i) { if (m_export_mode & vaapiAllocatorParams::NATIVE_EXPORT_MASK) { #ifndef DISABLE_VAAPI_BUFFER_EXPORT vaapi_mids[i].m_buffer_info.mem_type = (m_export_mode & vaapiAllocatorParams::PRIME)? VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM; va_res = m_libva->vaDeriveImage(m_dpy, surfaces[i], &(vaapi_mids[i].m_image)); mfx_res = va_to_mfx_status(va_res); if (MFX_ERR_NONE != mfx_res) break; va_res = m_libva->vaAcquireBufferHandle(m_dpy, vaapi_mids[i].m_image.buf, &(vaapi_mids[i].m_buffer_info)); #else va_res = VA_STATUS_ERROR_OPERATION_FAILED; #endif mfx_res = va_to_mfx_status(va_res); } if (m_exporter) { vaapi_mids[i].m_custom = m_exporter->acquire(&vaapi_mids[i]); if (!vaapi_mids[i].m_custom) { mfx_res = MFX_ERR_UNKNOWN; break; } } } } if (MFX_ERR_NONE == mfx_res) { for (i = 0; i < surfaces_num; ++i) { vaapi_mid = &(vaapi_mids[i]); vaapi_mid->m_fourcc = fourcc; vaapi_mid->m_surface = &(surfaces[i]); mids[i] = vaapi_mid; } } if (MFX_ERR_NONE == mfx_res) { response->mids = mids; response->NumFrameActual = surfaces_num; } else // i.e. MFX_ERR_NONE != mfx_res { response->mids = NULL; response->NumFrameActual = 0; if (VA_FOURCC_P208 != va_fourcc || fourcc == MFX_FOURCC_VP8_MBDATA ) { if (bCreateSrfSucceeded) m_libva->vaDestroySurfaces(m_dpy, surfaces, surfaces_num); } else { for (i = 0; i < numAllocated; i++) m_libva->vaDestroyBuffer(m_dpy, surfaces[i]); } if (mids) { free(mids); mids = NULL; } if (vaapi_mids) { free(vaapi_mids); vaapi_mids = NULL; } if (surfaces) { free(surfaces); surfaces = NULL; } } return mfx_res; }
mfxStatus vaapiFrameAllocator::AllocImpl(mfxFrameAllocRequest *request, mfxFrameAllocResponse *response) { mfxStatus mfx_res = MFX_ERR_NONE; VAStatus va_res = VA_STATUS_SUCCESS; unsigned int va_fourcc = 0; VASurfaceID* surfaces = NULL; VASurfaceAttrib attrib; vaapiMemId *vaapi_mids = NULL, *vaapi_mid = NULL; mfxMemId* mids = NULL; mfxU32 fourcc = request->Info.FourCC; mfxU16 surfaces_num = request->NumFrameSuggested, numAllocated = 0, i = 0; bool bCreateSrfSucceeded = false; memset(response, 0, sizeof(mfxFrameAllocResponse)); va_fourcc = ConvertMfxFourccToVAFormat(fourcc); if (!va_fourcc || ((VA_FOURCC_NV12 != va_fourcc) && (VA_FOURCC_YV12 != va_fourcc) && (VA_FOURCC_YUY2 != va_fourcc) && (VA_FOURCC_ARGB != va_fourcc) && (VA_FOURCC_P208 != va_fourcc))) { return MFX_ERR_MEMORY_ALLOC; } if (!surfaces_num) { return MFX_ERR_MEMORY_ALLOC; } if (MFX_ERR_NONE == mfx_res) { surfaces = (VASurfaceID*)calloc(surfaces_num, sizeof(VASurfaceID)); vaapi_mids = (vaapiMemId*)calloc(surfaces_num, sizeof(vaapiMemId)); mids = (mfxMemId*)calloc(surfaces_num, sizeof(mfxMemId)); if ((NULL == surfaces) || (NULL == vaapi_mids) || (NULL == mids)) mfx_res = MFX_ERR_MEMORY_ALLOC; } if (MFX_ERR_NONE == mfx_res) { if( VA_FOURCC_P208 != va_fourcc ) { attrib.type = VASurfaceAttribPixelFormat; attrib.value.type = VAGenericValueTypeInteger; attrib.value.value.i = va_fourcc; attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; va_res = vaCreateSurfaces(m_dpy, VA_RT_FORMAT_YUV420, request->Info.Width, request->Info.Height, surfaces, surfaces_num, &attrib, 1); mfx_res = va_to_mfx_status(va_res); bCreateSrfSucceeded = (MFX_ERR_NONE == mfx_res); } else { VAContextID context_id = request->reserved[0]; int codedbuf_size = static_cast<int>((request->Info.Width * request->Info.Height) * 400LL / (16 * 16)); for (numAllocated = 0; numAllocated < surfaces_num; numAllocated++) { VABufferID coded_buf; va_res = vaCreateBuffer(m_dpy, context_id, VAEncCodedBufferType, codedbuf_size, 1, NULL, &coded_buf); mfx_res = va_to_mfx_status(va_res); if (MFX_ERR_NONE != mfx_res) break; surfaces[numAllocated] = coded_buf; } } } if (MFX_ERR_NONE == mfx_res) { for (i = 0; i < surfaces_num; ++i) { vaapi_mid = &(vaapi_mids[i]); vaapi_mid->m_fourcc = fourcc; vaapi_mid->m_surface = &(surfaces[i]); mids[i] = vaapi_mid; } } if (MFX_ERR_NONE == mfx_res) { response->mids = mids; response->NumFrameActual = surfaces_num; } else // i.e. MFX_ERR_NONE != mfx_res { response->mids = NULL; response->NumFrameActual = 0; if (VA_FOURCC_P208 != va_fourcc) { if (bCreateSrfSucceeded) vaDestroySurfaces(m_dpy, surfaces, surfaces_num); } else { for (i = 0; i < numAllocated; i++) vaDestroyBuffer(m_dpy, surfaces[i]); } if (mids) { free(mids); mids = NULL; } if (vaapi_mids) { free(vaapi_mids); vaapi_mids = NULL; } if (surfaces) { free(surfaces); surfaces = NULL; } } return mfx_res; }