Merge pull request #5101 from FernetMenta/ffmpeg-threads
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / VDPAU.cpp
index 3bc7608..73c4fa4 100644 (file)
@@ -39,6 +39,7 @@
 
 using namespace VDPAU;
 #define NUM_RENDER_PICS 7
+#define NUM_CROP_PIX 3
 
 #define ARSIZE(x) (sizeof(x) / sizeof((x)[0]))
 
@@ -62,9 +63,7 @@ CDecoder::Desc decoder_profiles[] = {
 {"VC1_SIMPLE",   VDP_DECODER_PROFILE_VC1_SIMPLE},
 {"VC1_MAIN",     VDP_DECODER_PROFILE_VC1_MAIN},
 {"VC1_ADVANCED", VDP_DECODER_PROFILE_VC1_ADVANCED},
-#ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
 {"MPEG4_PART2_ASP", VDP_DECODER_PROFILE_MPEG4_PART2_ASP},
-#endif
 };
 const size_t decoder_profile_count = sizeof(decoder_profiles)/sizeof(CDecoder::Desc);
 
@@ -136,6 +135,7 @@ bool CVDPAUContext::EnsureContext(CVDPAUContext **ctx)
     {
       delete m_context;
       m_context = 0;
+      *ctx = NULL;
       return false;
     }
   }
@@ -511,14 +511,14 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned
 #endif
   if (!g_Windowing.IsExtSupported("GL_NV_vdpau_interop"))
   {
-    CLog::Log(LOGNOTICE, "VDPAU: required extension GL_NV_vdpau_interop not found");
+    CLog::Log(LOGNOTICE, "VDPAU::Open: required extension GL_NV_vdpau_interop not found");
     return false;
   }
 
   if(avctx->coded_width  == 0
   || avctx->coded_height == 0)
   {
-    CLog::Log(LOGWARNING,"(VDPAU) no width/height available, can't init");
+    CLog::Log(LOGWARNING,"VDPAU::Open: no width/height available, can't init");
     return false;
   }
   m_vdpauConfig.numRenderBuffers = surfaces;
@@ -537,45 +537,62 @@ bool CDecoder::Open(AVCodecContext* avctx, const enum PixelFormat fmt, unsigned
 
   {
     VdpDecoderProfile profile = 0;
-    if(avctx->codec_id == AV_CODEC_ID_H264)
-      profile = VDP_DECODER_PROFILE_H264_HIGH;
-#ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
-    else if(avctx->codec_id == AV_CODEC_ID_MPEG4)
-      profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
-#endif
+
+    // convert FFMPEG codec ID to VDPAU profile.
+    ReadFormatOf(avctx->codec_id, profile, m_vdpauConfig.vdpChromaType);
     if(profile)
     {
+      VdpStatus vdp_st;
+      VdpBool is_supported = false;
+      uint32_t max_level, max_macroblocks, max_width, max_height;
+
+      // query device capabilities to ensure that VDPAU can handle the requested codec
+      vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_query_caps(m_vdpauConfig.context->GetDevice(),
+               profile, &is_supported, &max_level, &max_macroblocks, &max_width, &max_height);
+
+      // test to make sure there is a possibility the codec will work
+      if (CheckStatus(vdp_st, __LINE__))
+      {
+        CLog::Log(LOGERROR, "VDPAU::Open: error %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
+        return false;
+      }
+
+      if (max_width < avctx->coded_width || max_height < avctx->coded_height)
+      {
+        CLog::Log(LOGWARNING,"VDPAU::Open: requested picture dimensions (%i, %i) exceed hardware capabilities ( %i, %i).",
+                             avctx->coded_width, avctx->coded_height, max_width, max_height);
+        return false;
+      }
+
       if (!CDVDCodecUtils::IsVP3CompatibleWidth(avctx->coded_width))
-        CLog::Log(LOGWARNING,"(VDPAU) width %i might not be supported because of hardware bug", avctx->width);
+        CLog::Log(LOGWARNING,"VDPAU::Open width %i might not be supported because of hardware bug", avctx->width);
    
-      /* attempt to create a decoder with this width/height, some sizes are not supported by hw */
-      VdpStatus vdp_st;
+      // attempt to create a decoder with this width/height, some sizes are not supported by hw
       vdp_st = m_vdpauConfig.context->GetProcs().vdp_decoder_create(m_vdpauConfig.context->GetDevice(), profile, avctx->coded_width, avctx->coded_height, 5, &m_vdpauConfig.vdpDecoder);
 
-      if(vdp_st != VDP_STATUS_OK)
+      if (CheckStatus(vdp_st, __LINE__))
       {
-        CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) checking for decoder support\n", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
+        CLog::Log(LOGERROR, "VDPAU::Open: error: %s(%d) checking for decoder support", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st);
         return false;
       }
 
       m_vdpauConfig.context->GetProcs().vdp_decoder_destroy(m_vdpauConfig.vdpDecoder);
       CheckStatus(vdp_st, __LINE__);
-    }
 
-    /* finally setup ffmpeg */
-    memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
-    m_hwContext.render = CDecoder::Render;
-    m_hwContext.bitstream_buffers_allocated = 0;
-    avctx->get_buffer      = CDecoder::FFGetBuffer;
-    avctx->reget_buffer    = CDecoder::FFGetBuffer;
-    avctx->release_buffer  = CDecoder::FFReleaseBuffer;
-    avctx->draw_horiz_band = CDecoder::FFDrawSlice;
-    avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
-    avctx->hwaccel_context = &m_hwContext;
-    avctx->thread_count    = 1;
-
-    g_Windowing.Register(this);
-    return true;
+      // finally setup ffmpeg
+      memset(&m_hwContext, 0, sizeof(AVVDPAUContext));
+      m_hwContext.render = CDecoder::Render;
+      m_hwContext.bitstream_buffers_allocated = 0;
+      avctx->get_buffer      = CDecoder::FFGetBuffer;
+      avctx->reget_buffer    = CDecoder::FFGetBuffer;
+      avctx->release_buffer  = CDecoder::FFReleaseBuffer;
+      avctx->draw_horiz_band = CDecoder::FFDrawSlice;
+      avctx->slice_flags=SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
+      avctx->hwaccel_context = &m_hwContext;
+
+      g_Windowing.Register(this);
+      return true;
+    }
   }
   return false;
 }
@@ -932,6 +949,7 @@ bool CDecoder::ConfigVDPAU(AVCodecContext* avctx, int ref_frames)
 
   m_inMsgEvent.Reset();
   m_vdpauConfigured = true;
+  m_ErrorCount = 0;
   return true;
 }
 
@@ -1062,7 +1080,11 @@ void CDecoder::FFDrawSlice(struct AVCodecContext *s,
                                    (VdpPictureInfo const *)&(vdp->m_hwContext.info),
                                    vdp->m_hwContext.bitstream_buffers_used,
                                    vdp->m_hwContext.bitstream_buffers);
-  vdp->CheckStatus(vdp_st, __LINE__);
+  if (vdp->CheckStatus(vdp_st, __LINE__))
+    vdp->m_DecoderError = true;
+  else
+    vdp->m_DecoderError = false;
+
   uint64_t diff = CurrentHostCounter() - startTime;
   if (diff*1000/CurrentHostFrequency() > 30)
     CLog::Log(LOGDEBUG, "CVDPAU::DrawSlice - VdpDecoderRender long decoding: %d ms, dec: %d, proc: %d, rend: %d", (int)((diff*1000)/CurrentHostFrequency()), decoded, processed, rend);
@@ -1077,6 +1099,9 @@ int CDecoder::Decode(AVCodecContext *avctx, AVFrame *pFrame)
 
   CSingleLock lock(m_DecoderSection);
 
+  if (m_DecoderError && pFrame)
+    return VC_ERROR;
+
   if (!m_vdpauConfigured)
     return VC_ERROR;
 
@@ -1248,6 +1273,8 @@ bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
   {
     CLog::Log(LOGERROR, " (VDPAU) Error: %s(%d) at %s:%d\n", m_vdpauConfig.context->GetProcs().vdp_get_error_string(vdp_st), vdp_st, __FILE__, line);
 
+    m_ErrorCount++;
+
     if(m_DisplayState == VDPAU_OPEN)
     {
       if (vdp_st == VDP_STATUS_DISPLAY_PREEMPTED)
@@ -1255,12 +1282,13 @@ bool CDecoder::CheckStatus(VdpStatus vdp_st, int line)
         m_DisplayEvent.Reset();
         m_DisplayState = VDPAU_LOST;
       }
-      else
+      else if (m_ErrorCount > 2)
         m_DisplayState = VDPAU_ERROR;
     }
 
     return true;
   }
+  m_ErrorCount = 0;
   return false;
 }
 
@@ -2385,6 +2413,7 @@ void CMixer::InitCycle()
   }
   m_mixerstep = 0;
 
+  m_processPicture.crop = false;
   if (m_mixerInput[1].DVDPic.format == RENDER_FMT_VDPAU)
   {
     m_processPicture.outputSurface = m_outputSurfaces.front();
@@ -2393,8 +2422,8 @@ void CMixer::InitCycle()
     if (m_SeenInterlaceFlag)
     {
       double ratio = (double)m_mixerInput[1].DVDPic.iDisplayHeight / m_mixerInput[1].DVDPic.iHeight;
-      m_mixerInput[1].DVDPic.iHeight -= 6;
-      m_mixerInput[1].DVDPic.iDisplayHeight = lrint(ratio*m_mixerInput[1].DVDPic.iHeight);
+      m_mixerInput[1].DVDPic.iDisplayHeight = lrint(ratio*(m_mixerInput[1].DVDPic.iHeight-NUM_CROP_PIX*2));
+      m_processPicture.crop = true;
     }
   }
   else
@@ -2938,6 +2967,11 @@ bool COutput::Init()
 bool COutput::Uninit()
 {
   m_mixer.Dispose();
+  glFlush();
+  while(ProcessSyncPicture())
+  {
+    Sleep(10);
+  }
   GLUnmapSurfaces();
   ReleaseBufferPool();
   DestroyGlxContext();
@@ -3063,7 +3097,7 @@ CVdpauRenderPicture* COutput::ProcessMixerPicture()
       retPic->texWidth = m_config.outWidth;
       retPic->texHeight = m_config.outHeight;
       retPic->crop.x1 = 0;
-      retPic->crop.y1 = (m_config.outHeight - retPic->DVDPic.iHeight) / 2;
+      retPic->crop.y1 = procPic.crop ? NUM_CROP_PIX : 0;
       retPic->crop.x2 = m_config.outWidth;
       retPic->crop.y2 = m_config.outHeight - retPic->crop.y1;
     }