static int ensure_image_formats(void) { VAStatus va_status; VAImageFormat *image_formats; int num_image_formats; if (va_num_image_formats >= 0) return va_num_image_formats; num_image_formats = vaMaxNumImageFormats(va_dpy); if (num_image_formats == 0) return 0; image_formats = malloc(num_image_formats * sizeof(*image_formats)); if (!image_formats) return 0; va_status = vaQueryImageFormats(va_dpy, image_formats, &num_image_formats); CHECK_VASTATUS(va_status, "vaQuerySurfaceAttributes()"); va_image_formats = image_formats; va_num_image_formats = num_image_formats; return num_image_formats; }
const VAImageFormat * VaapiDisplay::getVaFormat(uint32_t fourcc) { AutoLock locker(m_lock); int i; if (m_vaImageFormats.empty()) { VAStatus vaStatus; int numImageFormats; numImageFormats = vaMaxNumImageFormats(m_vaDisplay); if (numImageFormats == 0) return NULL; m_vaImageFormats.reserve(numImageFormats); m_vaImageFormats.resize(numImageFormats); vaStatus = vaQueryImageFormats(m_vaDisplay, &m_vaImageFormats[0], &numImageFormats); checkVaapiStatus(vaStatus, "vaQueryImageFormats()"); for (i=0; i< m_vaImageFormats.size(); i++) DEBUG_FOURCC("supported image format: ", m_vaImageFormats[i].fourcc); } for (i = 0; i < m_vaImageFormats.size(); i++) { VAImageFormat vaImageFormat = m_vaImageFormats[i]; if (vaImageFormat.fourcc == fourcc) return &m_vaImageFormats[i]; } return NULL; }
bool getVaFormat(VADisplay display, VAImageFormat& format) { int num = vaMaxNumImageFormats(display); if (!num) return false; std::vector<VAImageFormat> vaFormats; vaFormats.resize(num); VAStatus vaStatus = vaQueryImageFormats(display, &vaFormats[0], &num); if (!checkVaapiStatus(vaStatus, "vaQueryImageFormats")) return false; if (vaStatus != VA_STATUS_SUCCESS) { ERROR("query image formats return %d", vaStatus); return false; } vaFormats.resize(num); for (size_t i = 0; i < vaFormats.size(); i++) { const VAImageFormat& fmt = vaFormats[i]; if (fmt.fourcc == VA_FOURCC_BGRX) { format = fmt; return true; } } return false; }
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::HWAccellGetImg( const VideoFrame *videoFrame, void *dest, ImgScaler *yv12ToRGB32 ) const { if ( dest && !( outH & 1 ) && !( outW % 4 ) ) { int fmt_count = vaMaxNumImageFormats( VADisp ); VAImageFormat img_fmt[ fmt_count ]; if ( vaQueryImageFormats( VADisp, img_fmt, &fmt_count ) == VA_STATUS_SUCCESS ) { const VASurfaceID surfaceID = ( unsigned long )videoFrame->data[ 3 ]; int img_fmt_idx[ 3 ] = { -1, -1, -1 }; for ( int i = 0 ; i < fmt_count ; ++i ) { if ( !qstrncmp( ( const char * )&img_fmt[ i ].fourcc, "BGR", 3 ) ) img_fmt_idx[ 0 ] = i; else if ( !qstrncmp( ( const char * )&img_fmt[ i ].fourcc, "YV12", 4 ) ) img_fmt_idx[ 1 ] = i; else if ( !qstrncmp( ( const char * )&img_fmt[ i ].fourcc, "NV12", 4 ) ) img_fmt_idx[ 2 ] = i; } return ( ( img_fmt_idx[ 0 ] > -1 && getRGB32Image( &img_fmt[ img_fmt_idx[ 0 ] ], surfaceID, dest ) ) || ( img_fmt_idx[ 1 ] > -1 && getYV12Image( &img_fmt[ img_fmt_idx[ 1 ] ], surfaceID, dest, yv12ToRGB32 ) ) || ( img_fmt_idx[ 2 ] > -1 && getNV12Image( &img_fmt[ img_fmt_idx[ 2 ] ], surfaceID, dest, yv12ToRGB32 ) ) ); } } return false; }
void* SurfaceInteropVAAPI::mapToHost(const VideoFormat &format, void *handle, int plane) { Q_UNUSED(plane); int nb_fmts = vaMaxNumImageFormats(m_surface->vadisplay()); //av_mallocz_array VAImageFormat *p_fmt = (VAImageFormat*)calloc(nb_fmts, sizeof(*p_fmt)); if (!p_fmt) { return NULL; } if (vaQueryImageFormats(m_surface->vadisplay(), p_fmt, &nb_fmts)) { free(p_fmt); return NULL; } VAImage image; for (int i = 0; i < nb_fmts; i++) { if (p_fmt[i].fourcc == VA_FOURCC_YV12 || p_fmt[i].fourcc == VA_FOURCC_IYUV || p_fmt[i].fourcc == VA_FOURCC_NV12) { qDebug("vaCreateImage: %c%c%c%c", p_fmt[i].fourcc<<24>>24, p_fmt[i].fourcc<<16>>24, p_fmt[i].fourcc<<8>>24, p_fmt[i].fourcc>>24); if (vaCreateImage(m_surface->vadisplay(), &p_fmt[i], m_surface->width(), m_surface->height(), &image) != VA_STATUS_SUCCESS) { image.image_id = VA_INVALID_ID; qDebug("vaCreateImage error: %c%c%c%c", p_fmt[i].fourcc<<24>>24, p_fmt[i].fourcc<<16>>24, p_fmt[i].fourcc<<8>>24, p_fmt[i].fourcc>>24); continue; } /* Validate that vaGetImage works with this format */ if (vaGetImage(m_surface->vadisplay(), m_surface->get(), 0, 0, m_surface->width(), m_surface->height(), image.image_id) != VA_STATUS_SUCCESS) { vaDestroyImage(m_surface->vadisplay(), image.image_id); qDebug("vaGetImage error: %c%c%c%c", p_fmt[i].fourcc<<24>>24, p_fmt[i].fourcc<<16>>24, p_fmt[i].fourcc<<8>>24, p_fmt[i].fourcc>>24); image.image_id = VA_INVALID_ID; continue; }
static int vaapi_device_init(AVHWDeviceContext *hwdev) { VAAPIDeviceContext *ctx = hwdev->internal->priv; AVVAAPIDeviceContext *hwctx = hwdev->hwctx; VAImageFormat *image_list = NULL; VAStatus vas; int err, i, image_count; enum AVPixelFormat pix_fmt; unsigned int fourcc; image_count = vaMaxNumImageFormats(hwctx->display); if (image_count <= 0) { err = AVERROR(EIO); goto fail; } image_list = av_malloc(image_count * sizeof(*image_list)); if (!image_list) { err = AVERROR(ENOMEM); goto fail; } vas = vaQueryImageFormats(hwctx->display, image_list, &image_count); if (vas != VA_STATUS_SUCCESS) { err = AVERROR(EIO); goto fail; } ctx->formats = av_malloc(image_count * sizeof(*ctx->formats)); if (!ctx->formats) { err = AVERROR(ENOMEM); goto fail; } ctx->nb_formats = 0; for (i = 0; i < image_count; i++) { fourcc = image_list[i].fourcc; pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); if (pix_fmt == AV_PIX_FMT_NONE) { av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n", fourcc); } else { av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n", fourcc, av_get_pix_fmt_name(pix_fmt)); ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt; ctx->formats[ctx->nb_formats].image_format = image_list[i]; ++ctx->nb_formats; } } av_free(image_list); return 0; fail: av_freep(&ctx->formats); av_free(image_list); return err; }
static int ensure_surface_attribs(void) { VAStatus va_status; VASurfaceAttrib *surface_attribs; unsigned int num_image_formats, num_surface_attribs; if (va_num_surface_attribs >= 0) return va_num_surface_attribs; num_image_formats = vaMaxNumImageFormats(va_dpy); if (num_image_formats == 0) return 0; va_status = vaCreateConfig(va_dpy, VAProfileNone, VAEntrypointVideoProc, NULL, 0, &vpp_config_id); CHECK_VASTATUS(va_status, "vaCreateConfig()"); /* Guess the number of surface attributes, thus including any pixel-format supported by the VA driver */ num_surface_attribs = VASurfaceAttribCount + num_image_formats; surface_attribs = malloc(num_surface_attribs * sizeof(*surface_attribs)); if (!surface_attribs) return 0; va_status = vaQuerySurfaceAttributes(va_dpy, vpp_config_id, surface_attribs, &num_surface_attribs); if (va_status == VA_STATUS_SUCCESS) va_surface_attribs = surface_attribs; else if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) { va_surface_attribs = realloc(surface_attribs, num_surface_attribs * sizeof(*va_surface_attribs)); if (!va_surface_attribs) { free(surface_attribs); return 0; } va_status = vaQuerySurfaceAttributes(va_dpy, vpp_config_id, va_surface_attribs, &num_surface_attribs); } CHECK_VASTATUS(va_status, "vaQuerySurfaceAttributes()"); va_num_surface_attribs = num_surface_attribs; return num_surface_attribs; }
static int get_image_format( VAAPIContext *vaapi, uint32_t fourcc, VAImageFormat **image_format ) { VAStatus status; int i; if (image_format) *image_format = NULL; if (!vaapi->image_formats || vaapi->n_image_formats == 0) { vaapi->image_formats = calloc(vaMaxNumImageFormats(vaapi->display), sizeof(vaapi->image_formats[0])); if (!vaapi->image_formats) return 0; status = vaQueryImageFormats(vaapi->display, vaapi->image_formats, &vaapi->n_image_formats); if (!vaapi_check_status(status, "vaQueryImageFormats()")) return 0; D(bug("%d image formats\n", vaapi->n_image_formats)); for (i = 0; i < vaapi->n_image_formats; i++) D(bug(" %s\n", string_of_VAImageFormat(&vaapi->image_formats[i]))); } for (i = 0; i < vaapi->n_image_formats; i++) { if (vaapi->image_formats[i].fourcc == fourcc) { if (image_format) *image_format = &vaapi->image_formats[i]; return 1; } } return 0; }
static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t *pi_chroma, int i_width, int i_height ) { assert( i_width > 0 && i_height > 0 ); /* */ p_va->p_surface = calloc( p_va->i_surface_count, sizeof(*p_va->p_surface) ); if( !p_va->p_surface ) return VLC_EGENERIC; p_va->image.image_id = VA_INVALID_ID; p_va->i_context_id = VA_INVALID_ID; /* Create surfaces */ VASurfaceID pi_surface_id[p_va->i_surface_count]; if( vaCreateSurfaces( p_va->p_display, i_width, i_height, VA_RT_FORMAT_YUV420, p_va->i_surface_count, pi_surface_id ) ) { for( int i = 0; i < p_va->i_surface_count; i++ ) p_va->p_surface[i].i_id = VA_INVALID_SURFACE; goto error; } for( int i = 0; i < p_va->i_surface_count; i++ ) { vlc_va_surface_t *p_surface = &p_va->p_surface[i]; p_surface->i_id = pi_surface_id[i]; p_surface->i_refcount = 0; p_surface->i_order = 0; } /* Create a context */ if( vaCreateContext( p_va->p_display, p_va->i_config_id, i_width, i_height, VA_PROGRESSIVE, pi_surface_id, p_va->i_surface_count, &p_va->i_context_id ) ) { p_va->i_context_id = VA_INVALID_ID; goto error; } /* Find and create a supported image chroma */ int i_fmt_count = vaMaxNumImageFormats( p_va->p_display ); VAImageFormat *p_fmt = calloc( i_fmt_count, sizeof(*p_fmt) ); if( !p_fmt ) goto error; if( vaQueryImageFormats( p_va->p_display, p_fmt, &i_fmt_count ) ) { free( p_fmt ); goto error; } VAImage testImage; if(vaDeriveImage(p_va->p_display, pi_surface_id[0], &testImage) == VA_STATUS_SUCCESS) { p_va->b_supports_derive = true; vaDestroyImage(p_va->p_display, testImage.image_id); } vlc_fourcc_t i_chroma = 0; VAImageFormat fmt; for( int i = 0; i < i_fmt_count; i++ ) { if( p_fmt[i].fourcc == VA_FOURCC( 'Y', 'V', '1', '2' ) || p_fmt[i].fourcc == VA_FOURCC( 'I', '4', '2', '0' ) || p_fmt[i].fourcc == VA_FOURCC( 'N', 'V', '1', '2' ) ) { if( vaCreateImage( p_va->p_display, &p_fmt[i], i_width, i_height, &p_va->image ) ) { p_va->image.image_id = VA_INVALID_ID; continue; } /* Validate that vaGetImage works with this format */ if( vaGetImage( p_va->p_display, pi_surface_id[0], 0, 0, i_width, i_height, p_va->image.image_id) ) { vaDestroyImage( p_va->p_display, p_va->image.image_id ); p_va->image.image_id = VA_INVALID_ID; continue; } i_chroma = VLC_CODEC_YV12; fmt = p_fmt[i]; break; } } free( p_fmt ); if( !i_chroma ) goto error; *pi_chroma = i_chroma; if(p_va->b_supports_derive) { vaDestroyImage( p_va->p_display, p_va->image.image_id ); p_va->image.image_id = VA_INVALID_ID; } if( unlikely(CopyInitCache( &p_va->image_cache, i_width )) ) goto error; /* Setup the ffmpeg hardware context */ *pp_hw_ctx = &p_va->hw_ctx; memset( &p_va->hw_ctx, 0, sizeof(p_va->hw_ctx) ); p_va->hw_ctx.display = p_va->p_display; p_va->hw_ctx.config_id = p_va->i_config_id; p_va->hw_ctx.context_id = p_va->i_context_id; /* */ p_va->i_surface_chroma = i_chroma; p_va->i_surface_width = i_width; p_va->i_surface_height = i_height; return VLC_SUCCESS; error: DestroySurfaces( p_va ); return VLC_EGENERIC; }
bool VAAPIContext::InitImage(const void *buf) { if (!buf) return false; if (!m_dispType == kVADisplayX11) return true; int num_formats = 0; int max_formats = vaMaxNumImageFormats(m_ctx.display); VAImageFormat *formats = new VAImageFormat[max_formats]; INIT_ST; va_status = vaQueryImageFormats(m_ctx.display, formats, &num_formats); CHECK_ST; const vaapi_surface *surf = (vaapi_surface*)buf; unsigned int deriveImageFormat = 0; if (vaDeriveImage(m_ctx.display, surf->m_id, &m_image) == VA_STATUS_SUCCESS) { m_deriveSupport = true; deriveImageFormat = m_image.format.fourcc; vaDestroyImage(m_ctx.display, m_image.image_id); } int nv12support = -1; for (int i = 0; i < num_formats; i++) { if (formats[i].fourcc == VA_FOURCC_YV12 || formats[i].fourcc == VA_FOURCC_IYUV || formats[i].fourcc == VA_FOURCC_NV12) { if (vaCreateImage(m_ctx.display, &formats[i], m_size.width(), m_size.height(), &m_image)) { m_image.image_id = VA_INVALID_ID; continue; } if (vaGetImage(m_ctx.display, surf->m_id, 0, 0, m_size.width(), m_size.height(), m_image.image_id)) { vaDestroyImage(m_ctx.display, m_image.image_id); m_image.image_id = VA_INVALID_ID; continue; } if (formats[i].fourcc == VA_FOURCC_NV12) { // mark as NV12 as supported, but favor other formats first nv12support = i; vaDestroyImage(m_ctx.display, m_image.image_id); m_image.image_id = VA_INVALID_ID; continue; } break; } } if (m_image.image_id == VA_INVALID_ID && nv12support >= 0) { // only nv12 is supported, use that format if (vaCreateImage(m_ctx.display, &formats[nv12support], m_size.width(), m_size.height(), &m_image)) { m_image.image_id = VA_INVALID_ID; } } else if (m_deriveSupport && deriveImageFormat != m_image.format.fourcc) { // only use vaDerive if it's giving us a format we can handle natively m_deriveSupport = false; } delete [] formats; if (m_image.image_id == VA_INVALID_ID) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create software image."); return false; } LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("InitImage: id %1, width %2 height %3 " "format %4 vaDeriveSupport:%5") .arg(m_image.image_id).arg(m_image.width).arg(m_image.height) .arg(m_image.format.fourcc).arg(m_deriveSupport)); if (m_deriveSupport) { vaDestroyImage(m_ctx.display, m_image.image_id ); m_image.image_id = VA_INVALID_ID; } return true; }
/** Finds a supported image chroma */ static int FindFormat(vlc_va_sys_t *sys) { int count = vaMaxNumImageFormats(sys->hw_ctx.display); VAImageFormat *fmts = malloc(count * sizeof (*fmts)); if (unlikely(fmts == NULL)) return VLC_ENOMEM; if (vaQueryImageFormats(sys->hw_ctx.display, fmts, &count)) { free(fmts); return VLC_EGENERIC; } sys->format.fourcc = 0; for (int i = 0; i < count; i++) { unsigned fourcc = fmts[i].fourcc; if (fourcc != VA_FOURCC_YV12 && fourcc != VA_FOURCC_IYUV && fourcc != VA_FOURCC_NV12) continue; VAImage image; if (vaCreateImage(sys->hw_ctx.display, &fmts[i], sys->width, sys->height, &image)) continue; /* Validate that vaGetImage works with this format */ int val = vaGetImage(sys->hw_ctx.display, sys->surfaces[0], 0, 0, sys->width, sys->height, image.image_id); vaDestroyImage(sys->hw_ctx.display, image.image_id); if (val != VA_STATUS_SUCCESS) continue; /* Mark NV12 as supported, but favor other formats first */ sys->format = fmts[i]; if (fourcc != VA_FOURCC_NV12) break; } free(fmts); if (sys->format.fourcc == 0) return VLC_EGENERIC; /* None of the formats work */ VAImage image; /* Use vaDerive() iif it supports the best selected format */ sys->do_derive = false; if (vaDeriveImage(sys->hw_ctx.display, sys->surfaces[0], &image) == VA_STATUS_SUCCESS) { if (image.format.fourcc == sys->format.fourcc) { sys->do_derive = true; sys->format = image.format; } vaDestroyImage(sys->hw_ctx.display, image.image_id); } return VLC_SUCCESS; }