Пример #1
0
bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
{
  AVCodec* pCodec;

  if(!m_dllAvUtil.Load()
  || !m_dllAvCodec.Load()
  || !m_dllSwScale.Load()
  || !m_dllAvFilter.Load()
  ) return false;

  m_dllAvCodec.avcodec_register_all();
  m_dllAvFilter.avfilter_register_all();

  m_bSoftware     = hints.software;
  m_pCodecContext = m_dllAvCodec.avcodec_alloc_context();

  pCodec = NULL;

  if (hints.codec == CODEC_ID_H264)
  {
    switch(hints.profile)
    {
      case FF_PROFILE_H264_HIGH_10:
      case FF_PROFILE_H264_HIGH_10_INTRA:
      case FF_PROFILE_H264_HIGH_422:
      case FF_PROFILE_H264_HIGH_422_INTRA:
      case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
      case FF_PROFILE_H264_HIGH_444_INTRA:
      case FF_PROFILE_H264_CAVLC_444:
      m_bSoftware = true;
      break;
    }
  }

#ifdef HAVE_LIBVDPAU
  if(g_guiSettings.GetBool("videoplayer.usevdpau") && !m_bSoftware)
  {
    while((pCodec = m_dllAvCodec.av_codec_next(pCodec)))
    {
      if(pCodec->id == hints.codec
      && pCodec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
      {
        if ((pCodec->id == CODEC_ID_MPEG4) && !g_advancedSettings.m_videoAllowMpeg4VDPAU)
          continue;

        CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Creating VDPAU(%ix%i, %d)",hints.width, hints.height, hints.codec);
        VDPAU::CDecoder* vdp = new VDPAU::CDecoder();
        m_pCodecContext->codec_id = hints.codec;
        m_pCodecContext->width    = hints.width;
        m_pCodecContext->height   = hints.height;
        m_pCodecContext->coded_width   = hints.width;
        m_pCodecContext->coded_height  = hints.height;

        // check number of surfaces used in renderer
        unsigned int surfaces = 0;
        for(CDVDCodecOptions::iterator it = options.begin(); it != options.end(); it++)
        {
          if (it->m_name == "surfaces")
          {
            surfaces = std::atoi(it->m_value.c_str());
            break;
          }
        }

        if(vdp->Open(m_pCodecContext, pCodec->pix_fmts ? pCodec->pix_fmts[0] : PIX_FMT_NONE, surfaces))
        {
          m_pHardware = vdp;
          m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set
          break;
        }
        m_pCodecContext->codec_id = CODEC_ID_NONE; // ffmpeg will complain if this has been set
        CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Failed to get VDPAU device");
        vdp->Release();
      }
    }
  }
#endif

  if(pCodec == NULL)
    pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);

  if(pCodec == NULL)
  {
    CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
    return false;
  }

  CLog::Log(LOGNOTICE,"CDVDVideoCodecFFmpeg::Open() Using codec: %s",pCodec->long_name ? pCodec->long_name : pCodec->name);

  m_pCodecContext->opaque = (void*)this;
  m_pCodecContext->debug_mv = 0;
  m_pCodecContext->debug = 0;
  m_pCodecContext->workaround_bugs = FF_BUG_AUTODETECT;
  m_pCodecContext->get_format = GetFormat;
  m_pCodecContext->codec_tag = hints.codec_tag;

#if defined(__APPLE__) && defined(__arm__)
  // ffmpeg with enabled neon will crash and burn if this is enabled
  m_pCodecContext->flags &= CODEC_FLAG_EMU_EDGE;
#else
  if (pCodec->id != CODEC_ID_H264 && pCodec->capabilities & CODEC_CAP_DR1
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,69,0)
      && pCodec->id != CODEC_ID_VP8
#endif
     )
    m_pCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
#endif

  // if we don't do this, then some codecs seem to fail.
  m_pCodecContext->coded_height = hints.height;
  m_pCodecContext->coded_width = hints.width;

  if( hints.extradata && hints.extrasize > 0 )
  {
    m_pCodecContext->extradata_size = hints.extrasize;
    m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
    memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
  }

  // set acceleration
  m_pCodecContext->dsp_mask = 0;//FF_MM_FORCE | FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE;

  // advanced setting override for skip loop filter (see avcodec.h for valid options)
  // TODO: allow per video setting?
  if (g_advancedSettings.m_iSkipLoopFilter != 0)
  {
    m_pCodecContext->skip_loop_filter = (AVDiscard)g_advancedSettings.m_iSkipLoopFilter;
  }

  // set any special options
  for(CDVDCodecOptions::iterator it = options.begin(); it != options.end(); it++)
  {
    if (it->m_name == "surfaces")
      m_uSurfacesCount = std::atoi(it->m_value.c_str());
    else
      m_dllAvUtil.av_set_string3(m_pCodecContext, it->m_name.c_str(), it->m_value.c_str(), 0, NULL);
  }

  int num_threads = std::min(8 /*MAX_THREADS*/, g_cpuInfo.getCPUCount());
  if( num_threads > 1 && !hints.software && m_pHardware == NULL // thumbnail extraction fails when run threaded
  && ( pCodec->id == CODEC_ID_H264
    || pCodec->id == CODEC_ID_MPEG4 ))
    m_dllAvCodec.avcodec_thread_init(m_pCodecContext, num_threads);

  if (m_dllAvCodec.avcodec_open(m_pCodecContext, pCodec) < 0)
  {
    CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to open codec");
    return false;
  }

  m_pFrame = m_dllAvCodec.avcodec_alloc_frame();
  if (!m_pFrame) return false;

  if(pCodec->name)
    m_name = CStdString("ff-") + pCodec->name;
  else
    m_name = "ffmpeg";

  if(m_pHardware)
    m_name += "-" + m_pHardware->Name();

  return true;
}
Пример #2
0
CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigned int surfaces)
{
  CDVDVideoCodec* pCodec = NULL;
  CDVDCodecOptions options;

  //when support for a hardware decoder is not compiled in
  //only print it if it's actually available on the platform
  CStdString hwSupport;
#if defined(HAVE_LIBVDADECODER) && defined(__APPLE__)
  hwSupport += "VDADecoder:yes ";
#elif defined(__APPLE__)
  hwSupport += "VDADecoder:no ";
#endif
#if defined(HAVE_VIDEOTOOLBOXDECODER) && defined(__APPLE__)
  hwSupport += "VideoToolBoxDecoder:yes ";
#elif defined(__APPLE__)
  hwSupport += "VideoToolBoxDecoder:no ";
#endif
#ifdef HAVE_LIBCRYSTALHD
  hwSupport += "CrystalHD:yes ";
#else
  hwSupport += "CrystalHD:no ";
#endif
#if defined(HAVE_LIBOPENMAX) && defined(_LINUX)
  hwSupport += "OpenMax:yes ";
#elif defined(_LINUX)
  hwSupport += "OpenMax:no ";
#endif
#if defined(HAVE_LIBVDPAU) && defined(_LINUX)
  hwSupport += "VDPAU:yes ";
#elif defined(_LINUX) && !defined(__APPLE__)
  hwSupport += "VDPAU:no ";
#endif
#if defined(_WIN32) && defined(HAS_DX)
  hwSupport += "DXVA:yes ";
#elif defined(_WIN32)
  hwSupport += "DXVA:no ";
#endif
#if defined(HAVE_LIBVA) && defined(_LINUX)
  hwSupport += "VAAPI:yes ";
#elif defined(_LINUX) && !defined(__APPLE__)
  hwSupport += "VAAPI:no ";
#endif
#if defined(HAVE_LIBGSTREAMER)
  hwSupport += "GStreamer:yes ";
#else
  hwSupport += "GStreamer:no ";
#endif

  CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());

#if defined(HAVE_LIBGSTREAMER)
  if (!hint.software)
  {
      CLog::Log(LOGINFO, "Trying GStreamer Video Decoder...");
      if ( (pCodec = OpenCodec(new CDVDVideoCodecGStreamer(), hint, options)) ) return pCodec;
  }
#endif

  // dvd's have weird still-frames in it, which is not fully supported in ffmpeg
  if(hint.stills && (hint.codec == CODEC_ID_MPEG2VIDEO || hint.codec == CODEC_ID_MPEG1VIDEO))
  {
    if( (pCodec = OpenCodec(new CDVDVideoCodecLibMpeg2(), hint, options)) ) return pCodec;
  }
#if defined(HAVE_LIBVDADECODER)
  if (!hint.software && g_guiSettings.GetBool("videoplayer.usevda"))
  {
    if (g_sysinfo.HasVDADecoder())
    {
      if (hint.codec == CODEC_ID_H264 && !hint.ptsinvalid)
      {
        CLog::Log(LOGINFO, "Trying Apple VDA Decoder...");
        if ( (pCodec = OpenCodec(new CDVDVideoCodecVDA(), hint, options)) ) return pCodec;
      }
    }
  }
#endif

#if defined(HAVE_VIDEOTOOLBOXDECODER)
  if (!hint.software && g_guiSettings.GetBool("videoplayer.usevideotoolbox"))
  {
    if (g_sysinfo.HasVideoToolBoxDecoder())
    {
      switch(hint.codec)
      {
        case CODEC_ID_H264:
          if (hint.codec == CODEC_ID_H264 && hint.ptsinvalid)
            break;
          CLog::Log(LOGINFO, "Apple VideoToolBox Decoder...");
          if ( (pCodec = OpenCodec(new CDVDVideoCodecVideoToolBox(), hint, options)) ) return pCodec;
        break;
        default:
        break;
      }
    }
  }
#endif

#if defined(HAVE_LIBCRYSTALHD)
  if (!hint.software && g_guiSettings.GetBool("videoplayer.usechd"))
  {
    if (CCrystalHD::GetInstance()->DevicePresent())
    {
      switch(hint.codec)
      {
        case CODEC_ID_VC1:
        case CODEC_ID_WMV3:
        case CODEC_ID_H264:
        case CODEC_ID_MPEG2VIDEO:
          if (hint.codec == CODEC_ID_H264 && hint.ptsinvalid)
            break;
          if (hint.codec == CODEC_ID_MPEG2VIDEO && hint.width <= 720)
            break;
          CLog::Log(LOGINFO, "Trying Broadcom Crystal HD Decoder...");
          if ( (pCodec = OpenCodec(new CDVDVideoCodecCrystalHD(), hint, options)) ) return pCodec;
        break;
        default:
        break;
      }
    }
  }
#endif

#if defined(HAVE_LIBOPENMAX)
  if (g_guiSettings.GetBool("videoplayer.useomx") && !hint.software )
  {
      if (hint.codec == CODEC_ID_H264 || hint.codec == CODEC_ID_MPEG2VIDEO || hint.codec == CODEC_ID_VC1)
    {
      CLog::Log(LOGINFO, "Trying OpenMax Decoder...");
      if ( (pCodec = OpenCodec(new CDVDVideoCodecOpenMax(), hint, options)) ) return pCodec;
    }
  }
#endif

  // try to decide if we want to try halfres decoding
#if !defined(_LINUX) && !defined(_WIN32)
  float pixelrate = (float)hint.width*hint.height*hint.fpsrate/hint.fpsscale;
  if( pixelrate > 1400.0f*720.0f*30.0f )
  {
    CLog::Log(LOGINFO, "CDVDFactoryCodec - High video resolution detected %dx%d, trying half resolution decoding ", hint.width, hint.height);
    options.push_back(CDVDCodecOption("lowres","1"));
  }
#endif

  CStdString value;
  value.Format("%d", surfaces);
  options.push_back(CDVDCodecOption("surfaces", value));
  if( (pCodec = OpenCodec(new CDVDVideoCodecFFmpeg(), hint, options)) ) return pCodec;

  return NULL;
}
Пример #3
0
bool CDVDVideoCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
{
  AVCodec* pCodec;

  if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwScale.Load()) return false;
  
  m_dllSwScale.sws_rgb2rgb_init(SWS_CPU_CAPS_MMX2);

  m_pCodecContext = m_dllAvCodec.avcodec_alloc_context();
  // avcodec_get_context_defaults(m_pCodecContext);

  pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);
  if (!pCodec)
  {
    CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
    return false;
  }

  m_pCodecContext->opaque = (void*)this;
  m_pCodecContext->get_buffer = my_get_buffer;
  m_pCodecContext->release_buffer = my_release_buffer;

  m_pCodecContext->debug_mv = 0;
  m_pCodecContext->debug = 0;
  m_pCodecContext->workaround_bugs = FF_BUG_AUTODETECT;
  /* some decoders (eg. dv) do not know the pix_fmt until they decode the
   * first frame. setting to -1 avoid enabling DR1 for them.
   */
  m_pCodecContext->pix_fmt = (PixelFormat) - 1;  

  if (pCodec->id != CODEC_ID_H264 && pCodec->capabilities & CODEC_CAP_DR1)
    m_pCodecContext->flags |= CODEC_FLAG_EMU_EDGE;

  // Hack to correct wrong frame rates that seem to be generated by some
  // codecs
  if (m_pCodecContext->time_base.den > 1000 && m_pCodecContext->time_base.num == 1)
    m_pCodecContext->time_base.num = 1000;

  // if we don't do this, then some codecs seem to fail.
  m_pCodecContext->coded_height = hints.height;
  m_pCodecContext->coded_width = hints.width;

  if( hints.extradata && hints.extrasize > 0 )
  {
    m_pCodecContext->extradata_size = hints.extrasize;
    m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
    memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
  }

  // set acceleration
  m_pCodecContext->dsp_mask = FF_MM_FORCE | FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE;
  
  // This doesn't seem to help with the H.264 MT patch. "Basically, the code decodes 
  // up to 128 macroblocks in one thread while doing prediction+idct+deblock of the 
  // previously decoded 128 blocks in another thread." This could explain the lack of
  // much difference.
  //
  //m_pCodecContext->skip_loop_filter = AVDISCARD_BIDIR;

  // set any special options
  for(CDVDCodecOptions::iterator it = options.begin(); it != options.end(); it++)
  {
    m_dllAvCodec.av_set_string(m_pCodecContext, it->m_name.c_str(), it->m_value.c_str());
  }

#ifdef _LINUX
  int num_threads = std::min(8 /*MAX_THREADS*/, g_cpuInfo.getCPUCount());
  if(num_threads > 1 && (pCodec->id == CODEC_ID_H264 || pCodec->id == CODEC_ID_MPEG4 || pCodec->id == CODEC_ID_MPEG2VIDEO))
    m_dllAvCodec.avcodec_thread_init(m_pCodecContext, num_threads);
#endif

  if (m_dllAvCodec.avcodec_open(m_pCodecContext, pCodec) < 0)
  {
    CLog::Log(LOGDEBUG,"CDVDVideoCodecFFmpeg::Open() Unable to open codec");
    return false;
  }

  m_pFrame = m_dllAvCodec.avcodec_alloc_frame();
  if (!m_pFrame) return false;

  return true;
}