Ticket #8593: vaapi-working.diff

File vaapi-working.diff, 37.9 KB (added by markk, 9 years ago)

Working version of VAAPI support

  • mythtv/configure

    diff --git a/mythtv/configure b/mythtv/configure
    index 667aadc..b5165f6 100755
    a b Advanced options (experts only): 
    122122  --disable-xv             disable XVideo   (X11 video output accel.)
    123123  --enable-vdpau           enable NVidia VDPAU hardware acceleration.
    124124  --enable-crystalhd       enable Broadcom CrystalHD hardware decoder support
     125  --enablevaapi            enable VAAPI hardware accelerated video decoding
    125126  --enable-dxva2           enable hardware accelerated decoding on windows
    126127  --disable-opengl-video   disable OpenGL based video display
    127128  --disable-quartz-video   disable Mac OS X CoreVideo based video display
    USING_LIST=' 
    13991400    dxva2
    14001401    opengl
    14011402    opengles
     1403    vaapi
    14021404    vdpau
    14031405'
    14041406
    v4l1_deps="backend v4l2 linux_videodev_h" 
    17751777vdpau_deps="opengl vdpau_vdpau_h vdpau_vdpau_x11_h"
    17761778xrandr_deps="x11"
    17771779xv_deps="x11"
     1780vaapi_deps="x11 opengl"
    17781781asi_deps="backend"
    17791782
    17801783<<BLOCKQUOTE
    check_header sys/select.h 
    36353638check_header termios.h
    36363639check_header vdpau/vdpau.h
    36373640check_header vdpau/vdpau_x11.h
     3641check_header va/va.h
     3642check_header va/va_x11.h
     3643check_header va/va_glx.h
    36383644
    36393645check_struct dxva2api.h DXVA_PictureParameters wDecodedPictureIndex
    36403646
    if enabled crystalhd; then 
    39143920        disable crystalhd;
    39153921fi
    39163922
     3923if enabled vaapi; then
     3924    enabled va_va_h && enabled va_va_glx_h && enabled va_va_x11_h || disable vaapi
     3925    if enabled vaapi; then
     3926        # TODO check for SDS versions
     3927        check_cpp_condition va/va.h "VA_VERSION_HEX >= 0x001F0000" ||
     3928        { echolog "VAAPI requires libva >= 0.31.1" && disable vaapi; }
     3929    fi
     3930else
     3931    disable vaapi
     3932fi
     3933
    39173934if enabled dxva2; then
    39183935    enabled dxva2api_h && enabled windows || disable dxva2
    39193936else
    if enabled x11 ; then 
    44734490  echo "xrandr support            ${xrandr-no}"
    44744491  echo "xv support                ${xv-no}"
    44754492  echo "VDPAU support             ${vdpau-no}"
     4493  echo "VAAPI support             ${vaapi-no}"
    44764494  echo "CrystalHD support         ${crystalhd-no}"
    44774495fi
    44784496  echo "OpenGL video              ${opengl_video-no}"
  • mythtv/libs/libmythtv/avformatdecoder.cpp

    diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
    index d18dcf6..788154c 100644
    a b extern "C" { 
    5353#include "videoout_d3d.h"
    5454#endif
    5555
     56#ifdef USING_VAAPI
     57#include "videoout_openglvaapi.h"
     58#include "vaapicontext.h"
     59#endif // USING_VAAPI
     60
    5661extern "C" {
    5762#include "libavutil/avutil.h"
    5863#include "libavcodec/ac3_parser.h"
    void release_avf_buffer_vdpau(struct AVCodecContext *c, AVFrame *pic); 
    125130void render_slice_vdpau(struct AVCodecContext *s, const AVFrame *src,
    126131                        int offset[4], int y, int type, int height);
    127132int  get_avf_buffer_dxva2(struct AVCodecContext *c, AVFrame *pic);
     133int  get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic);
    128134
    129135static AVCodec *find_vdpau_decoder(AVCodec *c, enum CodecID id)
    130136{
    void AvFormatDecoder::GetDecoders(render_opts &opts) 
    238244    (*opts.equiv_decoders)["dxva2"].append("dummy");
    239245#endif
    240246
     247#ifdef USING_VAAPI
     248    opts.decoders->append("vaapi");
     249    (*opts.equiv_decoders)["vaapi"].append("dummy");
     250#endif
     251
    241252    PrivateDecoder::GetDecoders(opts);
    242253}
    243254
    void AvFormatDecoder::InitVideoCodec(AVStream *stream, AVCodecContext *enc, 
    12751286        enc->get_format      = get_format_dxva2;
    12761287        enc->release_buffer  = release_avf_buffer;
    12771288    }
     1289    else if (CODEC_IS_VAAPI(codec, enc))
     1290    {
     1291        enc->get_buffer      = get_avf_buffer_vaapi;
     1292        enc->get_format      = get_format_vaapi;
     1293        enc->release_buffer  = release_avf_buffer;
     1294        enc->slice_flags     = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
     1295    }
    12781296    else if (codec && codec->capabilities & CODEC_CAP_DR1)
    12791297    {
    12801298        enc->flags          |= CODEC_FLAG_EMU_EDGE;
    int AvFormatDecoder::ScanStreams(bool novideo) 
    18101828                        handled = true;
    18111829                    }
    18121830#endif // USING_VDPAU
     1831#ifdef USING_VAAPI
     1832                    MythCodecID vaapi_mcid;
     1833                    PixelFormat pix_fmt = PIX_FMT_YUV420P;
     1834                    vaapi_mcid = VideoOutputOpenGLVAAPI::GetBestSupportedCodec(
     1835                            width, height, mpeg_version(enc->codec_id),
     1836                            no_hardware_decoders, pix_fmt);
     1837
     1838                    if (vaapi_mcid >= video_codec_id)
     1839                    {
     1840                        enc->codec_id = (CodecID)myth2av_codecid(vaapi_mcid);
     1841                        video_codec_id = vaapi_mcid;
     1842                        handled = true;
     1843                        if (!no_hardware_decoders &&
     1844                            codec_is_vaapi(video_codec_id))
     1845                        {
     1846                            enc->pix_fmt = pix_fmt;
     1847                        }
     1848                    }
     1849#endif // USING_VAAPI
    18131850#ifdef USING_DXVA2
    18141851                    MythCodecID dxva2_mcid;
    18151852                    PixelFormat pix_fmt = PIX_FMT_YUV420P;
    int get_avf_buffer_dxva2(struct AVCodecContext *c, AVFrame *pic) 
    23992436    return 0;
    24002437}
    24012438
     2439int get_avf_buffer_vaapi(struct AVCodecContext *c, AVFrame *pic)
     2440{
     2441    AvFormatDecoder *nd = (AvFormatDecoder *)(c->opaque);
     2442    VideoFrame *frame = nd->GetPlayer()->GetNextVideoFrame();
     2443
     2444    pic->data[0]     = frame->buf;
     2445    pic->data[1]     = NULL;
     2446    pic->data[2]     = NULL;
     2447    pic->data[3]     = NULL;
     2448    pic->linesize[0] = 0;
     2449    pic->linesize[1] = 0;
     2450    pic->linesize[2] = 0;
     2451    pic->linesize[3] = 0;
     2452    pic->opaque      = frame;
     2453    pic->type        = FF_BUFFER_TYPE_USER;
     2454    pic->age         = 256 * 256 * 256 * 64;
     2455    frame->pix_fmt   = c->pix_fmt;
     2456
     2457#ifdef USING_VAAPI
     2458    if (nd->GetPlayer()->getVideoOutput())
     2459    {
     2460        VideoOutputOpenGLVAAPI *vo =
     2461            dynamic_cast<VideoOutputOpenGLVAAPI*>(nd->GetPlayer()->getVideoOutput());
     2462        c->hwaccel_context = (vaapi_context*)vo->GetVAAPIContext();
     2463        pic->data[3] = vo->GetSurfaceIDPointer(frame->buf);
     2464    }
     2465#endif
     2466
     2467    return 0;
     2468}
     2469
    24022470void AvFormatDecoder::DecodeDTVCC(const uint8_t *buf, uint len)
    24032471{
    24042472    if (!len)
  • mythtv/libs/libmythtv/libmythtv.pro

    diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro
    index 7f03f79..f87d629 100644
    a b using_frontend { 
    370370    using_opengl_video:HEADERS += openglvideo.h   videoout_opengl.h
    371371    using_opengl_video:SOURCES += openglvideo.cpp videoout_opengl.cpp
    372372
     373    using_vaapi: DEFINES += USING_VAAPI
     374    using_vaapi: DEFINES += vaapicontext.h   videoout_openglvaapi.h
     375    using_vaapi: SOURCES += vaapicontext.cpp videoout_openglvaapi.cpp
     376    using_vaapi: LIBS    += -lva -lva-x11 -lva-glx
     377
    373378    # Misc. frontend
    374379    HEADERS += DetectLetterbox.h
    375380    SOURCES += DetectLetterbox.cpp
  • mythtv/libs/libmythtv/videodisplayprofile.cpp

    diff --git a/mythtv/libs/libmythtv/videodisplayprofile.cpp b/mythtv/libs/libmythtv/videodisplayprofile.cpp
    index f78c5c1..bb31bb0 100644
    a b QString VideoDisplayProfile::GetDecoderName(const QString &decoder) 
    639639        dec_name["ffmpeg"]   = QObject::tr("Standard");
    640640        dec_name["macaccel"] = QObject::tr("Mac hardware acceleration");
    641641        dec_name["vdpau"]    = QObject::tr("NVidia VDPAU acceleration");
     642        dec_name["vaapi"]    = QObject::tr("VAAPI acceleration");
    642643        dec_name["dxva2"]    = QObject::tr("Windows hardware acceleration");
    643644    }
    644645
    QString VideoDisplayProfile::GetDecoderHelp(QString decoder) 
    680681            "accelerate video decoding and playback "
    681682            "(requires Windows Vista or later).");
    682683
     684    if (decoder == "vaapi")
     685        msg += QObject::tr(
     686            "VAAPI will attempt to use the graphics hardware to "
     687            "accelerate video decoding.");
    683688    return msg;
    684689}
    685690
    QString VideoDisplayProfile::GetDeinterlacerName(const QString short_name) 
    737742        return QObject::tr("Advanced (1x, HW)");
    738743    else if ("vdpauadvanceddoublerate" == short_name)
    739744        return QObject::tr("Advanced (2x, HW)");
     745    else if ("vaapionefield" == short_name)
     746        return QObject::tr("One Field (1x, HW)");
     747    else if ("vaapibobdeint" == short_name)
     748        return QObject::tr("Bob (2x, HW)");
    740749
    741750    return "";
    742751}
    QString VideoDisplayProfile::GetVideoRendererHelp(const QString &renderer) 
    11671176            "This is the only video renderer for NVidia VDPAU decoding.");
    11681177    }
    11691178
     1179    if (renderer == "openglvaapi")
     1180    {
     1181        msg = QObject::tr(
     1182             "This video renderer uses VAAPI for video decoding and "
     1183             "OpenGL for scaling and color conversion.");
     1184    }
     1185
    11701186    return msg;
    11711187}
    11721188
    QString VideoDisplayProfile::GetDeinterlacerHelp(const QString &deint) 
    13001316        msg = kBasicMsg + " " +  kDoubleRateMsg + " " + kUsingGPU;
    13011317    else if (deint == "vdpauadvanceddoublerate")
    13021318        msg = kAdvMsg + " " +  kDoubleRateMsg + " " + kUsingGPU;
     1319    else if (deint == "vaapionefield")
     1320        msg = kOneFieldMsg + " " + kUsingGPU;
     1321    else if (deint == "vaapibobdeint")
     1322        msg = kBobMsg + " " + kUsingGPU;
    13031323    else
    13041324        msg = QObject::tr("'%1' has not been documented yet.").arg(deint);
    13051325
  • mythtv/libs/libmythtv/videoout_opengl.cpp

    diff --git a/mythtv/libs/libmythtv/videoout_opengl.cpp b/mythtv/libs/libmythtv/videoout_opengl.cpp
    index 6ff024b..50e823b 100644
    a b bool VideoOutputOpenGL::SetupContext(void) 
    213213        return false;
    214214    }
    215215
    216     //gl_context = dynamic_cast<MythRenderOpenGL*>(win->GetRenderDevice());
     216    gl_context = dynamic_cast<MythRenderOpenGL*>(win->GetRenderDevice());
    217217    if (gl_context)
    218218    {
    219219        gl_context->UpRef();
  • mythtv/libs/libmythtv/videooutbase.cpp

    diff --git a/mythtv/libs/libmythtv/videooutbase.cpp b/mythtv/libs/libmythtv/videooutbase.cpp
    index 158fce8..3ab5b9e 100644
    a b  
    3636#include "videoout_vdpau.h"
    3737#endif
    3838
     39#ifdef USING_VAAPI
     40#include "videoout_openglvaapi.h"
     41#endif
     42
    3943#include "videoout_null.h"
    4044#include "dithertable.h"
    4145
    void VideoOutput::GetRenderOptions(render_opts &opts) 
    8892#ifdef USING_VDPAU
    8993    VideoOutputVDPAU::GetRenderOptions(opts);
    9094#endif // USING_VDPAU
     95
     96#ifdef USING_VAAPI
     97    VideoOutputOpenGLVAAPI::GetRenderOptions(opts);
     98#endif // USING_VAAPI
    9199}
    92100
    93101/**
    VideoOutput *VideoOutput::Create( 
    131139    renderers += VideoOutputVDPAU::GetAllowedRenderers(codec_id, video_dim);
    132140#endif // USING_VDPAU
    133141
     142#ifdef USING_VAAPI
     143    const QStringList vaapilist
     144            = VideoOutputOpenGLVAAPI::GetAllowedRenderers(codec_id, video_dim);
     145    renderers += vaapilist;
     146#endif // USING_VAAPI
     147
    134148    VERBOSE(VB_PLAYBACK, LOC + "Allowed renderers: " +
    135149            to_comma_list(renderers));
    136150
    VideoOutput *VideoOutput::Create( 
    188202            vo = new VideoOutputVDPAU();
    189203#endif // USING_VDPAU
    190204
     205#ifdef USING_VAAPI
     206        if (renderer == "openglvaapi")
     207            vo = new VideoOutputOpenGLVAAPI();
     208#endif // USING_VAAPI
     209
    191210#ifdef USING_XV
    192211        if (xvlist.contains(renderer))
    193212            vo = new VideoOutputXv();
  • new file mythtv/libs/libmythtv/vaapicontext.cpp

    diff --git a/mythtv/libs/libmythtv/vaapicontext.cpp b/mythtv/libs/libmythtv/vaapicontext.cpp
    new file mode 100644
    index 0000000..b698c8e
    - +  
     1#include "openglvideo.h"
     2#include "mythverbose.h"
     3#include "mythxdisplay.h"
     4#include "mythcodecid.h"
     5#include "frame.h"
     6#include "vaapicontext.h"
     7#include "mythmainwindow.h"
     8
     9#define LOC QString("VAAPI: ")
     10#define ERR QString("VAAPI Error: ")
     11#define NUM_VAAPI_BUFFERS 24
     12
     13#define INIT_ST \
     14  VAStatus va_status; \
     15  bool ok = true;
     16
     17#define CHECK_ST \
     18  ok &= (va_status == VA_STATUS_SUCCESS); \
     19  if (!ok) { \
     20      VERBOSE(VB_IMPORTANT, ERR + QString("Error at %1:%2 (#%3, %4)") \
     21              .arg(__FILE__).arg( __LINE__).arg(va_status) \
     22              .arg(vaErrorStr(va_status))); \
     23  }
     24
     25#define CREATE_CHECK(arg1, arg2) \
     26  if (ok) \
     27  { \
     28      ok = arg1; \
     29      if (!ok) \
     30          VERBOSE(VB_IMPORTANT, ERR + arg2); \
     31  }
     32
     33QString profileToString(VAProfile profile);
     34QString entryToString(VAEntrypoint entry);
     35VAProfile preferredProfile(MythCodecID codec);
     36
     37QString profileToString(VAProfile profile)
     38{
     39    if (VAProfileMPEG2Simple == profile)         return "MPEG2Simple";
     40    if (VAProfileMPEG2Main == profile)           return "MPEG2Main";
     41    if (VAProfileMPEG4Simple == profile)         return "MPEG4Simple";
     42    if (VAProfileMPEG4AdvancedSimple == profile) return "MPEG4AdvSimple";
     43    if (VAProfileMPEG4Main == profile)           return "MPEG4Main";
     44    if (VAProfileH264Baseline == profile)        return "H264Base";
     45    if (VAProfileH264Main == profile)            return "H264Main";
     46    if (VAProfileH264High == profile)            return "H264High";
     47    if (VAProfileVC1Simple == profile)           return "VC1Simple";
     48    if (VAProfileVC1Main == profile)             return "VC1Main";
     49    if (VAProfileVC1Advanced == profile)         return "VC1Advanced";
     50    if (VAProfileH263Baseline == profile)        return "H263Base";
     51    return "Unknown";
     52}
     53
     54QString entryToString(VAEntrypoint entry)
     55{
     56    if (VAEntrypointVLD == entry)        return "VLD ";
     57    if (VAEntrypointIZZ == entry)        return "IZZ (UNSUPPORTED) ";
     58    if (VAEntrypointIDCT == entry)       return "IDCT (UNSUPPORTED) ";
     59    if (VAEntrypointMoComp == entry)     return "MC (UNSUPPORTED) ";
     60    if (VAEntrypointDeblocking == entry) return "Deblock (UNSUPPORTED) ";
     61    if (VAEntrypointEncSlice == entry)   return "EncSlice (UNSUPPORTED) ";
     62    return "Unknown";
     63}
     64
     65VAProfile preferredProfile(MythCodecID codec)
     66{
     67    // FIXME handle unsupported codecs properly
     68    if (kCodec_H263_VAAPI  == codec) return VAProfileMPEG4AdvancedSimple;
     69    if (kCodec_MPEG4_VAAPI == codec) return VAProfileMPEG4AdvancedSimple;
     70    if (kCodec_H264_VAAPI  == codec) return VAProfileH264High;
     71    if (kCodec_VC1_VAAPI   == codec) return VAProfileVC1Advanced;
     72    if (kCodec_WMV3_VAAPI  == codec) return VAProfileVC1Main;
     73    return VAProfileMPEG2Main;
     74}
     75
     76class VAAPIDisplay
     77{
     78  protected:
     79    VAAPIDisplay() : m_va_disp(NULL), m_x_disp(NULL), m_ref_count(0) { }
     80  public:
     81   ~VAAPIDisplay()
     82    {
     83        if (m_va_disp)
     84        {
     85            INIT_ST
     86            XLOCK(m_x_disp, va_status = vaTerminate(m_va_disp));
     87            CHECK_ST
     88        }
     89        if (m_x_disp)
     90        {
     91            m_x_disp->Sync(true);
     92            delete m_x_disp;
     93        }
     94    }
     95
     96    bool Create(void)
     97    {
     98        MythMainWindow *mw = GetMythMainWindow();
     99        if (!mw)
     100            return false;
     101
     102        MythRenderOpenGL *gl = static_cast<MythRenderOpenGL*>(mw->GetRenderDevice());
     103        if (!gl)
     104        {
     105            VERBOSE(VB_PLAYBACK, LOC +
     106                    QString("Failed to get OpenGL context - you must use the "
     107                            "OpenGL UI painter for VAAPI support."));
     108            return false;
     109        }
     110        gl->makeCurrent();
     111        display = glXGetCurrentDisplay();
     112        gl->doneCurrent();
     113
     114        m_x_disp = OpenMythXDisplay();
     115        if (!m_x_disp)
     116            return false;
     117
     118        MythXLocker locker(m_x_disp);
     119        int major_ver, minor_ver;
     120
     121        //m_va_disp = vaGetDisplayGLX(m_x_disp->GetDisplay());
     122        m_va_disp = vaGetDisplayGLX(display);
     123
     124        if (!m_va_disp)
     125        {
     126            VERBOSE(VB_IMPORTANT, ERR + "Failed to create VADisplay");
     127            return false;
     128        }
     129
     130        INIT_ST
     131        va_status = vaInitialize(m_va_disp, &major_ver, &minor_ver);
     132        CHECK_ST
     133
     134        static bool debugged = false;
     135        if (ok && !debugged)
     136        {
     137            debugged = true;
     138            VERBOSE(VB_IMPORTANT, LOC + QString("Version: %1.%2")
     139                                        .arg(major_ver).arg(minor_ver));
     140            VERBOSE(VB_IMPORTANT, LOC + QString("Vendor : %1")
     141                                        .arg(vaQueryVendorString(m_va_disp)));
     142        }
     143        if (ok)
     144        {
     145            UpRef();
     146            VERBOSE(VB_PLAYBACK, LOC + QString("Created VAAPI GLX display"));
     147        }
     148        return ok;
     149    }
     150
     151    void UpRef(void)
     152    {
     153        XLOCK(m_x_disp, m_ref_count++)
     154    }
     155
     156    void DownRef(void)
     157    {
     158        m_x_disp->Lock();
     159        m_ref_count--;
     160        if (m_ref_count <= 0)
     161        {
     162            if (gVAAPIDisplay == this)
     163                gVAAPIDisplay = NULL;
     164            VERBOSE(VB_PLAYBACK, LOC + "Deleting VAAPI display.");
     165            m_x_disp->Unlock();
     166            delete this;
     167            return;
     168        }
     169        m_x_disp->Unlock();
     170    }
     171
     172    static VAAPIDisplay* GetDisplay(void)
     173    {
     174        if (gVAAPIDisplay)
     175        {
     176            gVAAPIDisplay->UpRef();
     177            return gVAAPIDisplay;
     178        }
     179
     180        gVAAPIDisplay = new VAAPIDisplay();
     181        if (gVAAPIDisplay && gVAAPIDisplay->Create())
     182            return gVAAPIDisplay;
     183
     184        delete gVAAPIDisplay;
     185        gVAAPIDisplay = NULL;
     186        return NULL;
     187    }
     188
     189    static VAAPIDisplay *gVAAPIDisplay;
     190    void                *m_va_disp;
     191    MythXDisplay        *m_x_disp;
     192    Display             *display;
     193    int                  m_ref_count;
     194};
     195
     196VAAPIDisplay* VAAPIDisplay::gVAAPIDisplay = NULL;
     197
     198bool VAAPIContext::IsFormatAccelerated(QSize size, MythCodecID codec,
     199                                       PixelFormat &pix_fmt)
     200{
     201    bool result = false;
     202    VAAPIContext *ctx = new VAAPIContext(codec);
     203    if (ctx && ctx->CreateDisplay(size))
     204    {
     205        pix_fmt = ctx->GetPixelFormat();
     206        result = pix_fmt == PIX_FMT_VAAPI_VLD;
     207    }
     208    delete ctx;
     209    return result;
     210}
     211
     212VAAPIContext::VAAPIContext(MythCodecID codec)
     213  : m_codec(codec),
     214    m_vaProfile(VAProfileMPEG2Main)/* ?? */,
     215    m_vaEntrypoint(VAEntrypointEncSlice),
     216    m_pix_fmt(PIX_FMT_YUV420P), m_numSurfaces(NUM_VAAPI_BUFFERS),
     217    m_surfaces(NULL), m_surfaceData(NULL)
     218{
     219    memset(&m_ctx, 0, sizeof(vaapi_context));
     220}
     221
     222VAAPIContext::~VAAPIContext()
     223{
     224    if (m_display)
     225    {
     226        m_display->m_x_disp->Lock();
     227
     228        for (int i = 0; i < m_numSurfaces && m_surfaceData; i++)
     229        {
     230            INIT_ST
     231            va_status = vaDestroySurfaceGLX(m_ctx.display,
     232                                            m_surfaceData[i].m_glx_surface);
     233            CHECK_ST
     234        }
     235
     236        INIT_ST
     237        if (m_ctx.context_id)
     238        {
     239            va_status = vaDestroyContext(m_ctx.display, m_ctx.context_id);
     240            CHECK_ST
     241        }
     242        if (m_ctx.config_id)
     243        {
     244            va_status = vaDestroyConfig(m_ctx.display, m_ctx.config_id);
     245            CHECK_ST
     246        }
     247        if (m_surfaces)
     248        {
     249            va_status = vaDestroySurfaces(m_ctx.display, m_surfaces, m_numSurfaces);
     250            CHECK_ST
     251        }
     252    }
     253
     254    if (m_surfaces)
     255        delete [] m_surfaces;
     256    if (m_surfaceData)
     257        delete [] m_surfaceData;
     258
     259    if (m_display)
     260    {
     261        m_display->m_x_disp->Unlock();
     262        m_display->DownRef();
     263    }
     264
     265    VERBOSE(VB_PLAYBACK, LOC + "Deleted context");
     266}
     267
     268bool VAAPIContext::CreateDisplay(QSize size)
     269{
     270    m_size = size;
     271    bool ok = true;
     272    m_display = VAAPIDisplay::GetDisplay();
     273    CREATE_CHECK(!m_size.isEmpty(), "Invalid size")
     274    CREATE_CHECK(m_display != NULL, "Invalid display")
     275    CREATE_CHECK(InitDisplay(),     "Invalid VADisplay")
     276    CREATE_CHECK(InitProfiles(),    "No supported profiles")
     277    if (ok)
     278        VERBOSE(VB_PLAYBACK, LOC + QString("Created context (%1x%2->%3x%4)")
     279            .arg(size.width()).arg(size.height())
     280            .arg(m_size.width()).arg(m_size.height()));
     281    return ok;
     282}
     283
     284bool VAAPIContext::CreateBuffers(void)
     285{
     286    bool ok = true;
     287    CREATE_CHECK(!m_size.isEmpty(), "Invalid size")
     288    CREATE_CHECK(InitBuffers(),     "Failed to create buffers.")
     289    CREATE_CHECK(InitContext(),     "Failed to create context")
     290    if (ok)
     291        VERBOSE(VB_PLAYBACK, LOC + QString("Created %1 buffers").arg(m_numSurfaces));
     292    return ok;
     293}
     294
     295bool VAAPIContext::InitDisplay(void)
     296{
     297    if (!m_display)
     298        return false;
     299    m_ctx.display = m_display->m_va_disp;
     300    return m_ctx.display;
     301}
     302
     303bool VAAPIContext::InitProfiles(void)
     304{
     305    if (!(codec_is_vaapi(m_codec)) || !m_ctx.display)
     306        return false;
     307
     308    MythXLocker locker(m_display->m_x_disp);
     309    int max_profiles, max_entrypoints;
     310    VAProfile profile_wanted = preferredProfile(m_codec);
     311    VAProfile profile_found  = VAProfileMPEG2Main;   // FIXME
     312    VAEntrypoint entry_found = VAEntrypointEncSlice; // unsupported value
     313
     314    max_profiles          = vaMaxNumProfiles(m_ctx.display);
     315    max_entrypoints       = vaMaxNumEntrypoints(m_ctx.display);
     316    VAProfile *profiles   = new VAProfile[max_profiles];
     317    VAEntrypoint *entries = new VAEntrypoint[max_entrypoints];
     318
     319    static bool debugged = false;
     320    if (profiles && entries)
     321    {
     322        INIT_ST
     323        int act_profiles, act_entries;
     324        va_status = vaQueryConfigProfiles(m_ctx.display,
     325                                          profiles,
     326                                         &act_profiles);
     327        CHECK_ST
     328        if (ok && act_profiles > 0)
     329        {
     330            for (int i = 0; i < act_profiles; i++)
     331            {
     332                va_status = vaQueryConfigEntrypoints(m_ctx.display,
     333                                                     profiles[i],
     334                                                     entries,
     335                                                    &act_entries);
     336                if (va_status == VA_STATUS_SUCCESS && act_entries > 0)
     337                {
     338                    if (profiles[i] == profile_wanted)
     339                    {
     340                        profile_found = profile_wanted;
     341                        for (int j = 0; j < act_entries; j++)
     342                            if (entries[j] < entry_found)
     343                                entry_found = entries[j];
     344                    }
     345
     346                    if (!debugged)
     347                    {
     348                        QString entrylist = "Entrypoints: ";
     349                        for (int j = 0; j < act_entries; j++)
     350                            entrylist += entryToString(entries[j]);
     351                        VERBOSE(VB_IMPORTANT, LOC + QString("Profile: %1 %2")
     352                            .arg(profileToString(profiles[i])).arg(entrylist));
     353                    }
     354                }
     355            }
     356        }
     357        debugged = true;
     358    }
     359    delete [] profiles;
     360    delete [] entries;
     361
     362    VERBOSE(VB_PLAYBACK, LOC + QString("Desired profile for '%1': %2")
     363        .arg(toString(m_codec)).arg(profileToString(profile_wanted)));
     364    VERBOSE(VB_PLAYBACK, LOC + QString("Found profile %1 with entry %2")
     365        .arg(profileToString(profile_found)).arg(entryToString(entry_found)));
     366
     367    if (profile_wanted != profile_found)
     368    {
     369        VERBOSE(VB_IMPORTANT, ERR + "Failed to find supported profile.");
     370        return false;
     371    }
     372
     373    if (entry_found > VAEntrypointVLD)
     374    {
     375        VERBOSE(VB_IMPORTANT, ERR + "Failed to find suitable entry point.");
     376        return false;
     377    }
     378
     379    m_vaProfile = profile_wanted;
     380    m_vaEntrypoint = entry_found;
     381    if (VAEntrypointVLD == m_vaEntrypoint)
     382        m_pix_fmt = PIX_FMT_VAAPI_VLD;
     383    return true;
     384}
     385
     386bool VAAPIContext::InitBuffers(void)
     387{
     388    if (!m_ctx.display)
     389        return false;
     390       
     391    MythXLocker locker(m_display->m_x_disp);
     392    m_surfaces    = new VASurfaceID[m_numSurfaces];
     393    m_surfaceData = new vaapi_surface[m_numSurfaces];
     394
     395    if (!m_surfaces || !m_surfaceData)
     396        return false;
     397
     398    memset(m_surfaces, 0, sizeof(m_surfaces));
     399    memset(m_surfaceData, 0, sizeof(m_surfaceData));
     400
     401    INIT_ST
     402    va_status = vaCreateSurfaces(m_ctx.display, m_size.width(), m_size.height(),
     403                                 VA_RT_FORMAT_YUV420, m_numSurfaces,
     404                                 m_surfaces);
     405    CHECK_ST
     406
     407    for (int i = 0; i < m_numSurfaces; i++)
     408        m_surfaceData[i].m_id = m_surfaces[i];
     409    return ok;
     410}
     411
     412bool VAAPIContext::CreateGLXSurfaces(uint tex, uint type)
     413{
     414    if (!m_ctx.display || !m_surfaces || !m_surfaceData)
     415        return false;
     416
     417    void * glx_surface = NULL;
     418    INIT_ST
     419    va_status = vaCreateSurfaceGLX(m_ctx.display, type, tex, &glx_surface);
     420    CHECK_ST
     421
     422    for (int i = 0; i < m_numSurfaces; i++)
     423    {
     424        m_surfaceData[i].m_glx_surface = glx_surface;
     425    }
     426    return ok;
     427}
     428
     429bool VAAPIContext::InitContext(void)
     430{
     431    if (!m_ctx.display || m_vaEntrypoint > VAEntrypointVLD)
     432        return false;
     433
     434    MythXLocker locker(m_display->m_x_disp);
     435    VAConfigAttrib attrib;
     436    attrib.type = VAConfigAttribRTFormat;
     437    INIT_ST
     438    va_status = vaGetConfigAttributes(m_ctx.display, m_vaProfile,
     439                                      m_vaEntrypoint, &attrib, 1);
     440    CHECK_ST
     441
     442    if (!ok || !(attrib.value & VA_RT_FORMAT_YUV420))
     443    {
     444        VERBOSE(VB_IMPORTANT, ERR + "Failed to confirm YUV420 chroma");
     445        return false;
     446    }
     447
     448    va_status = vaCreateConfig(m_ctx.display, m_vaProfile, m_vaEntrypoint,
     449                               &attrib, 1, &m_ctx.config_id);
     450    CHECK_ST
     451    if (!ok)
     452    {
     453        VERBOSE(VB_IMPORTANT, ERR + "Failed to create decoder config.");
     454        return false;
     455    }
     456
     457    va_status = vaCreateContext(m_ctx.display, m_ctx.config_id,
     458                                m_size.width(), m_size.height(), VA_PROGRESSIVE,
     459                                m_surfaces, m_numSurfaces,
     460                                &m_ctx.context_id);
     461    CHECK_ST
     462    if (!ok)
     463    {
     464        VERBOSE(VB_IMPORTANT, ERR + "Failed to create decoder context.");
     465        return false;
     466    }
     467    return true;
     468}
     469
     470void* VAAPIContext::GetVideoSurface(int i)
     471{
     472    if (i < 0 || i >= m_numSurfaces)
     473        return NULL;
     474    return &m_surfaceData[i];
     475}
     476
     477uint8_t* VAAPIContext::GetSurfaceIDPointer(void* buf)
     478{
     479    if (!buf)
     480        return NULL;
     481
     482    const vaapi_surface *surf = (vaapi_surface*)buf;
     483    if (!surf->m_id)
     484        return NULL;
     485
     486    INIT_ST
     487    va_status = vaSyncSurface(m_ctx.display, surf->m_id);
     488    CHECK_ST
     489    return (uint8_t*)(uintptr_t)surf->m_id;
     490}
     491
     492bool VAAPIContext::CopySurfaceToTexture(const void* buf, FrameScanType scan)
     493{
     494    if (!buf)
     495        return false;
     496
     497    const vaapi_surface *surf = (vaapi_surface*)buf;
     498    if (!surf)
     499        return false;
     500    if (!surf->m_glx_surface)
     501        return false;
     502
     503    int field = VA_FRAME_PICTURE;
     504    //if (scan == kScan_Interlaced)
     505    //    field = VA_TOP_FIELD;
     506    //else if (scan == kScan_Intr2ndField)
     507    //    field = VA_BOTTOM_FIELD;
     508
     509    INIT_ST
     510    va_status = vaSyncSurface(m_ctx.display, surf->m_id);
     511    CHECK_ST
     512
     513    va_status = vaCopySurfaceGLX(m_ctx.display, surf->m_glx_surface,
     514                                 surf->m_id, field);
     515    CHECK_ST
     516    return true;
     517}
     518
  • new file mythtv/libs/libmythtv/vaapicontext.h

    diff --git a/mythtv/libs/libmythtv/vaapicontext.h b/mythtv/libs/libmythtv/vaapicontext.h
    new file mode 100644
    index 0000000..6b42d4d
    - +  
     1#ifndef VAAPICONTEXT_H
     2#define VAAPICONTEXT_H
     3
     4extern "C" {
     5#include "libavcodec/vaapi.h"
     6}
     7#include "va/va_glx.h"
     8
     9struct vaapi_surface
     10{
     11    VASurfaceID m_id;
     12    void*       m_glx_surface;
     13};
     14
     15class VAAPIDisplay;
     16class OpenGLVideo;
     17
     18class VAAPIContext
     19{
     20  public:
     21    static bool IsFormatAccelerated(QSize size, MythCodecID codec,
     22                                    PixelFormat &pix_fmt);
     23    VAAPIContext(MythCodecID codec);
     24   ~VAAPIContext();
     25
     26    bool  CreateDisplay(QSize size);
     27    bool  CreateBuffers(void);
     28    bool  CreateGLXSurfaces(uint tex, uint type);
     29    void* GetVideoSurface(int i);
     30    uint8_t* GetSurfaceIDPointer(void* buf);
     31   
     32    int   GetNumBuffers(void)        { return m_numSurfaces; }
     33    PixelFormat GetPixelFormat(void) { return m_pix_fmt;     }
     34
     35    bool  CopySurfaceToTexture(const void* buf, FrameScanType scan);
     36
     37    bool InitDisplay(void);
     38    bool InitProfiles(void);
     39    bool InitBuffers(void);
     40    bool InitContext(void);
     41
     42    vaapi_context  m_ctx;
     43    MythCodecID    m_codec;
     44    QSize          m_size;
     45    VAAPIDisplay  *m_display;
     46    VAProfile      m_vaProfile;
     47    VAEntrypoint   m_vaEntrypoint;
     48    PixelFormat    m_pix_fmt;
     49    int            m_numSurfaces;
     50    VASurfaceID   *m_surfaces;
     51    vaapi_surface *m_surfaceData;
     52};
     53
     54#endif // VAAPICONTEXT_H
  • new file mythtv/libs/libmythtv/videoout_openglvaapi.cpp

    diff --git a/mythtv/libs/libmythtv/videoout_openglvaapi.cpp b/mythtv/libs/libmythtv/videoout_openglvaapi.cpp
    new file mode 100644
    index 0000000..6c1a105
    - +  
     1#include "videoout_openglvaapi.h"
     2#include "vaapicontext.h"
     3
     4#define LOC QString("VidOutGLVAAPI: ")
     5#define ERR QString("VidOutGLVAAPI Error: ")
     6
     7void VideoOutputOpenGLVAAPI::GetRenderOptions(render_opts &opts)
     8{
     9    opts.renderers->append("openglvaapi");
     10
     11    (*opts.deints)["openglvaapi"].append("vaapionefield");
     12    (*opts.deints)["openglvaapi"].append("vaapibobdeint");
     13    (*opts.deints)["openglvaapi"].append("none");
     14    (*opts.osds)["openglvaapi"].append("opengl2");
     15
     16    if (opts.decoders->contains("vaapi"))
     17        (*opts.safe_renderers)["vaapi"].append("openglvaapi");
     18
     19    if (opts.decoders->contains("ffmpeg"))
     20        (*opts.safe_renderers)["ffmpeg"].append("openglvaapi");
     21
     22    (*opts.safe_renderers)["dummy"].append("openglvaapi");
     23    (*opts.safe_renderers)["nuppel"].append("openglvaapi");
     24
     25    opts.priorities->insert("openglvaapi", 120);
     26}
     27
     28VideoOutputOpenGLVAAPI::VideoOutputOpenGLVAAPI()
     29  : VideoOutputOpenGL(), m_ctx(NULL)
     30{
     31}
     32
     33VideoOutputOpenGLVAAPI::~VideoOutputOpenGLVAAPI()
     34{
     35    TearDown();
     36}
     37
     38void VideoOutputOpenGLVAAPI::TearDown(void)
     39{
     40    DeleteVAAPIContext();
     41}
     42
     43bool VideoOutputOpenGLVAAPI::InputChanged(const QSize &input_size, float aspect,
     44                              MythCodecID  av_codec_id, void *codec_private,
     45                              bool &aspect_only)
     46{
     47    VERBOSE(VB_PLAYBACK, LOC + QString("InputChanged(%1,%2,%3) %4->%5")
     48            .arg(input_size.width()).arg(input_size.height()).arg(aspect)
     49            .arg(toString(video_codec_id)).arg(toString(av_codec_id)));
     50
     51    if (!codec_is_vaapi(av_codec_id))
     52        return VideoOutputOpenGL::InputChanged(input_size, aspect, av_codec_id,
     53                                               codec_private, aspect_only);
     54                                                   
     55    QMutexLocker locker(&gl_context_lock);
     56    bool cid_changed = (video_codec_id != av_codec_id);
     57    bool res_changed = input_size  != window.GetActualVideoDim();
     58    bool asp_changed = aspect      != window.GetVideoAspect();
     59   
     60    if (!res_changed && !cid_changed)
     61    {
     62        if (asp_changed)
     63        {
     64            aspect_only = true;
     65            VideoAspectRatioChanged(aspect);
     66            MoveResize();
     67        }
     68        return true;
     69    }
     70
     71    TearDown();
     72    QRect disp = window.GetDisplayVisibleRect();
     73    if (Init(input_size.width(), input_size.height(),
     74             aspect, gl_parent_win, disp.left(),  disp.top(),
     75             disp.width(), disp.height(), av_codec_id, gl_embed_win))
     76    {
     77        BestDeint();
     78        return true;
     79    }
     80
     81    VERBOSE(VB_IMPORTANT, ERR + QString("Failed to re-initialise video output."));
     82    errorState = kError_Unknown;
     83
     84    return false;
     85}
     86
     87bool VideoOutputOpenGLVAAPI::Init(int width, int height, float aspect,
     88                                  WId winid, int winx, int winy, int winw,
     89                                  int winh, MythCodecID codec_id, WId embedid)
     90{
     91    bool ok = VideoOutputOpenGL::Init(width, height, aspect, winid, winx, winy,
     92                                      winw, winh, codec_id, embedid);
     93    if (ok && codec_is_vaapi(video_codec_id))
     94        return CreateVAAPIContext(QSize(width, height));
     95    return ok;
     96}
     97
     98bool VideoOutputOpenGLVAAPI::CreateVAAPIContext(QSize size)
     99{
     100    if (m_ctx)
     101        DeleteVAAPIContext();
     102
     103    OpenGLLocker ctx_lock(gl_context);
     104
     105    m_ctx = new VAAPIContext(video_codec_id);
     106    if (m_ctx && m_ctx->CreateDisplay(size) && m_ctx->CreateBuffers())
     107    {
     108        if (m_ctx->CreateGLXSurfaces(gl_videochain->GetInputTexture(),
     109                                     gl_videochain->GetTextureType()))
     110        {
     111            int num_buffers = m_ctx->GetNumBuffers();
     112            const QSize video_dim = window.GetActualVideoDim();
     113
     114            bool ok = true;
     115            for (int i = 0; i < num_buffers; i++)
     116            {
     117                ok &= vbuffers.CreateBuffer(video_dim.width(),
     118                                            video_dim.height(), i,
     119                                            m_ctx->GetVideoSurface(i),
     120                                            FMT_VAAPI);
     121            }
     122            return ok;
     123            return true;
     124        }
     125    }
     126
     127    VERBOSE(VB_IMPORTANT, ERR + QString("Failed to create VAAPI context."));
     128    errorState = kError_Unknown;
     129    return false;
     130}
     131
     132void VideoOutputOpenGLVAAPI::DeleteVAAPIContext(void)
     133{
     134    delete m_ctx;
     135    m_ctx = NULL;
     136}
     137
     138bool VideoOutputOpenGLVAAPI::CreateBuffers(void)
     139{
     140    if (codec_is_vaapi(video_codec_id))
     141    {
     142        vbuffers.Init(24, true, 2, 1, 4, 1);
     143        return true;
     144    }
     145    return VideoOutputOpenGL::CreateBuffers();
     146}
     147
     148void* VideoOutputOpenGLVAAPI::GetVAAPIContext(void)
     149{
     150    if (m_ctx)
     151        return &m_ctx->m_ctx;
     152    return NULL;
     153}
     154
     155uint8_t* VideoOutputOpenGLVAAPI::GetSurfaceIDPointer(void* buf)
     156{
     157    if (m_ctx)
     158        return m_ctx->GetSurfaceIDPointer(buf);
     159    return NULL;
     160}
     161
     162void VideoOutputOpenGLVAAPI::SetProfile(void)
     163{
     164    if (db_vdisp_profile)
     165        db_vdisp_profile->SetVideoRenderer("openglvaapi");
     166}
     167
     168bool VideoOutputOpenGLVAAPI::ApproveDeintFilter(const QString &filtername) const
     169{
     170    return filtername.contains("vaapi");
     171}
     172
     173bool VideoOutputOpenGLVAAPI::SetDeinterlacingEnabled(bool enable)
     174{
     175    m_deinterlacing = enable;
     176    SetupDeinterlace(enable);
     177    return m_deinterlacing;
     178}
     179
     180bool VideoOutputOpenGLVAAPI::SetupDeinterlace(bool i, const QString& ovrf)
     181{
     182    //m_deintfiltername = !db_vdisp_profile ? "" :
     183    //                     db_vdisp_profile->GetFilteredDeint(ovrf);
     184    m_deinterlacing = i;
     185    return m_deinterlacing;
     186}
     187
     188void VideoOutputOpenGLVAAPI::ProcessFrame(VideoFrame *frame, OSD *osd,
     189                                          FilterChain *filterList,
     190                                          const PIPMap &pipPlayers,
     191                                          FrameScanType scan)
     192{
     193    VideoOutputOpenGL::ProcessFrame(frame, osd, filterList, pipPlayers, scan);
     194
     195    if (codec_is_vaapi(video_codec_id) && m_ctx && gl_videochain && frame)
     196    {
     197        gl_context->makeCurrent();
     198        m_ctx->CopySurfaceToTexture(frame->buf, scan);
     199        gl_videochain->SetInputUpdated();
     200        gl_context->doneCurrent();
     201    }
     202}
     203
     204QStringList VideoOutputOpenGLVAAPI::GetAllowedRenderers(
     205    MythCodecID myth_codec_id, const QSize &video_dim)
     206{
     207    (void) video_dim;
     208    QStringList list;
     209    if ((codec_is_std(myth_codec_id) || (codec_is_vaapi(myth_codec_id))) &&
     210         !getenv("NO_VAAPI"))
     211    {
     212        list += "openglvaapi";
     213    }
     214    return list;
     215}
     216
     217MythCodecID VideoOutputOpenGLVAAPI::GetBestSupportedCodec(
     218    uint width,       uint height,
     219    uint stream_type, bool no_acceleration,
     220    PixelFormat &pix_fmt)
     221{
     222    QSize size(width, height);
     223    bool use_cpu = no_acceleration;
     224    VideoDisplayProfile vdp;
     225    vdp.SetInput(size);
     226    QString dec = vdp.GetDecoder();
     227
     228   PixelFormat fmt = PIX_FMT_YUV420P;
     229    MythCodecID test_cid = (MythCodecID)(kCodec_MPEG1_VAAPI + (stream_type - 1));
     230    if (codec_is_vaapi(test_cid))
     231        use_cpu |= !VAAPIContext::IsFormatAccelerated(size, test_cid, fmt);
     232    else
     233        use_cpu = true;
     234
     235    if ((dec != "vaapi") || getenv("NO_VAAPI") || use_cpu)
     236        return (MythCodecID)(kCodec_MPEG1 + (stream_type - 1));
     237
     238    pix_fmt = fmt;
     239    return test_cid;
     240}
  • new file mythtv/libs/libmythtv/videoout_openglvaapi.h

    diff --git a/mythtv/libs/libmythtv/videoout_openglvaapi.h b/mythtv/libs/libmythtv/videoout_openglvaapi.h
    new file mode 100644
    index 0000000..24488fe
    - +  
     1#ifndef VIDEOOUTPUTOPENGLVAAPI_H
     2#define VIDEOOUTPUTOPENGLVAAPI_H
     3
     4#include "videoout_opengl.h"
     5
     6class VAAPIContext;
     7
     8class VideoOutputOpenGLVAAPI : public VideoOutputOpenGL
     9{
     10  public:
     11    static void GetRenderOptions(render_opts &opts);
     12
     13    VideoOutputOpenGLVAAPI();
     14   ~VideoOutputOpenGLVAAPI();
     15
     16    bool  Init(int width, int height, float aspect, WId winid,
     17               int winx, int winy, int winw, int winh,
     18               MythCodecID codec_id, WId embedid = 0);
     19    bool  CreateVAAPIContext(QSize size);
     20    void  DeleteVAAPIContext(void);
     21    bool  CreateBuffers(void);
     22    void* GetVAAPIContext(void);
     23    uint8_t* GetSurfaceIDPointer(void* buf);
     24    void  SetProfile(void);
     25    void  TearDown(void);
     26    bool  InputChanged(const QSize &input_size, float aspect,
     27                       MythCodecID  av_codec_id, void *codec_private,
     28                       bool &aspect_only);
     29    void  ProcessFrame(VideoFrame *frame, OSD *osd,
     30                       FilterChain *filterList,
     31                       const PIPMap &pipPlayers,
     32                       FrameScanType scan);
     33    bool  ApproveDeintFilter(const QString& filtername) const;
     34    bool  SetDeinterlacingEnabled(bool enable);
     35    bool  SetupDeinterlace(bool i, const QString& ovrf="");
     36    void  InitPictureAttributes(void) { }
     37
     38    static QStringList GetAllowedRenderers(MythCodecID myth_codec_id,
     39                                           const QSize &video_dim);
     40    static MythCodecID GetBestSupportedCodec(uint width, uint height,
     41                                             uint stream_type,
     42                                             bool no_acceleration,
     43                                             PixelFormat &pix_fmt);
     44
     45  private:
     46    VAAPIContext *m_ctx;
     47};
     48#endif // VIDEOOUTPUTOPENGLVAAPI_H
     49