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;
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
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;
00480 VAEntrypoint entry_found = VAEntrypointEncSlice;
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
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 }