MythTV  0.26-pre
vaapicontext.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends