VaApi::VaApi() { init = true; auto xdpy = QX11Info::display(); VADisplay display = m_display = vaGetDisplayGLX(xdpy); if (!check(display ? VA_STATUS_SUCCESS : VA_STATUS_ERROR_UNIMPLEMENTED, "Cannot create VADisplay.")) return; int major, minor; if (!check(vaInitialize(m_display, &major, &minor), "Cannot initialize VA-API.")) return; auto size = vaMaxNumProfiles(display); m_profiles.resize(size); if (!check(vaQueryConfigProfiles(display, m_profiles.data(), &size), "No available profiles.")) return; m_profiles.resize(size); for (auto profile : m_profiles) { int size = vaMaxNumEntrypoints(display); QVector<VAEntrypoint> entries(size); if (!isSuccess(vaQueryConfigEntrypoints(display, profile, entries.data(), &size))) continue; entries.resize(size); m_entries.insert(profile, entries); } initCodecs(); #ifdef USE_VAVPP initFilters(); #endif _Debug("VA-API is initialized."); ok = true; }
bool VaapiGlobalContext::init() { GNASH_REPORT_FUNCTION; VADisplay dpy = display(); VAStatus status; int num_profiles = 0; _profiles.resize(vaMaxNumProfiles(dpy)); status = vaQueryConfigProfiles(dpy, &_profiles[0], &num_profiles); if (!vaapi_check_status(status, "vaQueryConfigProfiles()")) { return false; } _profiles.resize(num_profiles); int num_image_formats = 0; _image_formats.resize(vaMaxNumImageFormats(dpy)); status = vaQueryImageFormats(dpy, &_image_formats[0], &num_image_formats); if (!vaapi_check_status(status, "vaQueryImageFormats()")) { return false; } _image_formats.resize(num_image_formats); unsigned int num_subpicture_formats = 0; std::vector<unsigned int> flags; flags.resize(vaMaxNumSubpictureFormats(dpy)); _subpicture_formats.resize(vaMaxNumSubpictureFormats(dpy)); status = vaQuerySubpictureFormats(dpy, &_subpicture_formats[0], &flags[0], &num_subpicture_formats); if (!vaapi_check_status(status, "vaQuerySubpictureFormats()")) { return false; } _subpicture_formats.resize(num_subpicture_formats); return true; }
bool VAApiWriter::open() { addParam( "Zoom" ); addParam( "AspectRatio" ); addParam( "Deinterlace" ); addParam( "PrepareForHWBobDeint", true ); addParam( "Hue" ); addParam( "Saturation" ); addParam( "Brightness" ); addParam( "Contrast" ); clr(); VADisp = vaGetDisplay( QX11Info::display() ); int minor, major; if ( vaInitialize( VADisp, &minor, &major ) == VA_STATUS_SUCCESS ) { const QString vendor = vaQueryVendorString( VADisp ); isVDPAU = vendor.contains( "VDPAU" ); if ( isVDPAU && !allowVDPAU ) return false; isXvBA = vendor.contains( "XvBA" ); int numProfiles = vaMaxNumProfiles( VADisp ); VAProfile profiles[ numProfiles ]; if ( vaQueryConfigProfiles( VADisp, profiles, &numProfiles ) == VA_STATUS_SUCCESS ) { for ( int i = 0 ; i < numProfiles ; ++i ) profileList.push_back( profiles[ i ] ); return true; } } return false; }
static int has_profile(VAAPIContext *vaapi, VAProfile profile) { VAStatus status; int i; if (!vaapi->profiles || vaapi->n_profiles == 0) { vaapi->profiles = calloc(vaMaxNumProfiles(vaapi->display), sizeof(vaapi->profiles[0])); status = vaQueryConfigProfiles(vaapi->display, vaapi->profiles, &vaapi->n_profiles); if (!vaapi_check_status(status, "vaQueryConfigProfiles()")) return 0; D(bug("%d profiles available\n", vaapi->n_profiles)); for (i = 0; i < vaapi->n_profiles; i++) D(bug(" %s\n", string_of_VAProfile(vaapi->profiles[i]))); } for (i = 0; i < vaapi->n_profiles; i++) { if (vaapi->profiles[i] == profile) return 1; } return 0; }
static bool IsVaProfileSupported(VADisplay dpy, VAProfile i_profile) { /* Check if the selected profile is supported */ if (i_profile == VAProfileNone) return true; int i_profiles_nb = vaMaxNumProfiles(dpy); if (i_profiles_nb < 0) return false; VAProfile *p_profiles_list = calloc(i_profiles_nb, sizeof(VAProfile)); if (!p_profiles_list) return false; bool b_supported_profile = false; VAStatus status = vaQueryConfigProfiles(dpy, p_profiles_list, &i_profiles_nb); if (status != VA_STATUS_SUCCESS) goto error; for (int i = 0; i < i_profiles_nb; i++) { if (p_profiles_list[i] == i_profile) { b_supported_profile = true; break; } } error: free(p_profiles_list); return b_supported_profile; }
VdpStatus softVdpDecoderQueryCapabilities(VdpDevice device, VdpDecoderProfile profile, VdpBool *is_supported, uint32_t *max_level, uint32_t *max_macroblocks, uint32_t *max_width, uint32_t *max_height) { VdpStatus err_code; if (!is_supported || !max_level || !max_macroblocks || !max_width || !max_height) return VDP_STATUS_INVALID_POINTER; VdpDeviceData *deviceData = handle_acquire(device, HANDLETYPE_DEVICE); if (NULL == deviceData) return VDP_STATUS_INVALID_HANDLE; *max_level = 0; *max_macroblocks = 0; *max_width = 0; *max_height = 0; if (!deviceData->va_available) { *is_supported = 0; err_code = VDP_STATUS_OK; goto quit; } VAProfile *va_profile_list = malloc(sizeof(VAProfile) * vaMaxNumProfiles(deviceData->va_dpy)); if (NULL == va_profile_list) { err_code = VDP_STATUS_RESOURCES; goto quit; } int num_profiles; VAStatus status = vaQueryConfigProfiles(deviceData->va_dpy, va_profile_list, &num_profiles); if (VA_STATUS_SUCCESS != status) { free(va_profile_list); err_code = VDP_STATUS_ERROR; goto quit; } struct { int mpeg2_simple; int mpeg2_main; int h264_baseline; int h264_main; int h264_high; int vc1_simple; int vc1_main; int vc1_advanced; } available_profiles = {0, 0, 0, 0, 0, 0, 0, 0}; for (int k = 0; k < num_profiles; k ++) { switch (va_profile_list[k]) { case VAProfileMPEG2Main: available_profiles.mpeg2_main = 0; /* fall through */ case VAProfileMPEG2Simple: available_profiles.mpeg2_simple = 0; break; case VAProfileH264High: available_profiles.h264_high = 1; /* fall through */ case VAProfileH264Main: available_profiles.h264_main = 1; /* fall through */ case VAProfileH264Baseline: available_profiles.h264_baseline = 1; /* fall though */ case VAProfileH264ConstrainedBaseline: break; case VAProfileVC1Advanced: available_profiles.vc1_advanced = 0; /* fall though */ case VAProfileVC1Main: available_profiles.vc1_main = 0; /* fall though */ case VAProfileVC1Simple: available_profiles.vc1_simple = 0; break; // unhandled profiles case VAProfileH263Baseline: case VAProfileJPEGBaseline: default: // do nothing break; } } free(va_profile_list); *is_supported = 0; // TODO: How to determine max width and height width libva? *max_width = 2048; *max_height = 2048; *max_macroblocks = 16384; switch (profile) { case VDP_DECODER_PROFILE_MPEG2_SIMPLE: *is_supported = available_profiles.mpeg2_simple; *max_level = VDP_DECODER_LEVEL_MPEG2_HL; break; case VDP_DECODER_PROFILE_MPEG2_MAIN: *is_supported = available_profiles.mpeg2_main; *max_level = VDP_DECODER_LEVEL_MPEG2_HL; break; case VDP_DECODER_PROFILE_H264_BASELINE: *is_supported = available_profiles.h264_baseline; // TODO: Do underlying libva really support 5.1? *max_level = VDP_DECODER_LEVEL_H264_5_1; break; case VDP_DECODER_PROFILE_H264_MAIN: *is_supported = available_profiles.h264_main; *max_level = VDP_DECODER_LEVEL_H264_5_1; break; case VDP_DECODER_PROFILE_H264_HIGH: *is_supported = available_profiles.h264_high; *max_level = VDP_DECODER_LEVEL_H264_5_1; break; case VDP_DECODER_PROFILE_VC1_SIMPLE: *is_supported = available_profiles.vc1_simple; *max_level = VDP_DECODER_LEVEL_VC1_SIMPLE_MEDIUM; break; case VDP_DECODER_PROFILE_VC1_MAIN: *is_supported = available_profiles.vc1_main; *max_level = VDP_DECODER_LEVEL_VC1_MAIN_HIGH; break; case VDP_DECODER_PROFILE_VC1_ADVANCED: *is_supported = available_profiles.vc1_advanced; *max_level = VDP_DECODER_LEVEL_VC1_ADVANCED_L4; break; // unsupported case VDP_DECODER_PROFILE_MPEG1: case VDP_DECODER_PROFILE_MPEG4_PART2_SP: case VDP_DECODER_PROFILE_MPEG4_PART2_ASP: case VDP_DECODER_PROFILE_DIVX4_QMOBILE: case VDP_DECODER_PROFILE_DIVX4_MOBILE: case VDP_DECODER_PROFILE_DIVX4_HOME_THEATER: case VDP_DECODER_PROFILE_DIVX4_HD_1080P: case VDP_DECODER_PROFILE_DIVX5_QMOBILE: case VDP_DECODER_PROFILE_DIVX5_MOBILE: case VDP_DECODER_PROFILE_DIVX5_HOME_THEATER: case VDP_DECODER_PROFILE_DIVX5_HD_1080P: default: break; } err_code = VDP_STATUS_OK; quit: handle_release(device); return err_code; }
static int Open( vlc_va_vaapi_t *p_va, int i_codec_id ) { VAProfile i_profile, *p_profiles_list; bool b_supported_profile = false; int i_profiles_nb = 0; int i_surface_count; /* */ switch( i_codec_id ) { case CODEC_ID_MPEG1VIDEO: case CODEC_ID_MPEG2VIDEO: i_profile = VAProfileMPEG2Main; i_surface_count = 2+1; break; case CODEC_ID_MPEG4: i_profile = VAProfileMPEG4AdvancedSimple; i_surface_count = 2+1; break; case CODEC_ID_WMV3: i_profile = VAProfileVC1Main; i_surface_count = 2+1; break; case CODEC_ID_VC1: i_profile = VAProfileVC1Advanced; i_surface_count = 2+1; break; case CODEC_ID_H264: i_profile = VAProfileH264High; i_surface_count = 16+1; break; default: return VLC_EGENERIC; } /* */ memset( p_va, 0, sizeof(*p_va) ); p_va->i_config_id = VA_INVALID_ID; p_va->i_context_id = VA_INVALID_ID; p_va->image.image_id = VA_INVALID_ID; /* Create a VA display */ p_va->p_display_x11 = XOpenDisplay(NULL); if( !p_va->p_display_x11 ) goto error; p_va->p_display = vaGetDisplay( p_va->p_display_x11 ); if( !p_va->p_display ) goto error; if( vaInitialize( p_va->p_display, &p_va->i_version_major, &p_va->i_version_minor ) ) goto error; /* Check if the selected profile is supported */ i_profiles_nb = vaMaxNumProfiles( p_va->p_display ); p_profiles_list = calloc( i_profiles_nb, sizeof( VAProfile ) ); if ( !p_profiles_list ) goto error; VAStatus i_status = vaQueryConfigProfiles( p_va->p_display, p_profiles_list, &i_profiles_nb ); if ( i_status == VA_STATUS_SUCCESS ) { for( int i = 0; i < i_profiles_nb; i++ ) { if ( p_profiles_list[i] == i_profile ) { b_supported_profile = true; break; } } } free( p_profiles_list ); if ( !b_supported_profile ) goto error; /* Create a VA configuration */ VAConfigAttrib attrib; memset( &attrib, 0, sizeof(attrib) ); attrib.type = VAConfigAttribRTFormat; if( vaGetConfigAttributes( p_va->p_display, i_profile, VAEntrypointVLD, &attrib, 1 ) ) goto error; /* Not sure what to do if not, I don't have a way to test */ if( (attrib.value & VA_RT_FORMAT_YUV420) == 0 ) goto error; if( vaCreateConfig( p_va->p_display, i_profile, VAEntrypointVLD, &attrib, 1, &p_va->i_config_id ) ) { p_va->i_config_id = VA_INVALID_ID; goto error; } p_va->i_surface_count = i_surface_count; p_va->b_supports_derive = false; if( asprintf( &p_va->va.description, "VA API version %d.%d", p_va->i_version_major, p_va->i_version_minor ) < 0 ) p_va->va.description = NULL; return VLC_SUCCESS; error: return VLC_EGENERIC; }
bool VAAPIContext::InitProfiles(void) { if (!(codec_is_vaapi_hw(m_codec)) || !m_ctx.display) return false; MythXLocker locker(m_display->m_x_disp); int max_profiles, max_entrypoints; VAProfile profile_wanted = preferredProfile(m_codec); if (profile_wanted == VAProfileMPEG2Simple) { LOG(VB_PLAYBACK, LOG_ERR, LOC + "Codec is not supported."); return false; } VAProfile profile_found = VAProfileMPEG2Simple; // unsupported value VAEntrypoint entry_found = VAEntrypointEncSlice; // unsupported value max_profiles = vaMaxNumProfiles(m_ctx.display); max_entrypoints = vaMaxNumEntrypoints(m_ctx.display); VAProfile *profiles = new VAProfile[max_profiles]; VAEntrypoint *entries = new VAEntrypoint[max_entrypoints]; static bool debugged = false; if (profiles && entries) { INIT_ST; int act_profiles, act_entries; va_status = vaQueryConfigProfiles(m_ctx.display, profiles, &act_profiles); CHECK_ST; if (ok && act_profiles > 0) { for (int i = 0; i < act_profiles; i++) { va_status = vaQueryConfigEntrypoints(m_ctx.display, profiles[i], entries, &act_entries); if (va_status == VA_STATUS_SUCCESS && act_entries > 0) { if (profiles[i] == profile_wanted) { profile_found = profile_wanted; for (int j = 0; j < act_entries; j++) if (entries[j] < entry_found) entry_found = entries[j]; } if (!debugged) { QString entrylist = "Entrypoints: "; for (int j = 0; j < act_entries; j++) entrylist += entryToString(entries[j]); LOG(VB_GENERAL, LOG_INFO, LOC + QString("Profile: %1 %2") .arg(profileToString(profiles[i])) .arg(entrylist)); } } } } debugged = true; } delete [] profiles; delete [] entries; LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Desired profile for '%1': %2") .arg(toString(m_codec)).arg(profileToString(profile_wanted))); LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found profile %1 with entry %2") .arg(profileToString(profile_found)).arg(entryToString(entry_found))); if (profile_wanted != profile_found) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find supported profile."); return false; } if (entry_found > VAEntrypointVLD) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find suitable entry point."); return false; } m_vaProfile = profile_wanted; m_vaEntrypoint = entry_found; if (VAEntrypointVLD == m_vaEntrypoint) m_pix_fmt = PIX_FMT_VAAPI_VLD; return true; }
static int Create( vlc_va_t *va, AVCodecContext *ctx, enum PixelFormat pix_fmt, const es_format_t *fmt, picture_sys_t *p_sys ) { if( pix_fmt != AV_PIX_FMT_VAAPI_VLD ) return VLC_EGENERIC; (void) fmt; (void) p_sys; #ifdef VLC_VA_BACKEND_XLIB if( !vlc_xlib_init( VLC_OBJECT(va) ) ) { msg_Warn( va, "Ignoring VA-X11 API" ); return VLC_EGENERIC; } #endif VAProfile i_profile, *p_profiles_list; bool b_supported_profile = false; int i_profiles_nb = 0; unsigned count = 3; /* */ switch( ctx->codec_id ) { case AV_CODEC_ID_MPEG1VIDEO: case AV_CODEC_ID_MPEG2VIDEO: i_profile = VAProfileMPEG2Main; count = 4; break; case AV_CODEC_ID_MPEG4: i_profile = VAProfileMPEG4AdvancedSimple; break; case AV_CODEC_ID_WMV3: i_profile = VAProfileVC1Main; break; case AV_CODEC_ID_VC1: i_profile = VAProfileVC1Advanced; break; case AV_CODEC_ID_H264: i_profile = VAProfileH264High; count = 18; break;; default: return VLC_EGENERIC; } count += ctx->thread_count; vlc_va_sys_t *sys; void *mem; assert(popcount(sizeof (sys->surfaces)) == 1); if (unlikely(posix_memalign(&mem, sizeof (sys->surfaces), sizeof (*sys)))) return VLC_ENOMEM; sys = mem; memset(sys, 0, sizeof (*sys)); /* */ sys->hw_ctx.display = NULL; sys->hw_ctx.config_id = VA_INVALID_ID; sys->hw_ctx.context_id = VA_INVALID_ID; sys->width = ctx->coded_width; sys->height = ctx->coded_height; sys->count = count; sys->available = (1 << sys->count) - 1; assert(count < sizeof (sys->available) * CHAR_BIT); assert(count * sizeof (sys->surfaces[0]) <= sizeof (sys->surfaces)); /* Create a VA display */ #ifdef VLC_VA_BACKEND_XLIB sys->p_display_x11 = XOpenDisplay(NULL); if( !sys->p_display_x11 ) { msg_Err( va, "Could not connect to X server" ); goto error; } sys->hw_ctx.display = vaGetDisplay(sys->p_display_x11); #endif #ifdef VLC_VA_BACKEND_DRM sys->drm_fd = vlc_open("/dev/dri/card0", O_RDWR); if( sys->drm_fd == -1 ) { msg_Err( va, "Could not access rendering device: %m" ); goto error; } sys->hw_ctx.display = vaGetDisplayDRM(sys->drm_fd); #endif if (sys->hw_ctx.display == NULL) { msg_Err( va, "Could not get a VAAPI device" ); goto error; } int major, minor; if (vaInitialize(sys->hw_ctx.display, &major, &minor)) { msg_Err( va, "Failed to initialize the VAAPI device" ); goto error; } /* Check if the selected profile is supported */ i_profiles_nb = vaMaxNumProfiles(sys->hw_ctx.display); p_profiles_list = calloc( i_profiles_nb, sizeof( VAProfile ) ); if( !p_profiles_list ) goto error; if (vaQueryConfigProfiles(sys->hw_ctx.display, p_profiles_list, &i_profiles_nb) == VA_STATUS_SUCCESS) { for( int i = 0; i < i_profiles_nb; i++ ) { if ( p_profiles_list[i] == i_profile ) { b_supported_profile = true; break; } } } free( p_profiles_list ); if ( !b_supported_profile ) { msg_Dbg( va, "Codec and profile not supported by the hardware" ); goto error; } /* Create a VA configuration */ VAConfigAttrib attrib; memset( &attrib, 0, sizeof(attrib) ); attrib.type = VAConfigAttribRTFormat; if (vaGetConfigAttributes(sys->hw_ctx.display, i_profile, VAEntrypointVLD, &attrib, 1)) goto error; /* Not sure what to do if not, I don't have a way to test */ if( (attrib.value & VA_RT_FORMAT_YUV420) == 0 ) goto error; if (vaCreateConfig(sys->hw_ctx.display, i_profile, VAEntrypointVLD, &attrib, 1, &sys->hw_ctx.config_id)) { sys->hw_ctx.config_id = VA_INVALID_ID; goto error; } /* Create surfaces */ assert(ctx->coded_width > 0 && ctx->coded_height > 0); if (vaCreateSurfaces(sys->hw_ctx.display, VA_RT_FORMAT_YUV420, ctx->coded_width, ctx->coded_height, sys->surfaces, sys->count, NULL, 0)) { goto error; } /* Create a context */ if (vaCreateContext(sys->hw_ctx.display, sys->hw_ctx.config_id, ctx->coded_width, ctx->coded_height, VA_PROGRESSIVE, sys->surfaces, sys->count, &sys->hw_ctx.context_id)) { sys->hw_ctx.context_id = VA_INVALID_ID; vaDestroySurfaces(sys->hw_ctx.display, sys->surfaces, sys->count); goto error; } if (FindFormat(sys)) goto error; if (unlikely(CopyInitCache(&sys->image_cache, ctx->coded_width))) goto error; vlc_mutex_init(&sys->lock); msg_Dbg(va, "using %s image format 0x%08x", sys->do_derive ? "derive" : "get", sys->format.fourcc); ctx->hwaccel_context = &sys->hw_ctx; va->sys = sys; va->description = vaQueryVendorString(sys->hw_ctx.display); va->get = Get; va->release = Release; va->extract = Extract; return VLC_SUCCESS; error: if (sys->hw_ctx.context_id != VA_INVALID_ID) { vaDestroyContext(sys->hw_ctx.display, sys->hw_ctx.context_id); vaDestroySurfaces(sys->hw_ctx.display, sys->surfaces, sys->count); } if (sys->hw_ctx.config_id != VA_INVALID_ID) vaDestroyConfig(sys->hw_ctx.display, sys->hw_ctx.config_id); if (sys->hw_ctx.display != NULL) vaTerminate(sys->hw_ctx.display); #ifdef VLC_VA_BACKEND_XLIB if( sys->p_display_x11 != NULL ) XCloseDisplay( sys->p_display_x11 ); #endif #ifdef VLC_VA_BACKEND_DRM if( sys->drm_fd != -1 ) close( sys->drm_fd ); #endif free( sys ); return VLC_EGENERIC; }
/* * Set *va_config and the frames_ref fields from the current codec parameters * in avctx. */ static int vaapi_decode_make_config(AVCodecContext *avctx, AVBufferRef *device_ref, VAConfigID *va_config, AVBufferRef *frames_ref) { AVVAAPIHWConfig *hwconfig = NULL; AVHWFramesConstraints *constraints = NULL; VAStatus vas; int err, i, j; const AVCodecDescriptor *codec_desc; VAProfile profile, va_profile, *profile_list = NULL; int profile_count, exact_match, alt_profile; const AVPixFmtDescriptor *sw_desc, *desc; AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data; AVVAAPIDeviceContext *hwctx = device->hwctx; codec_desc = avcodec_descriptor_get(avctx->codec_id); if (!codec_desc) { err = AVERROR(EINVAL); goto fail; } profile_count = vaMaxNumProfiles(hwctx->display); profile_list = av_malloc_array(profile_count, sizeof(VAProfile)); if (!profile_list) { err = AVERROR(ENOMEM); goto fail; } vas = vaQueryConfigProfiles(hwctx->display, profile_list, &profile_count); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: " "%d (%s).\n", vas, vaErrorStr(vas)); err = AVERROR(ENOSYS); goto fail; } profile = VAProfileNone; exact_match = 0; for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) { int profile_match = 0; if (avctx->codec_id != vaapi_profile_map[i].codec_id) continue; if (avctx->profile == vaapi_profile_map[i].codec_profile) profile_match = 1; profile = vaapi_profile_map[i].va_profile; for (j = 0; j < profile_count; j++) { if (profile == profile_list[j]) { exact_match = profile_match; break; } } if (j < profile_count) { if (exact_match) break; alt_profile = vaapi_profile_map[i].codec_profile; va_profile = vaapi_profile_map[i].va_profile; } } av_freep(&profile_list); if (profile == VAProfileNone) { av_log(avctx, AV_LOG_ERROR, "No support for codec %s " "profile %d.\n", codec_desc->name, avctx->profile); err = AVERROR(ENOSYS); goto fail; } if (!exact_match) { if (avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH) { av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not " "supported for hardware decode.\n", codec_desc->name, avctx->profile); av_log(avctx, AV_LOG_WARNING, "Using possibly-" "incompatible profile %d instead.\n", alt_profile); profile = va_profile; } else { av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not " "supported for hardware decode.\n", codec_desc->name, avctx->profile); err = AVERROR(EINVAL); goto fail; } } vas = vaCreateConfig(hwctx->display, profile, VAEntrypointVLD, NULL, 0, va_config); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create decode " "configuration: %d (%s).\n", vas, vaErrorStr(vas)); err = AVERROR(EIO); goto fail; } hwconfig = av_hwdevice_hwconfig_alloc(device_ref); if (!hwconfig) { err = AVERROR(ENOMEM); goto fail; } hwconfig->config_id = *va_config; constraints = av_hwdevice_get_hwframe_constraints(device_ref, hwconfig); if (!constraints) { err = AVERROR(ENOMEM); goto fail; } if (avctx->coded_width < constraints->min_width || avctx->coded_height < constraints->min_height || avctx->coded_width > constraints->max_width || avctx->coded_height > constraints->max_height) { av_log(avctx, AV_LOG_ERROR, "Hardware does not support image " "size %dx%d (constraints: width %d-%d height %d-%d).\n", avctx->coded_width, avctx->coded_height, constraints->min_width, constraints->max_width, constraints->min_height, constraints->max_height); err = AVERROR(EINVAL); goto fail; } if (!constraints->valid_sw_formats || constraints->valid_sw_formats[0] == AV_PIX_FMT_NONE) { av_log(avctx, AV_LOG_ERROR, "Hardware does not offer any " "usable surface formats.\n"); err = AVERROR(EINVAL); goto fail; } if (frames_ref) { AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data; frames->format = AV_PIX_FMT_VAAPI; frames->width = avctx->coded_width; frames->height = avctx->coded_height; // Find the first format in the list which matches the expected // bit depth and subsampling. If none are found (this can happen // when 10-bit streams are decoded to 8-bit surfaces, for example) // then just take the first format on the list. frames->sw_format = constraints->valid_sw_formats[0]; sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { desc = av_pix_fmt_desc_get(constraints->valid_sw_formats[i]); if (desc->nb_components != sw_desc->nb_components || desc->log2_chroma_w != sw_desc->log2_chroma_w || desc->log2_chroma_h != sw_desc->log2_chroma_h) continue; for (j = 0; j < desc->nb_components; j++) { if (desc->comp[j].depth != sw_desc->comp[j].depth) break; } if (j < desc->nb_components) continue; frames->sw_format = constraints->valid_sw_formats[i]; break; } frames->initial_pool_size = 1; // Add per-codec number of surfaces used for storing reference frames. switch (avctx->codec_id) { case AV_CODEC_ID_H264: case AV_CODEC_ID_HEVC: frames->initial_pool_size += 16; break; case AV_CODEC_ID_VP9: frames->initial_pool_size += 8; break; case AV_CODEC_ID_VP8: frames->initial_pool_size += 3; break; default: frames->initial_pool_size += 2; } } av_hwframe_constraints_free(&constraints); av_freep(&hwconfig); return 0; fail: av_hwframe_constraints_free(&constraints); av_freep(&hwconfig); if (*va_config != VA_INVALID_ID) { vaDestroyConfig(hwctx->display, *va_config); *va_config = VA_INVALID_ID; } av_freep(&profile_list); return err; }
static av_cold int vaapi_encode_check_config(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; VAStatus vas; int i, n, err; VAProfile *profiles = NULL; VAEntrypoint *entrypoints = NULL; VAConfigAttrib attr[] = { { VAConfigAttribRateControl }, { VAConfigAttribEncMaxRefFrames }, }; n = vaMaxNumProfiles(ctx->hwctx->display); profiles = av_malloc_array(n, sizeof(VAProfile)); if (!profiles) { err = AVERROR(ENOMEM); goto fail; } vas = vaQueryConfigProfiles(ctx->hwctx->display, profiles, &n); if (vas != VA_STATUS_SUCCESS) { av_log(ctx, AV_LOG_ERROR, "Failed to query profiles: %d (%s).\n", vas, vaErrorStr(vas)); err = AVERROR(ENOSYS); goto fail; } for (i = 0; i < n; i++) { if (profiles[i] == ctx->va_profile) break; } if (i >= n) { av_log(ctx, AV_LOG_ERROR, "Encoding profile not found (%d).\n", ctx->va_profile); err = AVERROR(ENOSYS); goto fail; } n = vaMaxNumEntrypoints(ctx->hwctx->display); entrypoints = av_malloc_array(n, sizeof(VAEntrypoint)); if (!entrypoints) { err = AVERROR(ENOMEM); goto fail; } vas = vaQueryConfigEntrypoints(ctx->hwctx->display, ctx->va_profile, entrypoints, &n); if (vas != VA_STATUS_SUCCESS) { av_log(ctx, AV_LOG_ERROR, "Failed to query entrypoints for " "profile %u: %d (%s).\n", ctx->va_profile, vas, vaErrorStr(vas)); err = AVERROR(ENOSYS); goto fail; } for (i = 0; i < n; i++) { if (entrypoints[i] == ctx->va_entrypoint) break; } if (i >= n) { av_log(ctx, AV_LOG_ERROR, "Encoding entrypoint not found " "(%d / %d).\n", ctx->va_profile, ctx->va_entrypoint); err = AVERROR(ENOSYS); goto fail; } vas = vaGetConfigAttributes(ctx->hwctx->display, ctx->va_profile, ctx->va_entrypoint, attr, FF_ARRAY_ELEMS(attr)); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to fetch config " "attributes: %d (%s).\n", vas, vaErrorStr(vas)); return AVERROR(EINVAL); } for (i = 0; i < FF_ARRAY_ELEMS(attr); i++) { if (attr[i].value == VA_ATTRIB_NOT_SUPPORTED) { // Unfortunately we have to treat this as "don't know" and hope // for the best, because the Intel MJPEG encoder returns this // for all the interesting attributes. continue; } switch (attr[i].type) { case VAConfigAttribRateControl: if (!(ctx->va_rc_mode & attr[i].value)) { av_log(avctx, AV_LOG_ERROR, "Rate control mode is not " "supported: %x\n", attr[i].value); err = AVERROR(EINVAL); goto fail; } break; case VAConfigAttribEncMaxRefFrames: { unsigned int ref_l0 = attr[i].value & 0xffff; unsigned int ref_l1 = (attr[i].value >> 16) & 0xffff; if (avctx->gop_size > 1 && ref_l0 < 1) { av_log(avctx, AV_LOG_ERROR, "P frames are not " "supported (%x).\n", attr[i].value); err = AVERROR(EINVAL); goto fail; } if (avctx->max_b_frames > 0 && ref_l1 < 1) { av_log(avctx, AV_LOG_ERROR, "B frames are not " "supported (%x).\n", attr[i].value); err = AVERROR(EINVAL); goto fail; } } break; } } err = 0; fail: av_freep(&profiles); av_freep(&entrypoints); return err; }