Example #1
0
bool Session::initialize()
{
  // Get URN's wich are supported by this addon
  if (!license_type_.empty())
  {
    GetSupportedDecrypterURN(dashtree_.adp_pssh_);
    xbmc->Log(ADDON::LOG_DEBUG, "Supported URN: %s", dashtree_.adp_pssh_.first.c_str());
  }

  // Open mpd file
  size_t paramPos = mpdFileURL_.find('?');
  dashtree_.base_url_ = (paramPos == std::string::npos)? mpdFileURL_:mpdFileURL_.substr(0, paramPos);

  paramPos = dashtree_.base_url_.find_last_of('/', dashtree_.base_url_.length());
  if (paramPos == std::string::npos)
  {
    xbmc->Log(ADDON::LOG_ERROR, "Invalid mpdURL: / expected (%s)", mpdFileURL_.c_str());
    return false;
  }
  dashtree_.base_url_.resize(paramPos + 1);

  if (!dashtree_.open(mpdFileURL_.c_str()) || dashtree_.empty())
  {
    xbmc->Log(ADDON::LOG_ERROR, "Could not open / parse mpdURL (%s)", mpdFileURL_.c_str());
    return false;
  }
  xbmc->Log(ADDON::LOG_INFO, "Successfully parsed .mpd file. Download speed: %0.4f Bytes/s", dashtree_.download_speed_);

  if (dashtree_.encryptionState_ == dash::DASHTree::ENCRYTIONSTATE_ENCRYPTED)
  {
    xbmc->Log(ADDON::LOG_ERROR, "Unable to handle decryption. Unsupported!");
    return false;
  }

  uint32_t min_bandwidth(0), max_bandwidth(0);
  {
    int buf;
    xbmc->GetSetting("MINBANDWIDTH", (char*)&buf); min_bandwidth = buf;
    xbmc->GetSetting("MAXBANDWIDTH", (char*)&buf); max_bandwidth = buf;
  }

  // create SESSION::STREAM objects. One for each AdaptationSet
  unsigned int i(0);
  const dash::DASHTree::AdaptationSet *adp;

  for (std::vector<STREAM*>::iterator b(streams_.begin()), e(streams_.end()); b != e; ++b)
    SAFE_DELETE(*b);
  streams_.clear();

  while ((adp = dashtree_.GetAdaptationSet(i++)))
  {
    streams_.push_back(new STREAM(dashtree_, adp->type_));
    STREAM &stream(*streams_.back());
    stream.stream_.prepare_stream(adp, width_, height_, min_bandwidth, max_bandwidth);

    switch (adp->type_)
    {
    case dash::DASHTree::VIDEO:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_VIDEO;
      break;
    case dash::DASHTree::AUDIO:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_AUDIO;
      break;
    case dash::DASHTree::TEXT:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_TELETEXT;
      break;
    default:
      break;
    }
    stream.info_.m_pID = i;
    strcpy(stream.info_.m_language, adp->language_.c_str());

    UpdateStream(stream);

  }

  // Try to initialize an SingleSampleDecryptor
#if 1
  if (dashtree_.encryptionState_)
  {
    if (dashtree_.protection_key_.size()!=16 || license_data_.empty())
      return false;

    uint8_t ld[1024];
    unsigned int ld_size(1024);
    b64_decode(license_data_.c_str(), license_data_.size(), ld, ld_size);

    const uint8_t *uuid((uint8_t*)strstr((const char*)ld, "{UUID}"));
    unsigned int license_size = uuid ? ld_size + 36 -6: ld_size;

    //Build up proto header
    AP4_DataBuffer init_data;
    init_data.Reserve(512);
    uint8_t *protoptr(init_data.UseData());
    *protoptr++ = 18; //id=16>>3=2, type=2(flexlen)
    *protoptr++ = 16; //length of key
    memcpy(protoptr, dashtree_.protection_key_.data(), 16);
    protoptr += 16;
    //-----------
    *protoptr++ = 34;//id=32>>3=4, type=2(flexlen)
    do {
      *protoptr++ = static_cast<uint8_t>(license_size & 127);
      license_size >>= 7;
      if (license_size)
        *(protoptr - 1) |= 128;
      else
        break;
    } while (1);
    if (uuid)
    {
      static const uint8_t hexmap[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
      memcpy(protoptr, ld, uuid - ld);
      protoptr += uuid - ld;
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[3]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[3]) & 15];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[2]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[2]) & 15];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[1]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[1]) & 15];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[0]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[0]) & 15];
      *protoptr++ = '-';
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[5]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[5]) & 15];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[4]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[4]) & 15];
      *protoptr++ = '-';
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[7]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[7]) & 15];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[6]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[6]) & 15];
      *protoptr++ = '-';
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[8]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[8]) & 15];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[9]) >> 4];
      *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[9]) & 15];
      *protoptr++ = '-';
      for (i = 10; i < 16; ++i)
      {
        *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[i]) >> 4];
        *protoptr++ = hexmap[(uint8_t)(dashtree_.protection_key_.data()[i]) & 15];
      }
      unsigned int sizeleft = ld_size - ((uuid - ld) + 6);
      memcpy(protoptr, uuid+6, sizeleft);
      protoptr += sizeleft;
    }
    else
    {
      memcpy(protoptr, ld, ld_size);
      protoptr += ld_size;
    }
    init_data.SetDataSize(protoptr - init_data.UseData());
    return (single_sample_decryptor_ = CreateSingleSampleDecrypter(init_data))!=0;
  }
Example #2
0
bool Session::initialize()
{
  // Get URN's wich are supported by this addon
  if (!license_type_.empty())
    GetSupportedDecrypterURN(dashtree_.adp_pssh_);

  // Open mpd file
  const char* delim(strrchr(mpdFileURL_.c_str(), '/'));
  if (!delim)
  {
    xbmc->Log(ADDON::LOG_ERROR, "Invalid mpdURL: / expected (%s)", mpdFileURL_.c_str());
    return false;
  }
  dashtree_.base_url_ = std::string(mpdFileURL_.c_str(), (delim - mpdFileURL_.c_str()) + 1);

  if (!dashtree_.open(mpdFileURL_.c_str()) || dashtree_.empty())
  {
    xbmc->Log(ADDON::LOG_ERROR, "Could not open / parse mpdURL (%s)", mpdFileURL_.c_str());
    return false;
  }
  xbmc->Log(ADDON::LOG_INFO, "Successfully parsed .mpd file. Download speed: %0.4f Bytes/s", dashtree_.download_speed_);

  if (dashtree_.encryptionState_ == dash::DASHTree::ENCRYTIONSTATE_ENCRYPTED)
  {
    xbmc->Log(ADDON::LOG_ERROR, "Unable to handle decryption. Unsupported!");
    return false;
  }

  uint32_t min_bandwidth(0), max_bandwidth(0);
  {
    int buf;
    xbmc->GetSetting("MINBANDWIDTH", (char*)&buf); min_bandwidth = buf;
    xbmc->GetSetting("MAXBANDWIDTH", (char*)&buf); max_bandwidth = buf;
  }

  // create SESSION::STREAM objects. One for each AdaptationSet
  unsigned int i(0);
  const dash::DASHTree::AdaptationSet *adp;

  for (std::vector<STREAM*>::iterator b(streams_.begin()), e(streams_.end()); b != e; ++b)
    SAFE_DELETE(*b);
  streams_.clear();

  while ((adp = dashtree_.GetAdaptationSet(i++)))
  {
    streams_.push_back(new STREAM(dashtree_, adp->type_));
    STREAM &stream(*streams_.back());
    stream.stream_.prepare_stream(adp, width_, height_, min_bandwidth, max_bandwidth);

    const dash::DASHTree::Representation *rep(stream.stream_.getRepresentation());

    stream.info_.m_Width = rep->width_;
    stream.info_.m_Height = rep->height_;
    stream.info_.m_Aspect = rep->aspect_;
    stream.info_.m_pID = i;
    switch (adp->type_)
    {
    case dash::DASHTree::VIDEO:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_VIDEO;
      break;
    case dash::DASHTree::AUDIO:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_AUDIO;
      break;
    case dash::DASHTree::TEXT:
      stream.info_.m_streamType = INPUTSTREAM_INFO::TYPE_TELETEXT;
      break;
    default:
      break;
    }

    // we currently use only the first track!
    std::string::size_type pos = rep->codecs_.find(",");
    if (pos == std::string::npos)
      pos = rep->codecs_.size();

    strncpy(stream.info_.m_codecInternalName, rep->codecs_.c_str(), pos);
    stream.info_.m_codecInternalName[pos] = 0;

    if (rep->codecs_.find("mp4a") == 0)
      strcpy(stream.info_.m_codecName, "aac");
    else if (rep->codecs_.find("ec-3") == 0 || rep->codecs_.find("ac-3") == 0)
      strcpy(stream.info_.m_codecName, "eac3");
    else if (rep->codecs_.find("avc") == 0)
      strcpy(stream.info_.m_codecName, "h264");
    else if (rep->codecs_.find("hevc") == 0)
      strcpy(stream.info_.m_codecName, "hevc");

    stream.info_.m_FpsRate = rep->fpsRate_;
    stream.info_.m_FpsScale = rep->fpsScale_;
    stream.info_.m_SampleRate = rep->samplingRate_;
    stream.info_.m_Channels = rep->channelCount_;
    stream.info_.m_Bandwidth = rep->bandwidth_;
    strcpy(stream.info_.m_language, adp->language_.c_str());
  }
  
  // Try to initialize an SingleSampleDecryptor
  if (dashtree_.encryptionState_)
  {
    AP4_DataBuffer init_data;

    if (dashtree_.adp_pssh_.second == "FILE")
    {
      std::string strkey(dashtree_.adp_pssh_.first.substr(9));
      while (size_t pos = strkey.find('-') != std::string::npos)
        strkey.erase(pos, 1);
      if (strkey.size() != 32)
      {
        xbmc->Log(ADDON::LOG_ERROR, "Key system mismatch (%s)!", dashtree_.adp_pssh_.first.c_str());
        return false;
      }

      unsigned char key_system[16];
      AP4_ParseHex(strkey.c_str(), key_system, 16);

      Session::STREAM *stream(streams_[0]);

      stream->enabled = true;
      stream->stream_.start_stream(0);
      stream->stream_.select_stream(true);

      stream->input_ = new AP4_DASHStream(&stream->stream_);
      stream->input_file_ = new AP4_File(*stream->input_, AP4_DefaultAtomFactory::Instance, true);
      AP4_Movie* movie = stream->input_file_->GetMovie();
      if (movie == NULL)
      {
        xbmc->Log(ADDON::LOG_ERROR, "No MOOV in stream!");
        stream->disable();
        return false;
      }
      AP4_Array<AP4_PsshAtom*>& pssh = movie->GetPsshAtoms();

      for (unsigned int i = 0; !init_data.GetDataSize() && i < pssh.ItemCount(); i++)
      {
        if (memcmp(pssh[i]->GetSystemId(), key_system, 16) == 0)
          init_data.AppendData(pssh[i]->GetData().GetData(), pssh[i]->GetData().GetDataSize());
      }

      if (!init_data.GetDataSize())
      {
        xbmc->Log(ADDON::LOG_ERROR, "Could not extract license from video stream (PSSH not found)");
        stream->disable();
        return false;
      }
      stream->disable();
    }
    else
    {
      init_data.SetBufferSize(1024);
      unsigned int init_data_size(1024);
      b64_decode(dashtree_.pssh_.second.data(), dashtree_.pssh_.second.size(), init_data.UseData(), init_data_size);
      init_data.SetDataSize(init_data_size);
    }
    return (single_sample_decryptor_ = CreateSingleSampleDecrypter(init_data))!=0;
  }
  return true;
}