|
MythTV
0.26-pre
|
00001 #include "openglvideo.h" 00002 #include "mythlogging.h" 00003 #include "mythxdisplay.h" 00004 #include "mythcodecid.h" 00005 #include "frame.h" 00006 #include "vaapicontext.h" 00007 #include "mythmainwindow.h" 00008 #include "myth_imgconvert.h" 00009 00010 #define LOC QString("VAAPI: ") 00011 #define ERR QString("VAAPI Error: ") 00012 #define NUM_VAAPI_BUFFERS 24 00013 00014 #define INIT_ST \ 00015 VAStatus va_status; \ 00016 bool ok = true 00017 00018 #define CHECK_ST \ 00019 ok &= (va_status == VA_STATUS_SUCCESS); \ 00020 if (!ok) \ 00021 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error at %1:%2 (#%3, %4)") \ 00022 .arg(__FILE__).arg( __LINE__).arg(va_status) \ 00023 .arg(vaErrorStr(va_status))) 00024 00025 #define CREATE_CHECK(arg1, arg2) \ 00026 if (ok) \ 00027 { \ 00028 ok = arg1; \ 00029 if (!ok) \ 00030 LOG(VB_GENERAL, LOG_ERR, LOC + arg2); \ 00031 } while(0) 00032 00033 QString profileToString(VAProfile profile); 00034 QString entryToString(VAEntrypoint entry); 00035 VAProfile preferredProfile(MythCodecID codec); 00036 00037 QString profileToString(VAProfile profile) 00038 { 00039 if (VAProfileMPEG2Simple == profile) return "MPEG2Simple"; 00040 if (VAProfileMPEG2Main == profile) return "MPEG2Main"; 00041 if (VAProfileMPEG4Simple == profile) return "MPEG4Simple"; 00042 if (VAProfileMPEG4AdvancedSimple == profile) return "MPEG4AdvSimple"; 00043 if (VAProfileMPEG4Main == profile) return "MPEG4Main"; 00044 if (VAProfileH264Baseline == profile) return "H264Base"; 00045 if (VAProfileH264Main == profile) return "H264Main"; 00046 if (VAProfileH264High == profile) return "H264High"; 00047 if (VAProfileVC1Simple == profile) return "VC1Simple"; 00048 if (VAProfileVC1Main == profile) return "VC1Main"; 00049 if (VAProfileVC1Advanced == profile) return "VC1Advanced"; 00050 if (VAProfileH263Baseline == profile) return "H263Base"; 00051 return "Unknown"; 00052 } 00053 00054 QString entryToString(VAEntrypoint entry) 00055 { 00056 if (VAEntrypointVLD == entry) return "VLD "; 00057 if (VAEntrypointIZZ == entry) return "IZZ (UNSUPPORTED) "; 00058 if (VAEntrypointIDCT == entry) return "IDCT (UNSUPPORTED) "; 00059 if (VAEntrypointMoComp == entry) return "MC (UNSUPPORTED) "; 00060 if (VAEntrypointDeblocking == entry) return "Deblock (UNSUPPORTED) "; 00061 if (VAEntrypointEncSlice == entry) return "EncSlice (UNSUPPORTED) "; 00062 return "Unknown"; 00063 } 00064 00065 VAProfile preferredProfile(MythCodecID codec) 00066 { 00067 if (kCodec_H263_VAAPI == codec) return VAProfileMPEG4AdvancedSimple; 00068 if (kCodec_MPEG4_VAAPI == codec) return VAProfileMPEG4AdvancedSimple; 00069 if (kCodec_H264_VAAPI == codec) return VAProfileH264High; 00070 if (kCodec_VC1_VAAPI == codec) return VAProfileVC1Advanced; 00071 if (kCodec_WMV3_VAAPI == codec) return VAProfileVC1Main; 00072 if (kCodec_MPEG2_VAAPI == codec) return VAProfileMPEG2Main; 00073 if (kCodec_MPEG1_VAAPI == codec) return VAProfileMPEG2Main; 00074 return VAProfileMPEG2Simple; // error 00075 } 00076 00077 class VAAPIDisplay 00078 { 00079 protected: 00080 VAAPIDisplay(VAAPIDisplayType display_type) 00081 : m_va_disp_type(display_type), 00082 m_va_disp(NULL), m_x_disp(NULL), 00083 m_ref_count(0), m_driver(QString()) { } 00084 public: 00085 ~VAAPIDisplay() 00086 { 00087 if (m_va_disp) 00088 { 00089 INIT_ST; 00090 XLOCK(m_x_disp, va_status = vaTerminate(m_va_disp)); 00091 CHECK_ST; 00092 } 00093 if (m_x_disp) 00094 { 00095 m_x_disp->Sync(true); 00096 delete m_x_disp; 00097 } 00098 } 00099 00100 bool Create(void) 00101 { 00102 m_x_disp = OpenMythXDisplay(); 00103 if (!m_x_disp) 00104 return false; 00105 00106 MythXLocker locker(m_x_disp); 00107 00108 if (m_va_disp_type == kVADisplayGLX) 00109 { 00110 MythMainWindow *mw = GetMythMainWindow(); 00111 if (!mw) 00112 return false; 00113 MythRenderOpenGL *gl = 00114 static_cast<MythRenderOpenGL*>(mw->GetRenderDevice()); 00115 if (!gl) 00116 { 00117 LOG(VB_PLAYBACK, LOG_ERR, LOC + 00118 QString("Failed to get OpenGL context - you must use the " 00119 "OpenGL UI painter for VAAPI GLX support.")); 00120 return false; 00121 } 00122 00123 gl->makeCurrent(); 00124 Display *display = glXGetCurrentDisplay(); 00125 gl->doneCurrent(); 00126 00127 m_va_disp = vaGetDisplayGLX(display); 00128 } 00129 else 00130 { 00131 m_va_disp = vaGetDisplay(m_x_disp->GetDisplay()); 00132 } 00133 00134 if (!m_va_disp) 00135 { 00136 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VADisplay"); 00137 return false; 00138 } 00139 00140 int major_ver, minor_ver; 00141 INIT_ST; 00142 va_status = vaInitialize(m_va_disp, &major_ver, &minor_ver); 00143 CHECK_ST; 00144 00145 if (ok) 00146 m_driver = vaQueryVendorString(m_va_disp); 00147 00148 static bool debugged = false; 00149 if (ok && !debugged) 00150 { 00151 debugged = true; 00152 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Version: %1.%2") 00153 .arg(major_ver).arg(minor_ver)); 00154 LOG(VB_GENERAL, LOG_INFO, LOC + QString("Driver : %1").arg(m_driver)); 00155 } 00156 if (ok) 00157 { 00158 UpRef(); 00159 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00160 QString("Created VAAPI %1 display") 00161 .arg(m_va_disp_type == kVADisplayGLX ? "GLX" : "X11")); 00162 } 00163 return ok; 00164 } 00165 00166 void UpRef(void) 00167 { 00168 XLOCK(m_x_disp, m_ref_count++) 00169 } 00170 00171 void DownRef(void) 00172 { 00173 m_x_disp->Lock(); 00174 m_ref_count--; 00175 if (m_ref_count <= 0) 00176 { 00177 if (gVAAPIDisplay == this) 00178 gVAAPIDisplay = NULL; 00179 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Deleting VAAPI display."); 00180 m_x_disp->Unlock(); 00181 delete this; 00182 return; 00183 } 00184 m_x_disp->Unlock(); 00185 } 00186 00187 QString GetDriver(void) 00188 { 00189 QString ret = m_driver; 00190 m_driver.detach(); 00191 return ret; 00192 } 00193 00194 static VAAPIDisplay* GetDisplay(VAAPIDisplayType display_type) 00195 { 00196 if (gVAAPIDisplay) 00197 { 00198 if (gVAAPIDisplay->m_va_disp_type != display_type) 00199 { 00200 LOG(VB_GENERAL, LOG_ERR, "Already have a VAAPI display " 00201 "of a different type - aborting"); 00202 return NULL; 00203 } 00204 gVAAPIDisplay->UpRef(); 00205 return gVAAPIDisplay; 00206 } 00207 00208 gVAAPIDisplay = new VAAPIDisplay(display_type); 00209 if (gVAAPIDisplay && gVAAPIDisplay->Create()) 00210 return gVAAPIDisplay; 00211 00212 delete gVAAPIDisplay; 00213 gVAAPIDisplay = NULL; 00214 return NULL; 00215 } 00216 00217 static VAAPIDisplay *gVAAPIDisplay; 00218 VAAPIDisplayType m_va_disp_type; 00219 void *m_va_disp; 00220 MythXDisplay *m_x_disp; 00221 int m_ref_count; 00222 QString m_driver; 00223 }; 00224 00225 VAAPIDisplay* VAAPIDisplay::gVAAPIDisplay = NULL; 00226 00227 bool VAAPIContext::IsFormatAccelerated(QSize size, MythCodecID codec, 00228 PixelFormat &pix_fmt) 00229 { 00230 bool result = false; 00231 VAAPIContext *ctx = new VAAPIContext(kVADisplayX11, codec); 00232 if (ctx && ctx->CreateDisplay(size)) 00233 { 00234 pix_fmt = ctx->GetPixelFormat(); 00235 result = pix_fmt == PIX_FMT_VAAPI_VLD; 00236 } 00237 delete ctx; 00238 return result; 00239 } 00240 00241 VAAPIContext::VAAPIContext(VAAPIDisplayType display_type, 00242 MythCodecID codec) 00243 : m_dispType(display_type), 00244 m_codec(codec), 00245 m_display(NULL), 00246 m_vaProfile(VAProfileMPEG2Main)/* ?? */, 00247 m_vaEntrypoint(VAEntrypointEncSlice), 00248 m_pix_fmt(PIX_FMT_YUV420P), m_numSurfaces(NUM_VAAPI_BUFFERS), 00249 m_surfaces(NULL), m_surfaceData(NULL), m_pictureAttributes(NULL), 00250 m_pictureAttributeCount(0), m_hueBase(0) 00251 { 00252 memset(&m_ctx, 0, sizeof(vaapi_context)); 00253 memset(&m_image, 0, sizeof(m_image)); 00254 m_image.image_id = VA_INVALID_ID; 00255 } 00256 00257 VAAPIContext::~VAAPIContext() 00258 { 00259 delete [] m_pictureAttributes; 00260 00261 ClearGLXSurfaces(); 00262 00263 if (m_display) 00264 { 00265 m_display->m_x_disp->Lock(); 00266 00267 INIT_ST; 00268 00269 if (m_image.image_id != VA_INVALID_ID) 00270 { 00271 va_status = vaDestroyImage(m_ctx.display, m_image.image_id); 00272 CHECK_ST; 00273 } 00274 if (m_ctx.context_id) 00275 { 00276 va_status = vaDestroyContext(m_ctx.display, m_ctx.context_id); 00277 CHECK_ST; 00278 } 00279 if (m_ctx.config_id) 00280 { 00281 va_status = vaDestroyConfig(m_ctx.display, m_ctx.config_id); 00282 CHECK_ST; 00283 } 00284 if (m_surfaces) 00285 { 00286 va_status = vaDestroySurfaces(m_ctx.display, m_surfaces, m_numSurfaces); 00287 CHECK_ST; 00288 } 00289 } 00290 00291 if (m_surfaces) 00292 delete [] m_surfaces; 00293 if (m_surfaceData) 00294 delete [] m_surfaceData; 00295 00296 if (m_display) 00297 { 00298 m_display->m_x_disp->Unlock(); 00299 m_display->DownRef(); 00300 } 00301 00302 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Deleted context"); 00303 } 00304 00305 bool VAAPIContext::CreateDisplay(QSize size) 00306 { 00307 m_size = size; 00308 bool ok = true; 00309 m_display = VAAPIDisplay::GetDisplay(m_dispType); 00310 CREATE_CHECK(!m_size.isEmpty(), "Invalid size"); 00311 CREATE_CHECK(m_display != NULL, "Invalid display"); 00312 CREATE_CHECK(InitDisplay(), "Invalid VADisplay"); 00313 CREATE_CHECK(InitProfiles(), "No supported profiles"); 00314 if (ok) 00315 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00316 QString("Created context (%1x%2->%3x%4)") 00317 .arg(size.width()).arg(size.height()) 00318 .arg(m_size.width()).arg(m_size.height())); 00319 // ATI hue adjustment 00320 if (m_display) 00321 m_hueBase = VideoOutput::CalcHueBase(m_display->GetDriver()); 00322 00323 return ok; 00324 } 00325 00326 void VAAPIContext::InitPictureAttributes(VideoColourSpace &colourspace) 00327 { 00328 if (!m_display) 00329 return; 00330 if (!m_display->m_va_disp) 00331 return; 00332 00333 delete [] m_pictureAttributes; 00334 m_pictureAttributeCount = 0; 00335 int supported_controls = kPictureAttributeSupported_None; 00336 QList<VADisplayAttribute> supported; 00337 int num = vaMaxNumDisplayAttributes(m_display->m_va_disp); 00338 VADisplayAttribute* attribs = new VADisplayAttribute[num]; 00339 00340 int actual = 0; 00341 INIT_ST; 00342 va_status = vaQueryDisplayAttributes(m_display->m_va_disp, attribs, &actual); 00343 CHECK_ST; 00344 00345 for (int i = 0; i < actual; i++) 00346 { 00347 int type = attribs[i].type; 00348 if ((attribs[i].flags & VA_DISPLAY_ATTRIB_SETTABLE) && 00349 (type == VADisplayAttribBrightness || 00350 type == VADisplayAttribContrast || 00351 type == VADisplayAttribHue || 00352 type == VADisplayAttribSaturation)) 00353 { 00354 supported.push_back(attribs[i]); 00355 if (type == VADisplayAttribBrightness) 00356 supported_controls += kPictureAttributeSupported_Brightness; 00357 if (type == VADisplayAttribHue) 00358 supported_controls += kPictureAttributeSupported_Hue; 00359 if (type == VADisplayAttribContrast) 00360 supported_controls += kPictureAttributeSupported_Contrast; 00361 if (type == VADisplayAttribSaturation) 00362 supported_controls += kPictureAttributeSupported_Colour; 00363 } 00364 } 00365 00366 colourspace.SetSupportedAttributes((PictureAttributeSupported)supported_controls); 00367 delete [] attribs; 00368 00369 if (!supported.size()) 00370 return; 00371 00372 m_pictureAttributeCount = supported.size(); 00373 m_pictureAttributes = new VADisplayAttribute[m_pictureAttributeCount]; 00374 for (int i = 0; i < m_pictureAttributeCount; i++) 00375 m_pictureAttributes[i] = supported.at(i); 00376 00377 if (supported_controls & kPictureAttributeSupported_Brightness) 00378 SetPictureAttribute(kPictureAttribute_Brightness, 00379 colourspace.GetPictureAttribute(kPictureAttribute_Brightness)); 00380 if (supported_controls & kPictureAttributeSupported_Hue) 00381 SetPictureAttribute(kPictureAttribute_Hue, 00382 colourspace.GetPictureAttribute(kPictureAttribute_Hue)); 00383 if (supported_controls & kPictureAttributeSupported_Contrast) 00384 SetPictureAttribute(kPictureAttribute_Contrast, 00385 colourspace.GetPictureAttribute(kPictureAttribute_Contrast)); 00386 if (supported_controls & kPictureAttributeSupported_Colour) 00387 SetPictureAttribute(kPictureAttribute_Colour, 00388 colourspace.GetPictureAttribute(kPictureAttribute_Colour)); 00389 } 00390 00391 int VAAPIContext::SetPictureAttribute(PictureAttribute attribute, int newValue) 00392 { 00393 if (!m_display) 00394 return newValue; 00395 if (!m_display->m_va_disp) 00396 return newValue; 00397 00398 int adj = 0; 00399 VADisplayAttribType attrib = VADisplayAttribBrightness; 00400 switch (attribute) 00401 { 00402 case kPictureAttribute_Brightness: 00403 attrib = VADisplayAttribBrightness; 00404 break; 00405 case kPictureAttribute_Contrast: 00406 attrib = VADisplayAttribContrast; 00407 break; 00408 case kPictureAttribute_Hue: 00409 attrib = VADisplayAttribHue; 00410 adj = m_hueBase; 00411 break; 00412 case kPictureAttribute_Colour: 00413 attrib = VADisplayAttribSaturation; 00414 break; 00415 default: 00416 return -1; 00417 } 00418 00419 bool found = false; 00420 for (int i = 0; i < m_pictureAttributeCount; i++) 00421 { 00422 if (m_pictureAttributes[i].type == attrib) 00423 { 00424 int min = m_pictureAttributes[i].min_value; 00425 int max = m_pictureAttributes[i].max_value; 00426 int val = min + (int)(((float)((newValue + adj) % 100) / 100.0) * (max - min)); 00427 m_pictureAttributes[i].value = val; 00428 found = true; 00429 break; 00430 } 00431 } 00432 00433 if (found) 00434 { 00435 INIT_ST; 00436 va_status = vaSetDisplayAttributes(m_display->m_va_disp, 00437 m_pictureAttributes, 00438 m_pictureAttributeCount); 00439 CHECK_ST; 00440 return newValue; 00441 } 00442 return -1; 00443 } 00444 00445 bool VAAPIContext::CreateBuffers(void) 00446 { 00447 bool ok = true; 00448 CREATE_CHECK(!m_size.isEmpty(), "Invalid size"); 00449 CREATE_CHECK(InitBuffers(), "Failed to create buffers."); 00450 CREATE_CHECK(InitContext(), "Failed to create context"); 00451 if (ok) 00452 LOG(VB_PLAYBACK, LOG_INFO, LOC + 00453 QString("Created %1 buffers").arg(m_numSurfaces)); 00454 return ok; 00455 } 00456 00457 bool VAAPIContext::InitDisplay(void) 00458 { 00459 if (!m_display) 00460 return false; 00461 m_ctx.display = m_display->m_va_disp; 00462 return m_ctx.display; 00463 } 00464 00465 bool VAAPIContext::InitProfiles(void) 00466 { 00467 if (!(codec_is_vaapi_hw(m_codec)) || !m_ctx.display) 00468 return false; 00469 00470 MythXLocker locker(m_display->m_x_disp); 00471 int max_profiles, max_entrypoints; 00472 VAProfile profile_wanted = preferredProfile(m_codec); 00473 if (profile_wanted == VAProfileMPEG2Simple) 00474 { 00475 LOG(VB_PLAYBACK, LOG_ERR, LOC + "Codec is not supported."); 00476 return false; 00477 } 00478 00479 VAProfile profile_found = VAProfileMPEG2Simple; // unsupported value 00480 VAEntrypoint entry_found = VAEntrypointEncSlice; // unsupported value 00481 00482 max_profiles = vaMaxNumProfiles(m_ctx.display); 00483 max_entrypoints = vaMaxNumEntrypoints(m_ctx.display); 00484 VAProfile *profiles = new VAProfile[max_profiles]; 00485 VAEntrypoint *entries = new VAEntrypoint[max_entrypoints]; 00486 00487 static bool debugged = false; 00488 if (profiles && entries) 00489 { 00490 INIT_ST; 00491 int act_profiles, act_entries; 00492 va_status = vaQueryConfigProfiles(m_ctx.display, 00493 profiles, 00494 &act_profiles); 00495 CHECK_ST; 00496 if (ok && act_profiles > 0) 00497 { 00498 for (int i = 0; i < act_profiles; i++) 00499 { 00500 va_status = vaQueryConfigEntrypoints(m_ctx.display, 00501 profiles[i], 00502 entries, 00503 &act_entries); 00504 if (va_status == VA_STATUS_SUCCESS && act_entries > 0) 00505 { 00506 if (profiles[i] == profile_wanted) 00507 { 00508 profile_found = profile_wanted; 00509 for (int j = 0; j < act_entries; j++) 00510 if (entries[j] < entry_found) 00511 entry_found = entries[j]; 00512 } 00513 00514 if (!debugged) 00515 { 00516 QString entrylist = "Entrypoints: "; 00517 for (int j = 0; j < act_entries; j++) 00518 entrylist += entryToString(entries[j]); 00519 LOG(VB_GENERAL, LOG_INFO, LOC + 00520 QString("Profile: %1 %2") 00521 .arg(profileToString(profiles[i])) 00522 .arg(entrylist)); 00523 } 00524 } 00525 } 00526 } 00527 debugged = true; 00528 } 00529 delete [] profiles; 00530 delete [] entries; 00531 00532 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Desired profile for '%1': %2") 00533 .arg(toString(m_codec)).arg(profileToString(profile_wanted))); 00534 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found profile %1 with entry %2") 00535 .arg(profileToString(profile_found)).arg(entryToString(entry_found))); 00536 00537 if (profile_wanted != profile_found) 00538 { 00539 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find supported profile."); 00540 return false; 00541 } 00542 00543 if (entry_found > VAEntrypointVLD) 00544 { 00545 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find suitable entry point."); 00546 return false; 00547 } 00548 00549 m_vaProfile = profile_wanted; 00550 m_vaEntrypoint = entry_found; 00551 if (VAEntrypointVLD == m_vaEntrypoint) 00552 m_pix_fmt = PIX_FMT_VAAPI_VLD; 00553 return true; 00554 } 00555 00556 bool VAAPIContext::InitBuffers(void) 00557 { 00558 if (!m_ctx.display) 00559 return false; 00560 00561 MythXLocker locker(m_display->m_x_disp); 00562 m_surfaces = new VASurfaceID[m_numSurfaces]; 00563 m_surfaceData = new vaapi_surface[m_numSurfaces]; 00564 00565 if (!m_surfaces || !m_surfaceData) 00566 return false; 00567 00568 memset(m_surfaces, 0, m_numSurfaces * sizeof(VASurfaceID)); 00569 memset(m_surfaceData, 0, m_numSurfaces * sizeof(vaapi_surface)); 00570 00571 INIT_ST; 00572 va_status = vaCreateSurfaces(m_ctx.display, m_size.width(), m_size.height(), 00573 VA_RT_FORMAT_YUV420, m_numSurfaces, 00574 m_surfaces); 00575 CHECK_ST; 00576 00577 for (int i = 0; i < m_numSurfaces; i++) 00578 m_surfaceData[i].m_id = m_surfaces[i]; 00579 return ok; 00580 } 00581 00582 bool VAAPIContext::InitContext(void) 00583 { 00584 if (!m_ctx.display || m_vaEntrypoint > VAEntrypointVLD) 00585 return false; 00586 00587 MythXLocker locker(m_display->m_x_disp); 00588 VAConfigAttrib attrib; 00589 attrib.type = VAConfigAttribRTFormat; 00590 INIT_ST; 00591 va_status = vaGetConfigAttributes(m_ctx.display, m_vaProfile, 00592 m_vaEntrypoint, &attrib, 1); 00593 CHECK_ST; 00594 00595 if (!ok || !(attrib.value & VA_RT_FORMAT_YUV420)) 00596 { 00597 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to confirm YUV420 chroma"); 00598 return false; 00599 } 00600 00601 va_status = vaCreateConfig(m_ctx.display, m_vaProfile, m_vaEntrypoint, 00602 &attrib, 1, &m_ctx.config_id); 00603 CHECK_ST; 00604 if (!ok) 00605 { 00606 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create decoder config."); 00607 return false; 00608 } 00609 00610 va_status = vaCreateContext(m_ctx.display, m_ctx.config_id, 00611 m_size.width(), m_size.height(), VA_PROGRESSIVE, 00612 m_surfaces, m_numSurfaces, 00613 &m_ctx.context_id); 00614 CHECK_ST; 00615 if (!ok) 00616 { 00617 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create decoder context."); 00618 return false; 00619 } 00620 return true; 00621 } 00622 00623 void* VAAPIContext::GetVideoSurface(int i) 00624 { 00625 if (i < 0 || i >= m_numSurfaces) 00626 return NULL; 00627 return &m_surfaceData[i]; 00628 } 00629 00630 uint8_t* VAAPIContext::GetSurfaceIDPointer(void* buf) 00631 { 00632 if (!buf) 00633 return NULL; 00634 00635 const vaapi_surface *surf = (vaapi_surface*)buf; 00636 if (!surf->m_id) 00637 return NULL; 00638 00639 INIT_ST; 00640 va_status = vaSyncSurface(m_ctx.display, surf->m_id); 00641 CHECK_ST; 00642 return (uint8_t*)(uintptr_t)surf->m_id; 00643 } 00644 00645 bool VAAPIContext::InitImage(const void *buf) 00646 { 00647 if (!buf) 00648 return false; 00649 if (!m_dispType == kVADisplayX11) 00650 return true; 00651 00652 int num_formats = 0; 00653 int max_formats = vaMaxNumImageFormats(m_ctx.display); 00654 VAImageFormat *formats = new VAImageFormat[max_formats]; 00655 00656 INIT_ST; 00657 va_status = vaQueryImageFormats(m_ctx.display, formats, &num_formats); 00658 CHECK_ST; 00659 00660 const vaapi_surface *surf = (vaapi_surface*)buf; 00661 for (int i = 0; i < num_formats; i++) 00662 { 00663 if(formats[i].fourcc == VA_FOURCC('Y','V','1','2') || 00664 formats[i].fourcc == VA_FOURCC('I','4','2','0') || 00665 formats[i].fourcc == VA_FOURCC('N','V','1','2')) 00666 { 00667 if (vaCreateImage(m_ctx.display, &formats[i], 00668 m_size.width(), m_size.height(), &m_image)) 00669 { 00670 m_image.image_id = VA_INVALID_ID; 00671 continue; 00672 } 00673 00674 if (vaGetImage(m_ctx.display, surf->m_id, 0, 0, 00675 m_size.width(), m_size.height(), m_image.image_id)) 00676 { 00677 vaDestroyImage(m_ctx.display, m_image.image_id); 00678 m_image.image_id = VA_INVALID_ID; 00679 continue; 00680 } 00681 break; 00682 } 00683 } 00684 00685 delete [] formats; 00686 00687 if (m_image.image_id == VA_INVALID_ID) 00688 { 00689 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create software image."); 00690 return false; 00691 } 00692 00693 LOG(VB_GENERAL, LOG_DEBUG, 00694 LOC + QString("InitImage: id %1, width %2 height %3 " 00695 "format %4") 00696 .arg(m_image.image_id).arg(m_image.width).arg(m_image.height) 00697 .arg(m_image.format.fourcc)); 00698 00699 return true; 00700 } 00701 00702 bool VAAPIContext::CopySurfaceToFrame(VideoFrame *frame, const void *buf) 00703 { 00704 MythXLocker locker(m_display->m_x_disp); 00705 00706 if (m_image.image_id == VA_INVALID_ID) 00707 InitImage(buf); 00708 00709 if (!frame || !buf || (m_dispType != kVADisplayX11) || 00710 m_image.image_id == VA_INVALID_ID) 00711 return false; 00712 00713 const vaapi_surface *surf = (vaapi_surface*)buf; 00714 00715 INIT_ST; 00716 va_status = vaSyncSurface(m_ctx.display, surf->m_id); 00717 CHECK_ST; 00718 00719 va_status = vaGetImage(m_ctx.display, surf->m_id, 0, 0, 00720 m_size.width(), m_size.height(), m_image.image_id); 00721 CHECK_ST; 00722 00723 if (ok) 00724 { 00725 void* source = NULL; 00726 if (vaMapBuffer(m_ctx.display, m_image.buf, &source)) 00727 return false; 00728 00729 if (m_image.format.fourcc == VA_FOURCC('Y','V','1','2') || 00730 m_image.format.fourcc == VA_FOURCC('I','4','2','0')) 00731 { 00732 bool swap = m_image.format.fourcc == VA_FOURCC('Y','V','1','2'); 00733 VideoFrame src; 00734 init(&src, FMT_YV12, (unsigned char*)source, m_image.width, 00735 m_image.height, m_image.data_size, NULL, 00736 NULL, frame->aspect, frame->frame_rate); 00737 src.pitches[0] = m_image.pitches[0]; 00738 src.pitches[1] = m_image.pitches[swap ? 2 : 1]; 00739 src.pitches[2] = m_image.pitches[swap ? 1 : 2]; 00740 src.offsets[0] = m_image.offsets[0]; 00741 src.offsets[1] = m_image.offsets[swap ? 2 : 1]; 00742 src.offsets[2] = m_image.offsets[swap ? 1 : 2]; 00743 copy(frame, &src); 00744 } 00745 else if (m_image.format.fourcc == VA_FOURCC('N','V','1','2')) 00746 { 00747 AVPicture img_in, img_out; 00748 avpicture_fill(&img_out, (uint8_t *)frame->buf, PIX_FMT_YUV420P, 00749 frame->width, frame->height); 00750 avpicture_fill(&img_in, (uint8_t *)source, PIX_FMT_NV12, 00751 m_image.width, m_image.height); 00752 myth_sws_img_convert(&img_out, PIX_FMT_YUV420P, 00753 &img_in, PIX_FMT_NV12, 00754 frame->width, frame->height); 00755 // Is this needed? Is it safe? 00756 frame->pitches[0] = img_out.linesize[0]; 00757 frame->pitches[1] = img_out.linesize[1]; 00758 frame->pitches[2] = img_out.linesize[2]; 00759 frame->offsets[0] = 0; 00760 frame->offsets[1] = img_out.data[1] - img_out.data[0]; 00761 frame->offsets[2] = img_out.data[2] - img_out.data[0]; 00762 } 00763 if (vaUnmapBuffer(m_ctx.display, m_image.buf)) 00764 return false; 00765 } 00766 00767 if (ok) 00768 return true; 00769 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get image"); 00770 return false; 00771 } 00772 00773 bool VAAPIContext::CopySurfaceToTexture(const void* buf, uint texture, 00774 uint texture_type, FrameScanType scan) 00775 { 00776 if (!buf || (m_dispType != kVADisplayGLX)) 00777 return false; 00778 00779 const vaapi_surface *surf = (vaapi_surface*)buf; 00780 void* glx_surface = GetGLXSurface(texture, texture_type); 00781 if (!glx_surface) 00782 return false; 00783 00784 int field = VA_FRAME_PICTURE; 00785 if (scan == kScan_Interlaced) 00786 field = VA_TOP_FIELD; 00787 else if (scan == kScan_Intr2ndField) 00788 field = VA_BOTTOM_FIELD; 00789 00790 m_display->m_x_disp->Lock(); 00791 INIT_ST; 00792 va_status = vaCopySurfaceGLX(m_ctx.display, glx_surface, surf->m_id, field); 00793 CHECK_ST; 00794 m_display->m_x_disp->Unlock(); 00795 return true; 00796 } 00797 00798 void* VAAPIContext::GetGLXSurface(uint texture, uint texture_type) 00799 { 00800 if (m_dispType != kVADisplayGLX) 00801 return NULL; 00802 00803 if (m_glxSurfaces.contains(texture)) 00804 return m_glxSurfaces.value(texture); 00805 00806 MythXLocker locker(m_display->m_x_disp); 00807 void *glx_surface = NULL; 00808 INIT_ST; 00809 va_status = vaCreateSurfaceGLX(m_ctx.display, texture_type, 00810 texture, &glx_surface); 00811 CHECK_ST; 00812 if (!glx_surface) 00813 { 00814 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create GLX surface."); 00815 return NULL; 00816 } 00817 00818 m_glxSurfaces.insert(texture, glx_surface); 00819 00820 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Number of VAAPI GLX surfaces: %1") 00821 .arg(m_glxSurfaces.size())); 00822 return glx_surface; 00823 } 00824 00825 void VAAPIContext::ClearGLXSurfaces(void) 00826 { 00827 if (!m_display || (m_dispType != kVADisplayGLX)) 00828 return; 00829 00830 MythXLocker locker(m_display->m_x_disp); 00831 INIT_ST; 00832 foreach (void* surface, m_glxSurfaces) 00833 { 00834 va_status = vaDestroySurfaceGLX(m_ctx.display, surface); 00835 CHECK_ST; 00836 } 00837 m_glxSurfaces.clear(); 00838 }
1.7.6.1