bool
CompositableHost::AddMaskEffect(EffectChain& aEffects,
                                const gfx::Matrix4x4& aTransform,
                                bool aIs3D)
{
  RefPtr<TextureSource> source;
  RefPtr<DeprecatedTextureHost> oldHost = GetDeprecatedTextureHost();
  if (oldHost) {
    oldHost->Lock();
    source = oldHost;
  } else {
    RefPtr<TextureHost> host = GetTextureHost();
    if (host) {
      host->Lock();
      source = host->GetTextureSources();
    }
  }

  if (!source) {
    NS_WARNING("Using compositable with no texture host as mask layer");
    return false;
  }

  RefPtr<EffectMask> effect = new EffectMask(source,
                                             source->GetSize(),
                                             aTransform);
  effect->mIs3D = aIs3D;
  aEffects.mSecondaryEffects[EFFECT_MASK] = effect;
  return true;
}
bool
CompositableHost::AddMaskEffect(EffectChain& aEffects,
                                const gfx::Matrix4x4& aTransform,
                                bool aIs3D)
{
  CompositableTextureSourceRef source;
  RefPtr<TextureHost> host = GetAsTextureHost();

  if (!host) {
    NS_WARNING("Using compositable with no valid TextureHost as mask");
    return false;
  }

  if (!host->Lock()) {
    NS_WARNING("Failed to lock the mask texture");
    return false;
  }

  if (!host->BindTextureSource(source)) {
    NS_WARNING("The TextureHost was successfully locked but can't provide a TextureSource");
    host->Unlock();
    return false;
  }
  MOZ_ASSERT(source);

  RefPtr<EffectMask> effect = new EffectMask(source,
                                             source->GetSize(),
                                             aTransform);
  effect->mIs3D = aIs3D;
  aEffects.mSecondaryEffects[EffectTypes::MASK] = effect;
  return true;
}
Example #3
0
// Same as above, for YCbCr surfaces
void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {
  client->Lock(OpenMode::OPEN_READ_WRITE);
  UpdateYCbCrTextureClient(client, ycbcrData);
  client->Unlock();

  // client serialization
  SurfaceDescriptor descriptor;
  ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor));

  ASSERT_EQ(descriptor.type(), SurfaceDescriptor::TSurfaceDescriptorBuffer);
  auto bufferDesc = descriptor.get_SurfaceDescriptorBuffer();
  ASSERT_EQ(bufferDesc.desc().type(), BufferDescriptor::TYCbCrDescriptor);
  auto ycbcrDesc = bufferDesc.desc().get_YCbCrDescriptor();
  ASSERT_EQ(ycbcrDesc.ySize(), ycbcrData.mYSize);
  ASSERT_EQ(ycbcrDesc.cbCrSize(), ycbcrData.mCbCrSize);
  ASSERT_EQ(ycbcrDesc.stereoMode(), ycbcrData.mStereoMode);

  // host deserialization
  RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr,
                                                                        client->GetFlags());

  RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get());

  ASSERT_TRUE(host.get() != nullptr);
  ASSERT_EQ(host->GetFlags(), client->GetFlags());

  // host read

  if (host->Lock()) {
    // This will work iff the compositor is not BasicCompositor
    ASSERT_EQ(host->GetFormat(), mozilla::gfx::SurfaceFormat::YUV);
    host->Unlock();
  }
}
SourceSurfaceCGIOSurfaceContext::SourceSurfaceCGIOSurfaceContext(DrawTargetCG *aDrawTarget)
{
#if(1)
  fprintf(stderr, "SourceSurfaceCGIOSurfaceContext not supported on 10.4\n");
#else
  CGContextRef cg = (CGContextRef)aDrawTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT_ACCELERATED);

  RefPtr<MacIOSurface> surf = MacIOSurface::IOSurfaceContextGetSurface(cg);

  mFormat = aDrawTarget->GetFormat();
  mSize.width = surf->GetWidth();
  mSize.height = surf->GetHeight();

  // TODO use CreateImageFromIOSurfaceContext instead of reading back the surface
  //mImage = MacIOSurface::CreateImageFromIOSurfaceContext(cg);
  mImage = nullptr;

  aDrawTarget->Flush();
  surf->Lock();
  size_t bytesPerRow = surf->GetBytesPerRow();
  size_t ioHeight = surf->GetHeight();
  void* ioData = surf->GetBaseAddress();
  // XXX If the width is much less then the stride maybe
  //     we should repack the image?
  mData = malloc(ioHeight*bytesPerRow);
  memcpy(mData, ioData, ioHeight*(bytesPerRow));
  mStride = bytesPerRow;
  surf->Unlock();
#endif
}
Example #5
0
// Same as above, for YCbCr surfaces
void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) {

  // client allocation
  ASSERT_TRUE(client->AsTextureClientYCbCr() != nullptr);
  TextureClientYCbCr* texture = client->AsTextureClientYCbCr();
  texture->AllocateForYCbCr(ToIntSize(ycbcrData.mYSize),
                            ToIntSize(ycbcrData.mCbCrSize),
                            ycbcrData.mStereoMode);
  ASSERT_TRUE(client->IsAllocated());

  // client painting
  texture->UpdateYCbCr(ycbcrData);

  ASSERT_TRUE(client->Lock(OPEN_READ_ONLY));
  client->Unlock();

  // client serialization
  SurfaceDescriptor descriptor;
  ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor));

  ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);

  // host deserialization
  RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr,
                                                                        client->GetFlags());

  RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get());

  ASSERT_TRUE(host.get() != nullptr);
  ASSERT_EQ(host->GetFlags(), client->GetFlags());

  // This will work iff the compositor is not BasicCompositor
  ASSERT_EQ(host->GetFormat(), mozilla::gfx::FORMAT_YUV);

  // host read
  ASSERT_TRUE(host->Lock());

  ASSERT_TRUE(host->GetFormat() == mozilla::gfx::FORMAT_YUV);

  YCbCrImageDataDeserializer yuvDeserializer(host->GetBuffer());
  ASSERT_TRUE(yuvDeserializer.IsValid());
  PlanarYCbCrData data;
  data.mYChannel = yuvDeserializer.GetYData();
  data.mCbChannel = yuvDeserializer.GetCbData();
  data.mCrChannel = yuvDeserializer.GetCrData();
  data.mYStride = yuvDeserializer.GetYStride();
  data.mCbCrStride = yuvDeserializer.GetCbCrStride();
  data.mStereoMode = yuvDeserializer.GetStereoMode();
  data.mYSize = yuvDeserializer.GetYSize();
  data.mCbCrSize = yuvDeserializer.GetCbCrSize();
  data.mYSkip = 0;
  data.mCbSkip = 0;
  data.mCrSkip = 0;
  data.mPicSize = data.mYSize;
  data.mPicX = 0;
  data.mPicY = 0;

  AssertYCbCrSurfacesEqual(&ycbcrData, &data);
  host->Unlock();
}
Example #6
0
// Run the test for a texture client and a surface
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {

  // client allocation
  ASSERT_TRUE(texture->CanExposeDrawTarget());

  ASSERT_TRUE(texture->Lock(OpenMode::OPEN_READ_WRITE));
  // client painting
  RefPtr<DrawTarget> dt = texture->BorrowDrawTarget();
  RefPtr<SourceSurface> source =
    gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface);
  dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint());

  RefPtr<SourceSurface> snapshot = dt->Snapshot();

  AssertSurfacesEqual(snapshot, source);

  dt = nullptr; // drop reference before calling Unlock()
  texture->Unlock();

  // client serialization
  SurfaceDescriptor descriptor;
  ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));

  ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);

  // host deserialization
  RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr,
                                                                 texture->GetFlags());

  ASSERT_TRUE(host.get() != nullptr);
  ASSERT_EQ(host->GetFlags(), texture->GetFlags());

  // host read

  // XXX - this can fail because lock tries to upload the texture but it needs a
  // Compositor to do that. We could add a DummyComposior for testing but I am
  // not sure it'll be worth it. Maybe always test against a BasicCompositor,
  // but the latter needs a widget...
  if (host->Lock()) {
    RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface();

    RefPtr<gfxImageSurface> hostSurface =
      new gfxImageSurface(hostDataSurface->GetData(),
                          hostDataSurface->GetSize(),
                          hostDataSurface->Stride(),
                          SurfaceFormatToImageFormat(hostDataSurface->GetFormat()));
    AssertSurfacesEqual(surface, hostSurface.get());
    host->Unlock();
  }
}
Example #7
0
// Run the test for a texture client and a surface
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {

    // client allocation
    ASSERT_TRUE(texture->CanExposeDrawTarget());
    texture->AllocateForSurface(ToIntSize(surface->GetSize()));
    ASSERT_TRUE(texture->IsAllocated());

    ASSERT_TRUE(texture->Lock(OPEN_READ_WRITE));
    // client painting
    RefPtr<DrawTarget> dt = texture->GetAsDrawTarget();
    RefPtr<SourceSurface> source =
        gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface);
    dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint());

    RefPtr<SourceSurface> snapshot = dt->Snapshot();

    AssertSurfacesEqual(snapshot, source);

    dt = nullptr; // drop reference before calling Unlock()
    texture->Unlock();

    // client serialization
    SurfaceDescriptor descriptor;
    ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));

    ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);

    // host deserialization
    RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr,
                               texture->GetFlags());

    ASSERT_TRUE(host.get() != nullptr);
    ASSERT_EQ(host->GetFlags(), texture->GetFlags());

    // host read
    ASSERT_TRUE(host->Lock());
    RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface();
    host->Unlock();

    nsRefPtr<gfxImageSurface> hostSurface =
        new gfxImageSurface(hostDataSurface->GetData(),
                            ThebesIntSize(hostDataSurface->GetSize()),
                            hostDataSurface->Stride(),
                            SurfaceFormatToImageFormat(hostDataSurface->GetFormat()));
    AssertSurfacesEqual(surface, hostSurface.get());
}
Example #8
0
TextureClient*
CairoImage::GetTextureClient(CompositableClient *aClient)
{
  if (!aClient) {
    return nullptr;
  }

  CompositableForwarder* forwarder = aClient->GetForwarder();
  RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial());
  if (textureClient) {
    return textureClient;
  }

  RefPtr<SourceSurface> surface = GetAsSourceSurface();
  MOZ_ASSERT(surface);
  if (!surface) {
    return nullptr;
  }

  // gfx::BackendType::NONE means default to content backend
  textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
                                                         surface->GetSize(),
                                                         gfx::BackendType::NONE,
                                                         TextureFlags::DEFAULT);
  if (!textureClient) {
    return nullptr;
  }
  MOZ_ASSERT(textureClient->CanExposeDrawTarget());
  if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
    return nullptr;
  }

  TextureClientAutoUnlock autoUnolck(textureClient);
  {
    // We must not keep a reference to the DrawTarget after it has been unlocked.
    DrawTarget* dt = textureClient->BorrowDrawTarget();
    if (!dt) {
      return nullptr;
    }
    dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
  }

  mTextureClients.Put(forwarder->GetSerial(), textureClient);
  return textureClient;
}
Example #9
0
HRESULT
MFTDecoder::CreateInputSample(const uint8_t* aData,
                              uint32_t aDataSize,
                              int64_t aTimestamp,
                              RefPtr<IMFSample>* aOutSample)
{
  NS_ENSURE_TRUE(mDecoder != nullptr, E_POINTER);

  HRESULT hr;
  RefPtr<IMFSample> sample;
  hr = wmf::MFCreateSample(byRef(sample));
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  RefPtr<IMFMediaBuffer> buffer;
  int32_t bufferSize = std::max<uint32_t>(uint32_t(mInputStreamInfo.cbSize), aDataSize);
  UINT32 alignment = (mInputStreamInfo.cbAlignment > 1) ? mInputStreamInfo.cbAlignment - 1 : 0;
  hr = wmf::MFCreateAlignedMemoryBuffer(bufferSize, alignment, byRef(buffer));
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  DWORD maxLength = 0;
  DWORD currentLength = 0;
  BYTE* dst = nullptr;
  hr = buffer->Lock(&dst, &maxLength, &currentLength);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  // Copy data into sample's buffer.
  memcpy(dst, aData, aDataSize);

  hr = buffer->Unlock();
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  hr = buffer->SetCurrentLength(aDataSize);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  hr = sample->AddBuffer(buffer);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  hr = sample->SetSampleTime(UsecsToHNs(aTimestamp));
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  *aOutSample = sample.forget();

  return S_OK;
}
Example #10
0
// Run the test for a texture client and a surface
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {

  // client allocation
  ASSERT_TRUE(texture->AsTextureClientSurface() != nullptr);
  TextureClientSurface* client = texture->AsTextureClientSurface();
  client->AllocateForSurface(ToIntSize(surface->GetSize()));
  ASSERT_TRUE(texture->IsAllocated());

  // client painting
  client->UpdateSurface(surface);

  nsRefPtr<gfxASurface> aSurface = client->GetAsSurface();
  nsRefPtr<gfxImageSurface> clientSurface = aSurface->GetAsImageSurface();

  ASSERT_TRUE(texture->Lock(OPEN_READ_ONLY));
  AssertSurfacesEqual(surface, clientSurface);
  texture->Unlock();

  // client serialization
  texture->SetID(1);
  SurfaceDescriptor descriptor;
  ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));

  ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);

  // host deserialization
  RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(texture->GetID(),
                                                                 descriptor, nullptr,
                                                                 texture->GetFlags());

  ASSERT_TRUE(host.get() != nullptr);
  ASSERT_EQ(host->GetFlags(), texture->GetFlags());
  ASSERT_EQ(host->GetID(), texture->GetID());

  // host read
  ASSERT_TRUE(host->Lock());
  nsRefPtr<gfxImageSurface> hostSurface = host->GetAsSurface();
  host->Unlock();

  AssertSurfacesEqual(surface, hostSurface.get());

  // host deallocation
  host->DeallocateSharedData();
}
Example #11
0
// Run the test for a texture client and a surface
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {

  // client allocation
  ASSERT_TRUE(texture->AsTextureClientSurface() != nullptr);
  TextureClientSurface* client = texture->AsTextureClientSurface();
  client->AllocateForSurface(ToIntSize(surface->GetSize()));
  ASSERT_TRUE(texture->IsAllocated());

  ASSERT_TRUE(texture->Lock(OPEN_READ_WRITE));
  // client painting
  client->UpdateSurface(surface);

  nsRefPtr<gfxASurface> aSurface = client->GetAsSurface();
  nsRefPtr<gfxImageSurface> clientSurface = aSurface->GetAsImageSurface();

  AssertSurfacesEqual(surface, clientSurface);
  texture->Unlock();

  // client serialization
  SurfaceDescriptor descriptor;
  ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));

  ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);

  // host deserialization
  RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr,
                                                                 texture->GetFlags());

  ASSERT_TRUE(host.get() != nullptr);
  ASSERT_EQ(host->GetFlags(), texture->GetFlags());

  // host read
  ASSERT_TRUE(host->Lock());
  RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface();
  host->Unlock();

  nsRefPtr<gfxImageSurface> hostSurface =
    new gfxImageSurface(hostDataSurface->GetData(),
                        ThebesIntSize(hostDataSurface->GetSize()),
                        hostDataSurface->Stride(),
                        SurfaceFormatToImageFormat(hostDataSurface->GetFormat()));
  AssertSurfacesEqual(surface, hostSurface.get());
}
Example #12
0
/* static */ already_AddRefed<TextureClient>
ImageClient::CreateTextureClientForImage(Image* aImage, KnowsCompositor* aForwarder)
{
  RefPtr<TextureClient> texture;
  if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
    PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage);
    const PlanarYCbCrData* data = ycbcr->GetData();
    if (!data) {
      return nullptr;
    }
    texture = TextureClient::CreateForYCbCr(aForwarder,
                                            data->mYSize, data->mYStride,
                                            data->mCbCrSize, data->mCbCrStride,
                                            data->mStereoMode,
                                            data->mColorDepth,
                                            data->mYUVColorSpace,
                                            TextureFlags::DEFAULT);
    if (!texture) {
      return nullptr;
    }

    TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
    if (!autoLock.Succeeded()) {
      return nullptr;
    }

    bool status = UpdateYCbCrTextureClient(texture, *data);
    MOZ_ASSERT(status);
    if (!status) {
      return nullptr;
    }
#ifdef MOZ_WIDGET_ANDROID
  } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
    gfx::IntSize size = aImage->GetSize();
    SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage();
    texture = AndroidSurfaceTextureData::CreateTextureClient(
      typedImage->GetHandle(), size, typedImage->GetContinuous(), typedImage->GetOriginPos(),
      aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT);
#endif
  } else {
    RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface();
    MOZ_ASSERT(surface);
    texture = TextureClient::CreateForDrawing(aForwarder, surface->GetFormat(), aImage->GetSize(),
                                              BackendSelector::Content, TextureFlags::DEFAULT);
    if (!texture) {
      return nullptr;
    }

    MOZ_ASSERT(texture->CanExposeDrawTarget());

    if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
      return nullptr;
    }

    {
      // We must not keep a reference to the DrawTarget after it has been unlocked.
      DrawTarget* dt = texture->BorrowDrawTarget();
      if (!dt) {
        gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
        return nullptr;
      }
      MOZ_ASSERT(surface.get());
      dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
    }

    texture->Unlock();
  }
  return texture.forget();
}
Example #13
0
bool
WMFReader::DecodeAudioData()
{
  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");

  HRESULT hr;
  hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
                                 0, // control flags
                                 0, // read stream index
                                 nullptr,
                                 nullptr,
                                 nullptr);

  if (FAILED(hr)) {
    LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x", hr);
    // End the stream.
    mAudioQueue.Finish();
    return false;
  }

  DWORD flags = 0;
  LONGLONG timestampHns = 0;
  RefPtr<IMFSample> sample;
  hr = mSourceReaderCallback->Wait(&flags, &timestampHns, byRef(sample));
  if (FAILED(hr) ||
      (flags & MF_SOURCE_READERF_ERROR) ||
      (flags & MF_SOURCE_READERF_ENDOFSTREAM) ||
      (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) {
    LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x flags=0x%x",
        hr, flags);
    // End the stream.
    mAudioQueue.Finish();
    return false;
  }

  if (!sample) {
    // Not enough data? Try again...
    return true;
  }

  RefPtr<IMFMediaBuffer> buffer;
  hr = sample->ConvertToContiguousBuffer(byRef(buffer));
  NS_ENSURE_TRUE(SUCCEEDED(hr), false);

  BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it.
  DWORD maxLength = 0, currentLength = 0;
  hr = buffer->Lock(&data, &maxLength, &currentLength);
  NS_ENSURE_TRUE(SUCCEEDED(hr), false);

  uint32_t numFrames = currentLength / mAudioBytesPerSample / mAudioChannels;
  NS_ASSERTION(sizeof(AudioDataValue) == mAudioBytesPerSample, "Size calculation is wrong");
  nsAutoArrayPtr<AudioDataValue> pcmSamples(new AudioDataValue[numFrames * mAudioChannels]);
  memcpy(pcmSamples.get(), data, currentLength);
  buffer->Unlock();

  int64_t offset = mDecoder->GetResource()->Tell();
  int64_t timestamp = HNsToUsecs(timestampHns);
  int64_t duration = GetSampleDuration(sample);

  mAudioQueue.Push(new AudioData(offset,
                                 timestamp,
                                 duration,
                                 numFrames,
                                 pcmSamples.forget(),
                                 mAudioChannels));

  #ifdef LOG_SAMPLE_DECODE
  LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
      timestamp, duration, currentLength);
  #endif

  return true;
}
Example #14
0
bool
ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
{
  AutoLockImage autoLock(aContainer);

  Image *image = autoLock.GetImage();
  if (!image) {
    return false;
  }

  // Don't try to update to an invalid image. We return true because the caller
  // would attempt to recreate the ImageClient otherwise, and that isn't going
  // to help.
  if (!image->IsValid()) {
    return true;
  }

  if (mLastPaintedImageSerial == image->GetSerial()) {
    return true;
  }

  RefPtr<TextureClient> texture = image->GetTextureClient(this);

  AutoRemoveTexture autoRemoveTexture(this);
  if (texture != mFrontBuffer) {
    autoRemoveTexture.mTexture = mFrontBuffer;
    mFrontBuffer = nullptr;
  }

  if (!texture) {
    // Slow path, we should not be hitting it very often and if we do it means
    // we are using an Image class that is not backed by textureClient and we
    // should fix it.
    if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
      PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
      const PlanarYCbCrData* data = ycbcr->GetData();
      if (!data) {
        return false;
      }
      texture = TextureClient::CreateForYCbCr(GetForwarder(),
        data->mYSize, data->mCbCrSize, data->mStereoMode,
        TextureFlags::DEFAULT | mTextureFlags
      );
      if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
        return false;
      }
      bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
      MOZ_ASSERT(status);

      texture->Unlock();
      if (!status) {
        return false;
      }

    } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
               image->GetFormat() == ImageFormat::EGLIMAGE) {
      gfx::IntSize size = image->GetSize();

      if (image->GetFormat() == ImageFormat::EGLIMAGE) {
        EGLImageImage* typedImage = static_cast<EGLImageImage*>(image);
        texture = new EGLImageTextureClient(GetForwarder(),
                                            mTextureFlags,
                                            typedImage,
                                            size);
#ifdef MOZ_WIDGET_ANDROID
      } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
        SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image);
        const SurfaceTextureImage::Data* data = typedImage->GetData();
        texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
                                           data->mSurfTex, size,
                                           data->mOriginPos);
#endif
      } else {
        MOZ_ASSERT(false, "Bad ImageFormat.");
      }
    } else {
      RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
      MOZ_ASSERT(surface);
      texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
                                              gfx::BackendType::NONE, mTextureFlags);
      if (!texture) {
        return false;
      }

      MOZ_ASSERT(texture->CanExposeDrawTarget());

      if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
        return false;
      }

      {
        // We must not keep a reference to the DrawTarget after it has been unlocked.
        DrawTarget* dt = texture->BorrowDrawTarget();
        if (!dt) {
          gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
          return false;
        }
        MOZ_ASSERT(surface.get());
        dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
      }

      texture->Unlock();
    }
  }
  if (!texture || !AddTextureClient(texture)) {
    return false;
  }

  mFrontBuffer = texture;
  GetForwarder()->UseTexture(this, texture);

  UpdatePictureRect(image->GetPictureRect());

  mLastPaintedImageSerial = image->GetSerial();
  aContainer->NotifyPaintedImage(image);

  texture->SyncWithObject(GetForwarder()->GetSyncObject());

  return true;
}
SimpleTiledLayerTile
SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile,
                                     const nsIntPoint& aTileOrigin,
                                     const nsIntRegion& aDirtyRegion)
{
  PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile");
  static gfx::IntSize kTileSize(TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);

  gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType());

  // if this is true, we're using a separate buffer to do our drawing first
  bool doBufferedDrawing = true;
  bool fullPaint = false;

  RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle();

  if (!textureClient) {
    NS_WARNING("TextureClient allocation failed");
    return SimpleTiledLayerTile();
  }

  if (!textureClient->Lock(OPEN_WRITE)) {
    NS_WARNING("TextureClient lock failed");
    return SimpleTiledLayerTile();
  }

  TextureClientSurface *textureClientSurf = textureClient->AsTextureClientSurface();
  if (!textureClientSurf) {
    doBufferedDrawing = false;
  }

  RefPtr<DrawTarget> drawTarget;

  nsRefPtr<gfxImageSurface> clientAsImageSurface;
  unsigned char *bufferData = nullptr;

  // these are set/updated differently based on doBufferedDrawing
  nsIntRect drawBounds;
  nsIntRegion drawRegion;
  nsIntRegion invalidateRegion;

  if (doBufferedDrawing) {
    // try to obtain the TextureClient as an ImageSurface, so that we can
    // access the pixels directly
    nsRefPtr<gfxASurface> asurf = textureClientSurf->GetAsSurface();
    clientAsImageSurface = asurf ? asurf->GetAsImageSurface() : nullptr;
    if (clientAsImageSurface) {
      int32_t bufferStride = clientAsImageSurface->Stride();

      if (!aTile.mCachedBuffer) {
        aTile.mCachedBuffer = SharedBuffer::Create(clientAsImageSurface->GetDataSize());
        fullPaint = true;
      }
      bufferData = (unsigned char*) aTile.mCachedBuffer->Data();

      drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData,
                                                                       kTileSize,
                                                                       bufferStride,
                                                                       tileFormat);

      if (fullPaint) {
        drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength());
        drawRegion = nsIntRegion(drawBounds);
      } else {
        drawBounds = aDirtyRegion.GetBounds();
        drawRegion = nsIntRegion(drawBounds);
        if (GetContentType() == gfxContentType::COLOR_ALPHA)
          drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y,
                                     drawBounds.width, drawBounds.height));
      }
    } else {
      // failed to obtain the client as an ImageSurface
      doBufferedDrawing = false;
    }
  }

  // this might get set above if we couldn't extract out a buffer
  if (!doBufferedDrawing) {
    drawTarget = textureClient->AsTextureClientDrawTarget()->GetAsDrawTarget();

    fullPaint = true;
    drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength());
    drawRegion = nsIntRegion(drawBounds);

    if (GetContentType() == gfxContentType::COLOR_ALPHA)
      drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height));
  }

  // do the drawing
  RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);

  ctxt->Scale(mResolution, mResolution);
  ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));

  mCallback(mThebesLayer, ctxt,
            drawRegion,
            fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED?
            invalidateRegion,
            mCallbackData);

  ctxt = nullptr;
  drawTarget = nullptr;

  if (doBufferedDrawing) {
    memcpy(clientAsImageSurface->Data(), bufferData, clientAsImageSurface->GetDataSize());
    clientAsImageSurface = nullptr;
    bufferData = nullptr;
  }

  textureClient->Unlock();

  if (!mCompositableClient->AddTextureClient(textureClient)) {
    NS_WARNING("Failed to add tile TextureClient [simple]");
    return SimpleTiledLayerTile();
  }

  // aTile.mCachedBuffer was set earlier
  aTile.mTileBuffer = textureClient;
  aTile.mManager = mManager;
  aTile.mLastUpdate = TimeStamp::Now();

  return aTile;
}
bool
PersistentBufferProviderShared::SetForwarder(KnowsCompositor* aFwd)
{
  MOZ_ASSERT(aFwd);
  if (!aFwd) {
    return false;
  }

  if (mFwd == aFwd) {
    // The forwarder should not change most of the time.
    return true;
  }

  if (IsActivityTracked()) {
    mFwd->GetActiveResourceTracker().RemoveObject(this);
  }

  if (mFwd->GetTextureForwarder() != aFwd->GetTextureForwarder() ||
      mFwd->GetCompositorBackendType() != aFwd->GetCompositorBackendType()) {
    // We are going to be used with an different and/or incompatible forwarder.
    // This should be extremely rare. We have to copy the front buffer into a
    // texture that is compatible with the new forwarder.

    // Grab the current front buffer.
    RefPtr<TextureClient> prevTexture = GetTexture(mFront);

    // Get rid of everything else
    Destroy();

    if (prevTexture) {
      RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing(
        aFwd, mFormat, mSize,
        BackendSelector::Canvas,
        TextureFlags::DEFAULT,
        TextureAllocationFlags::ALLOC_DEFAULT
      );

      MOZ_ASSERT(newTexture);
      if (!newTexture) {
        return false;
      }

      // If we early-return in one of the following branches, we will
      // leave the buffer provider in an empty state, since we called
      // Destroy. Not ideal but at least we won't try to use it with a
      // an incompatible ipc channel.

      if (!newTexture->Lock(OpenMode::OPEN_WRITE)) {
        return false;
      }

      if (!prevTexture->Lock(OpenMode::OPEN_READ)) {
        newTexture->Unlock();
        return false;
      }

      bool success = prevTexture->CopyToTextureClient(newTexture, nullptr, nullptr);

      prevTexture->Unlock();
      newTexture->Unlock();

      if (!success) {
        return false;
      }

      if (!mTextures.append(newTexture)) {
        return false;
      }
      mFront = Some<uint32_t>(mTextures.length() - 1);
      mBack = mFront;
    }
  }

  mFwd = aFwd;

  return true;
}
TileClient
ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
                                    const nsIntPoint& aTileOrigin,
                                    const nsIntRegion& aDirtyRegion)
{
  PROFILER_LABEL("ClientTiledLayerBuffer", "ValidateTile");

#ifdef GFX_TILEDLAYER_PREF_WARNINGS
  if (aDirtyRegion.IsComplex()) {
    printf_stderr("Complex region\n");
  }
#endif

  if (aTile.IsPlaceholderTile()) {
    aTile.SetLayerManager(mManager);
  }

  // Discard our front and backbuffers if our contents changed. In this case
  // the calling code will already have taken care of invalidating the entire
  // layer.
  if (HasFormatChanged()) {
    aTile.DiscardBackBuffer();
    aTile.DiscardFrontBuffer();
  }

  bool createdTextureClient = false;
  nsIntRegion offsetDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
  bool usingSinglePaintBuffer = !!mSinglePaintDrawTarget;
  RefPtr<TextureClient> backBuffer =
    aTile.GetBackBuffer(offsetDirtyRegion,
                        mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType())),
                        &createdTextureClient, !usingSinglePaintBuffer);

  if (!backBuffer->Lock(OPEN_READ_WRITE)) {
    NS_WARNING("Failed to lock tile TextureClient for updating.");
    aTile.DiscardFrontBuffer();
    return aTile;
  }

  // We must not keep a reference to the DrawTarget after it has been unlocked,
  // make sure these are null'd before unlocking as destruction of the context
  // may cause the target to be flushed.
  RefPtr<DrawTarget> drawTarget = backBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget();
  drawTarget->SetTransform(Matrix());

  RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);

  if (usingSinglePaintBuffer) {
    // XXX Perhaps we should just copy the bounding rectangle here?
    RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot();
    nsIntRegionRectIterator it(aDirtyRegion);
    for (const nsIntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
      printf_stderr(" break into subdirtyRect %i, %i, %i, %i\n",
                    dirtyRect->x, dirtyRect->y, dirtyRect->width, dirtyRect->height);
#endif
      gfx::Rect drawRect(dirtyRect->x - aTileOrigin.x,
                         dirtyRect->y - aTileOrigin.y,
                         dirtyRect->width,
                         dirtyRect->height);
      drawRect.Scale(mResolution);

      gfx::IntRect copyRect(NS_roundf((dirtyRect->x - mSinglePaintBufferOffset.x) * mResolution),
                            NS_roundf((dirtyRect->y - mSinglePaintBufferOffset.y) * mResolution),
                            drawRect.width,
                            drawRect.height);
      gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
      drawTarget->CopySurface(source, copyRect, copyTarget);

      // Mark the newly updated area as invalid in the front buffer
      aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
    }

    // The new buffer is now validated, remove the dirty region from it.
    aTile.mInvalidBack.Sub(nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE),
                           offsetDirtyRegion);
  } else {
    // Area of the full tile...
    nsIntRegion tileRegion = nsIntRect(aTileOrigin.x, aTileOrigin.y, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);

    // Intersect this area with the portion that's dirty.
    tileRegion = tileRegion.Intersect(aDirtyRegion);

    // Move invalid areas into layer space.
    aTile.mInvalidFront.MoveBy(aTileOrigin);
    aTile.mInvalidBack.MoveBy(aTileOrigin);

    // Add the area that's going to be redrawn to the invalid area of the
    // front region.
    aTile.mInvalidFront.Or(aTile.mInvalidFront, tileRegion);

    // Add invalid areas of the backbuffer to the area to redraw.
    tileRegion.Or(tileRegion, aTile.mInvalidBack);

    // Move invalid areas back into tile space.
    aTile.mInvalidFront.MoveBy(-aTileOrigin);

    // This will be validated now.
    aTile.mInvalidBack.SetEmpty();

    nsIntRect bounds = tileRegion.GetBounds();
    bounds.ScaleRoundOut(mResolution, mResolution);
    bounds.MoveBy(-aTileOrigin);

    if (GetContentType() != gfxContentType::COLOR) {
      drawTarget->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
    }

    ctxt->NewPath();
    ctxt->Clip(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
    ctxt->Scale(mResolution, mResolution);
    ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
    mCallback(mThebesLayer, ctxt,
              tileRegion.GetBounds(),
              DrawRegionClip::CLIP_NONE,
              nsIntRegion(), mCallbackData);

  }

#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
  DrawDebugOverlay(drawTarget, aTileOrigin.x * mResolution,
                   aTileOrigin.y * mResolution, GetTileLength(), GetTileLength());
#endif

  ctxt = nullptr;
  drawTarget = nullptr;

  backBuffer->Unlock();

  aTile.Flip();

  if (createdTextureClient) {
    if (!mCompositableClient->AddTextureClient(backBuffer)) {
      NS_WARNING("Failed to add tile TextureClient.");
      aTile.DiscardFrontBuffer();
      aTile.DiscardBackBuffer();
      return aTile;
    }
  }

  // Note, we don't call UpdatedTexture. The Updated function is called manually
  // by the TiledContentHost before composition.

  if (backBuffer->HasInternalBuffer()) {
    // If our new buffer has an internal buffer, we don't want to keep another
    // TextureClient around unnecessarily, so discard the back-buffer.
    aTile.DiscardBackBuffer();
  }

  return aTile;
}
Example #18
0
HRESULT
WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
                                          int64_t aStreamOffset,
                                          VideoData** aOutVideoData)
{
  NS_ENSURE_TRUE(aSample, E_POINTER);
  NS_ENSURE_TRUE(aOutVideoData, E_POINTER);

  *aOutVideoData = nullptr;

  HRESULT hr;
  RefPtr<IMFMediaBuffer> buffer;

  // Must convert to contiguous buffer to use IMD2DBuffer interface.
  hr = aSample->ConvertToContiguousBuffer(byRef(buffer));
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  // Try and use the IMF2DBuffer interface if available, otherwise fallback
  // to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient,
  // but only some systems (Windows 8?) support it.
  BYTE* data = nullptr;
  LONG stride = 0;
  RefPtr<IMF2DBuffer> twoDBuffer;
  hr = buffer->QueryInterface(static_cast<IMF2DBuffer**>(byRef(twoDBuffer)));
  if (SUCCEEDED(hr)) {
    hr = twoDBuffer->Lock2D(&data, &stride);
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
  } else {
    hr = buffer->Lock(&data, nullptr, nullptr);
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    stride = mVideoStride;
  }

  // YV12, planar format: [YYYY....][VVVV....][UUUU....]
  // i.e., Y, then V, then U.
  VideoData::YCbCrBuffer b;

  // Y (Y') plane
  b.mPlanes[0].mData = data;
  b.mPlanes[0].mStride = stride;
  b.mPlanes[0].mHeight = mVideoHeight;
  b.mPlanes[0].mWidth = mVideoWidth;
  b.mPlanes[0].mOffset = 0;
  b.mPlanes[0].mSkip = 0;

  // The V and U planes are stored 16-row-aligned, so we need to add padding
  // to the row heights to ensure the Y'CbCr planes are referenced properly.
  uint32_t padding = 0;
  if (mVideoHeight % 16 != 0) {
    padding = 16 - (mVideoHeight % 16);
  }
  uint32_t y_size = stride * (mVideoHeight + padding);
  uint32_t v_size = stride * (mVideoHeight + padding) / 4;
  uint32_t halfStride = (stride + 1) / 2;
  uint32_t halfHeight = (mVideoHeight + 1) / 2;
  uint32_t halfWidth = (mVideoWidth + 1) / 2;

  // U plane (Cb)
  b.mPlanes[1].mData = data + y_size + v_size;
  b.mPlanes[1].mStride = halfStride;
  b.mPlanes[1].mHeight = halfHeight;
  b.mPlanes[1].mWidth = halfWidth;
  b.mPlanes[1].mOffset = 0;
  b.mPlanes[1].mSkip = 0;

  // V plane (Cr)
  b.mPlanes[2].mData = data + y_size;
  b.mPlanes[2].mStride = halfStride;
  b.mPlanes[2].mHeight = halfHeight;
  b.mPlanes[2].mWidth = halfWidth;
  b.mPlanes[2].mOffset = 0;
  b.mPlanes[2].mSkip = 0;

  Microseconds pts = GetSampleTime(aSample);
  Microseconds duration = GetSampleDuration(aSample);
  nsRefPtr<VideoData> v = VideoData::Create(mVideoInfo,
                                            mImageContainer,
                                            aStreamOffset,
                                            std::max(0LL, pts),
                                            duration,
                                            b,
                                            false,
                                            -1,
                                            ToIntRect(mPictureRegion));
  if (twoDBuffer) {
    twoDBuffer->Unlock2D();
  } else {
    buffer->Unlock();
  }

  v.forget(aOutVideoData);
  return S_OK;
}
Example #19
0
HRESULT
WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
                                          int64_t aStreamOffset,
                                          VideoData** aOutVideoData)
{
  NS_ENSURE_TRUE(aSample, E_POINTER);
  NS_ENSURE_TRUE(aOutVideoData, E_POINTER);

  *aOutVideoData = nullptr;

  HRESULT hr;
  RefPtr<IMFMediaBuffer> buffer;

  // Must convert to contiguous buffer to use IMD2DBuffer interface.
  hr = aSample->ConvertToContiguousBuffer(getter_AddRefs(buffer));
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  // Try and use the IMF2DBuffer interface if available, otherwise fallback
  // to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient,
  // but only some systems (Windows 8?) support it.
  BYTE* data = nullptr;
  LONG stride = 0;
  RefPtr<IMF2DBuffer> twoDBuffer;
  hr = buffer->QueryInterface(static_cast<IMF2DBuffer**>(getter_AddRefs(twoDBuffer)));
  if (SUCCEEDED(hr)) {
    hr = twoDBuffer->Lock2D(&data, &stride);
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
  } else {
    hr = buffer->Lock(&data, nullptr, nullptr);
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    stride = mVideoStride;
  }

  // YV12, planar format: [YYYY....][VVVV....][UUUU....]
  // i.e., Y, then V, then U.
  VideoData::YCbCrBuffer b;

  uint32_t videoWidth = mImageSize.width;
  uint32_t videoHeight = mImageSize.height;

  // Y (Y') plane
  b.mPlanes[0].mData = data;
  b.mPlanes[0].mStride = stride;
  b.mPlanes[0].mHeight = videoHeight;
  b.mPlanes[0].mWidth = videoWidth;
  b.mPlanes[0].mOffset = 0;
  b.mPlanes[0].mSkip = 0;

  // The V and U planes are stored 16-row-aligned, so we need to add padding
  // to the row heights to ensure the Y'CbCr planes are referenced properly.
  uint32_t padding = 0;
  if (videoHeight % 16 != 0) {
    padding = 16 - (videoHeight % 16);
  }
  uint32_t y_size = stride * (videoHeight + padding);
  uint32_t v_size = stride * (videoHeight + padding) / 4;
  uint32_t halfStride = (stride + 1) / 2;
  uint32_t halfHeight = (videoHeight + 1) / 2;
  uint32_t halfWidth = (videoWidth + 1) / 2;

  // U plane (Cb)
  b.mPlanes[1].mData = data + y_size + v_size;
  b.mPlanes[1].mStride = halfStride;
  b.mPlanes[1].mHeight = halfHeight;
  b.mPlanes[1].mWidth = halfWidth;
  b.mPlanes[1].mOffset = 0;
  b.mPlanes[1].mSkip = 0;

  // V plane (Cr)
  b.mPlanes[2].mData = data + y_size;
  b.mPlanes[2].mStride = halfStride;
  b.mPlanes[2].mHeight = halfHeight;
  b.mPlanes[2].mWidth = halfWidth;
  b.mPlanes[2].mOffset = 0;
  b.mPlanes[2].mSkip = 0;

  media::TimeUnit pts = GetSampleTime(aSample);
  NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
  media::TimeUnit duration = GetSampleDuration(aSample);
  NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);

  RefPtr<layers::PlanarYCbCrImage> image =
    new IMFYCbCrImage(buffer, twoDBuffer);

  nsIntRect pictureRegion = mVideoInfo.ScaledImageRect(videoWidth, videoHeight);
  VideoData::SetVideoDataToImage(image,
                                 mVideoInfo,
                                 b,
                                 pictureRegion,
                                 false);

  RefPtr<VideoData> v =
    VideoData::CreateFromImage(mVideoInfo,
                               mImageContainer,
                               aStreamOffset,
                               pts.ToMicroseconds(),
                               duration.ToMicroseconds(),
                               image.forget(),
                               false,
                               -1,
                               pictureRegion);

  v.forget(aOutVideoData);
  return S_OK;
}
Example #20
0
HRESULT
WMFAudioMFTManager::Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutData)
{
  aOutData = nullptr;
  RefPtr<IMFSample> sample;
  HRESULT hr;
  int typeChangeCount = 0;
  while (true) {
    hr = mDecoder->Output(&sample);
    if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
      return hr;
    }
    if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
      hr = UpdateOutputType();
      NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
      // Catch infinite loops, but some decoders perform at least 2 stream
      // changes on consecutive calls, so be permissive.
      // 100 is arbitrarily > 2.
      NS_ENSURE_TRUE(typeChangeCount < 100, MF_E_TRANSFORM_STREAM_CHANGE);
      ++typeChangeCount;
      continue;
    }
    break;
  }

  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  RefPtr<IMFMediaBuffer> buffer;
  hr = sample->ConvertToContiguousBuffer(byRef(buffer));
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it.
  DWORD maxLength = 0, currentLength = 0;
  hr = buffer->Lock(&data, &maxLength, &currentLength);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  // Sometimes when starting decoding, the AAC decoder gives us samples
  // with a negative timestamp. AAC does usually have preroll (or encoder
  // delay) encoded into its bitstream, but the amount encoded to the stream
  // is variable, and it not signalled in-bitstream. There is sometimes
  // signalling in the MP4 container what the preroll amount, but it's
  // inconsistent. It looks like WMF's AAC encoder may take this into
  // account, so strip off samples with a negative timestamp to get us
  // to a 0-timestamp start. This seems to maintain A/V sync, so we can run
  // with this until someone complains...

  // We calculate the timestamp and the duration based on the number of audio
  // frames we've already played. We don't trust the timestamp stored on the
  // IMFSample, as sometimes it's wrong, possibly due to buggy encoders?

  // If this sample block comes after a discontinuity (i.e. a gap or seek)
  // reset the frame counters, and capture the timestamp. Future timestamps
  // will be offset from this block's timestamp.
  UINT32 discontinuity = false;
  sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity);
  if (mMustRecaptureAudioPosition || discontinuity) {
    // Update the output type, in case this segment has a different
    // rate. This also triggers on the first sample, which can have a
    // different rate than is advertised in the container, and sometimes we
    // don't get a MF_E_TRANSFORM_STREAM_CHANGE when the rate changes.
    hr = UpdateOutputType();
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

    mAudioFrameSum = 0;
    LONGLONG timestampHns = 0;
    hr = sample->GetSampleTime(&timestampHns);
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    mAudioTimeOffset = media::TimeUnit::FromMicroseconds(timestampHns / 10);
    mMustRecaptureAudioPosition = false;
  }
  // We can assume PCM 16 output.
  int32_t numSamples = currentLength / 2;
  int32_t numFrames = numSamples / mAudioChannels;
  MOZ_ASSERT(numFrames >= 0);
  MOZ_ASSERT(numSamples >= 0);
  if (numFrames == 0) {
    // All data from this chunk stripped, loop back and try to output the next
    // frame, if possible.
    return S_OK;
  }

  nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[numSamples]);

  int16_t* pcm = (int16_t*)data;
  for (int32_t i = 0; i < numSamples; ++i) {
    audioData[i] = AudioSampleToFloat(pcm[i]);
  }

  buffer->Unlock();

  media::TimeUnit timestamp =
    mAudioTimeOffset + FramesToTimeUnit(mAudioFrameSum, mAudioRate);
  NS_ENSURE_TRUE(timestamp.IsValid(), E_FAIL);

  mAudioFrameSum += numFrames;

  media::TimeUnit duration = FramesToTimeUnit(numFrames, mAudioRate);
  NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);

  aOutData = new AudioData(aStreamOffset,
                           timestamp.ToMicroseconds(),
                           duration.ToMicroseconds(),
                           numFrames,
                           audioData.forget(),
                           mAudioChannels,
                           mAudioRate);

  #ifdef LOG_SAMPLE_DECODE
  LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
      timestamp.ToMicroseconds(), duration.ToMicroseconds(), currentLength);
  #endif

  return S_OK;
}
  NS_IMETHOD
  Run() override
  {
    AssertIsOnMainThread();

    MutexAutoLock lock(mPromiseProxy->Lock());
    if (mPromiseProxy->CleanedUp()) {
      return NS_OK;
    }

    nsCOMPtr<nsPIDOMWindowOuter> window;
    nsresult rv = OpenWindow(getter_AddRefs(window));
    if (NS_SUCCEEDED(rv)) {
      MOZ_ASSERT(window);

      WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
      MOZ_ASSERT(workerPrivate);

      WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo();
      nsCOMPtr<nsIURI> baseURI;
      nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mHref);
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return NS_ERROR_FAILURE;
      }

      nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
      nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);

      if (!webProgress) {
        return NS_ERROR_FAILURE;
      }

      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
      MOZ_ASSERT(swm);

      nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
      MOZ_ASSERT(principal);
      RefPtr<ServiceWorkerRegistrationInfo> registration =
        swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
      if (NS_WARN_IF(!registration)) {
        return NS_ERROR_FAILURE;
      }
      RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
        registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID());
      if (NS_WARN_IF(!serviceWorkerInfo)) {
        return NS_ERROR_FAILURE;
      }

      nsCOMPtr<nsIWebProgressListener> listener =
        new WebProgressListener(mPromiseProxy, serviceWorkerInfo->WorkerPrivate(),
                                window, baseURI);

      rv = webProgress->AddProgressListener(listener,
                                            nsIWebProgress::NOTIFY_STATE_DOCUMENT);
      MOZ_ASSERT(NS_SUCCEEDED(rv));
      return NS_OK;
    }

    RefPtr<ResolveOpenWindowRunnable> resolveRunnable =
      new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv);

    NS_WARN_IF(!resolveRunnable->Dispatch());

    return NS_OK;
  }
Example #22
0
TextureClient*
CairoImage::GetTextureClient(CompositableClient *aClient)
{
  if (!aClient) {
    return nullptr;
  }

  CompositableForwarder* forwarder = aClient->GetForwarder();
  RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial());
  if (textureClient) {
    return textureClient;
  }

  RefPtr<SourceSurface> surface = GetAsSourceSurface();
  MOZ_ASSERT(surface);
  if (!surface) {
    return nullptr;
  }


// XXX windows' TextureClients do not hold ISurfaceAllocator,
// recycler does not work on windows.
#ifndef XP_WIN

// XXX only gonk ensure when TextureClient is recycled,
// TextureHost is not used by CompositableHost.
#ifdef MOZ_WIDGET_GONK
  RefPtr<TextureClientRecycleAllocator> recycler =
    aClient->GetTextureClientRecycler();
  if (recycler) {
    textureClient =
      recycler->CreateOrRecycleForDrawing(surface->GetFormat(),
                                          surface->GetSize(),
                                          gfx::BackendType::NONE,
                                          aClient->GetTextureFlags());
  }
#endif

#endif
  if (!textureClient) {
    // gfx::BackendType::NONE means default to content backend
    textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
                                                           surface->GetSize(),
                                                           gfx::BackendType::NONE,
                                                           TextureFlags::DEFAULT);
  }
  if (!textureClient) {
    return nullptr;
  }
  MOZ_ASSERT(textureClient->CanExposeDrawTarget());
  if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
    return nullptr;
  }

  TextureClientAutoUnlock autoUnolck(textureClient);
  {
    // We must not keep a reference to the DrawTarget after it has been unlocked.
    DrawTarget* dt = textureClient->BorrowDrawTarget();
    if (!dt) {
      return nullptr;
    }
    dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
  }

  mTextureClients.Put(forwarder->GetSerial(), textureClient);
  return textureClient;
}
SimpleTiledLayerTile
SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile,
                                     const nsIntPoint& aTileOrigin,
                                     const nsIntRegion& aDirtyRegion)
{
  PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile");
  static gfx::IntSize kTileSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight());

  gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType());

  // if this is true, we're using a separate buffer to do our drawing first
  bool doBufferedDrawing = true;
  bool fullPaint = false;

  RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle();

  if (!textureClient) {
    NS_WARNING("TextureClient allocation failed");
    return SimpleTiledLayerTile();
  }

  if (!textureClient->Lock(OPEN_READ_WRITE)) {
    NS_WARNING("TextureClient lock failed");
    return SimpleTiledLayerTile();
  }

  if (!textureClient->CanExposeDrawTarget()) {
    doBufferedDrawing = false;
  }

  RefPtr<DrawTarget> drawTarget;

  unsigned char *bufferData = nullptr;

  // these are set/updated differently based on doBufferedDrawing
  nsIntRect drawBounds;
  nsIntRegion drawRegion;
  nsIntRegion invalidateRegion;

  RefPtr<DrawTarget> srcDT;
  uint8_t* srcData = nullptr;
  int32_t srcStride = 0;
  gfx::IntSize srcSize;
  gfx::SurfaceFormat srcFormat = gfx::SurfaceFormat::UNKNOWN;

  if (doBufferedDrawing) {
    // try to directly access the pixels of the TextureClient
    srcDT = textureClient->GetAsDrawTarget();
    if (srcDT->LockBits(&srcData, &srcSize, &srcStride, &srcFormat)) {
      if (!aTile.mCachedBuffer) {
        aTile.mCachedBuffer = SharedBuffer::Create(srcStride * srcSize.height);
        fullPaint = true;
      }
      bufferData = (unsigned char*) aTile.mCachedBuffer->Data();

      drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData,
                                                                       kTileSize,
                                                                       srcStride,
                                                                       tileFormat);

      if (fullPaint) {
        drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height);
        drawRegion = nsIntRegion(drawBounds);
      } else {
        drawBounds = aDirtyRegion.GetBounds();
        drawRegion = nsIntRegion(drawBounds);
        if (GetContentType() == gfxContentType::COLOR_ALPHA)
          drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y,
                                     drawBounds.width, drawBounds.height));
      }
    } else {
      // failed to obtain the client as an ImageSurface
      doBufferedDrawing = false;
    }
  }

  // this might get set above if we couldn't extract out a buffer
  if (!doBufferedDrawing) {
    drawTarget = textureClient->GetAsDrawTarget();

    fullPaint = true;
    drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height);
    drawRegion = nsIntRegion(drawBounds);

    if (GetContentType() == gfxContentType::COLOR_ALPHA)
      drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height));
  }

  // do the drawing
  RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);

  ctxt->Scale(mResolution, mResolution);
  ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));

  mCallback(mThebesLayer, ctxt,
            drawRegion,
            fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED?
            invalidateRegion,
            mCallbackData);

  ctxt = nullptr;

  if (doBufferedDrawing) {
    memcpy(srcData, bufferData, srcSize.height * srcStride);
    bufferData = nullptr;
    srcDT->ReleaseBits(srcData);
    srcDT = nullptr;
  }

  drawTarget = nullptr;
  textureClient->Unlock();

  if (!mCompositableClient->AddTextureClient(textureClient)) {
    NS_WARNING("Failed to add tile TextureClient [simple]");
    return SimpleTiledLayerTile();
  }

  // aTile.mCachedBuffer was set earlier
  aTile.mTileBuffer = textureClient;
  aTile.mManager = mManager;
  aTile.mLastUpdate = TimeStamp::Now();

  return aTile;
}
Example #24
0
HRESULT
WMFAudioMFTManager::Output(int64_t aStreamOffset,
                           nsAutoPtr<MediaData>& aOutData)
{
  aOutData = nullptr;
  RefPtr<IMFSample> sample;
  HRESULT hr;
  while (true) {
    hr = mDecoder->Output(&sample);
    if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
      return hr;
    }
    if (hr == MF_E_TRANSFORM_STREAM_CHANGE) {
      hr = UpdateOutputType();
      NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
      continue;
    }
    break;
  }

  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  RefPtr<IMFMediaBuffer> buffer;
  hr = sample->ConvertToContiguousBuffer(byRef(buffer));
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it.
  DWORD maxLength = 0, currentLength = 0;
  hr = buffer->Lock(&data, &maxLength, &currentLength);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  // Sometimes when starting decoding, the AAC decoder gives us samples
  // with a negative timestamp. AAC does usually have preroll (or encoder
  // delay) encoded into its bitstream, but the amount encoded to the stream
  // is variable, and it not signalled in-bitstream. There is sometimes
  // signalling in the MP4 container what the preroll amount, but it's
  // inconsistent. It looks like WMF's AAC encoder may take this into
  // account, so strip off samples with a negative timestamp to get us
  // to a 0-timestamp start. This seems to maintain A/V sync, so we can run
  // with this until someone complains...

  // We calculate the timestamp and the duration based on the number of audio
  // frames we've already played. We don't trust the timestamp stored on the
  // IMFSample, as sometimes it's wrong, possibly due to buggy encoders?

  // If this sample block comes after a discontinuity (i.e. a gap or seek)
  // reset the frame counters, and capture the timestamp. Future timestamps
  // will be offset from this block's timestamp.
  UINT32 discontinuity = false;
  int32_t numFramesToStrip = 0;
  sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity);
  if (mMustRecaptureAudioPosition || discontinuity) {
    // Update the output type, in case this segment has a different
    // rate. This also triggers on the first sample, which can have a
    // different rate than is advertised in the container, and sometimes we
    // don't get a MF_E_TRANSFORM_STREAM_CHANGE when the rate changes.
    hr = UpdateOutputType();
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

    mAudioFrameSum = 0;
    LONGLONG timestampHns = 0;
    hr = sample->GetSampleTime(&timestampHns);
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    hr = HNsToFrames(timestampHns, mAudioRate, &mAudioFrameOffset);
    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    if (mAudioFrameOffset < 0) {
      // First sample has a negative timestamp. Strip off the samples until
      // we reach positive territory.
      numFramesToStrip = -mAudioFrameOffset;
      mAudioFrameOffset = 0;
    }
    mMustRecaptureAudioPosition = false;
  }
  MOZ_ASSERT(numFramesToStrip >= 0);
  int32_t numSamples = currentLength / mAudioBytesPerSample;
  int32_t numFrames = numSamples / mAudioChannels;
  int32_t offset = std::min<int32_t>(numFramesToStrip, numFrames);
  numFrames -= offset;
  numSamples -= offset * mAudioChannels;
  MOZ_ASSERT(numFrames >= 0);
  MOZ_ASSERT(numSamples >= 0);
  if (numFrames == 0) {
    // All data from this chunk stripped, loop back and try to output the next
    // frame, if possible.
    return S_OK;
  }

  nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[numSamples]);

  // Just assume PCM output for now...
  MOZ_ASSERT(mAudioBytesPerSample == 2);
  int16_t* pcm = ((int16_t*)data) + (offset * mAudioChannels);
  MOZ_ASSERT(pcm >= (int16_t*)data);
  MOZ_ASSERT(pcm <= (int16_t*)(data + currentLength));
  MOZ_ASSERT(pcm+numSamples <= (int16_t*)(data + currentLength));
  for (int32_t i = 0; i < numSamples; ++i) {
    audioData[i] = AudioSampleToFloat(pcm[i]);
  }

  buffer->Unlock();
  int64_t timestamp;
  hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, &timestamp);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  mAudioFrameSum += numFrames;

  int64_t duration;
  hr = FramesToUsecs(numFrames, mAudioRate, &duration);
  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);

  aOutData = new AudioData(aStreamOffset,
                           timestamp,
                           duration,
                           numFrames,
                           audioData.forget(),
                           mAudioChannels,
                           mAudioRate);

  #ifdef LOG_SAMPLE_DECODE
  LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
      timestamp, duration, currentLength);
  #endif

  return S_OK;
}
Example #25
0
bool
WMFReader::DecodeAudioData()
{
  MOZ_ASSERT(OnTaskQueue());

  HRESULT hr;
  hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM,
                                 0, // control flags
                                 0, // read stream index
                                 nullptr,
                                 nullptr,
                                 nullptr);

  if (FAILED(hr)) {
    DECODER_LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x", hr);
    // End the stream.
    return false;
  }

  DWORD flags = 0;
  LONGLONG timestampHns = 0;
  RefPtr<IMFSample> sample;
  hr = mSourceReaderCallback->Wait(&flags, &timestampHns, byRef(sample));
  if (FAILED(hr) ||
      (flags & MF_SOURCE_READERF_ERROR) ||
      (flags & MF_SOURCE_READERF_ENDOFSTREAM) ||
      (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) {
    DECODER_LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x flags=0x%x",
                hr, flags);
    // End the stream.
    return false;
  }

  if (!sample) {
    // Not enough data? Try again...
    return true;
  }

  RefPtr<IMFMediaBuffer> buffer;
  hr = sample->ConvertToContiguousBuffer(byRef(buffer));
  NS_ENSURE_TRUE(SUCCEEDED(hr), false);

  BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it.
  DWORD maxLength = 0, currentLength = 0;
  hr = buffer->Lock(&data, &maxLength, &currentLength);
  NS_ENSURE_TRUE(SUCCEEDED(hr), false);

  uint32_t numFrames = currentLength / mAudioBytesPerSample / mAudioChannels;
  NS_ASSERTION(sizeof(AudioDataValue) == mAudioBytesPerSample, "Size calculation is wrong");
  nsAutoArrayPtr<AudioDataValue> pcmSamples(new AudioDataValue[numFrames * mAudioChannels]);
  memcpy(pcmSamples.get(), data, currentLength);
  buffer->Unlock();

  // We calculate the timestamp and the duration based on the number of audio
  // frames we've already played. We don't trust the timestamp stored on the
  // IMFSample, as sometimes it's wrong, possibly due to buggy encoders?

  // If this sample block comes after a discontinuity (i.e. a gap or seek)
  // reset the frame counters, and capture the timestamp. Future timestamps
  // will be offset from this block's timestamp.
  UINT32 discontinuity = false;
  sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity);
  if (mMustRecaptureAudioPosition || discontinuity) {
    mAudioFrameSum = 0;
    hr = HNsToFrames(timestampHns, mAudioRate, &mAudioFrameOffset);
    NS_ENSURE_TRUE(SUCCEEDED(hr), false);
    mMustRecaptureAudioPosition = false;
  }

  int64_t timestamp;
  hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, &timestamp);
  NS_ENSURE_TRUE(SUCCEEDED(hr), false);

  mAudioFrameSum += numFrames;

  int64_t duration;
  hr = FramesToUsecs(numFrames, mAudioRate, &duration);
  NS_ENSURE_TRUE(SUCCEEDED(hr), false);

  mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(),
                                 timestamp,
                                 duration,
                                 numFrames,
                                 pcmSamples.forget(),
                                 mAudioChannels,
                                 mAudioRate));

  #ifdef LOG_SAMPLE_DECODE
  DECODER_LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
              timestamp, duration, currentLength);
  #endif

  return true;
}
Example #26
0
static TemporaryRef<TextureClient>
TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator,
                      TextureFlags baseFlags, LayersBackend layersBackend)
{
  auto backendType = gfx::BackendType::CAIRO;
  TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType,
                           baseFlags, layersBackend);

  RefPtr<BufferTextureClient> texClient;

  {
    gl::ScopedReadbackFB autoReadback(src);

    // We have a source FB, now we need a format.
    GLenum destFormat = LOCAL_GL_BGRA;
    GLenum destType = LOCAL_GL_UNSIGNED_BYTE;
    GLenum readFormat;
    GLenum readType;

    // We actually don't care if they match, since we can handle
    // any read{Format,Type} we get.
    auto gl = src->mGL;
    GetActualReadFormats(gl, destFormat, destType, &readFormat, &readType);

    MOZ_ASSERT(readFormat == LOCAL_GL_RGBA ||
               readFormat == LOCAL_GL_BGRA);
    MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);

    // With a format and type, we can create texClient.
    if (readFormat == LOCAL_GL_BGRA &&
        readType == LOCAL_GL_UNSIGNED_BYTE)
    {
      // 0xAARRGGBB
      // In Lendian: [BB, GG, RR, AA]
      texClient = factory.CreateB8G8R8AX8();

    } else if (readFormat == LOCAL_GL_RGBA &&
               readType == LOCAL_GL_UNSIGNED_BYTE)
    {
      // [RR, GG, BB, AA]
      texClient = factory.CreateR8G8B8AX8();
    } else {
      MOZ_CRASH("Bad `read{Format,Type}`.");
    }

    MOZ_ASSERT(texClient);
    if (!texClient)
        return nullptr;

    // With a texClient, we can lock for writing.
    MOZ_ALWAYS_TRUE( texClient->Lock(OpenMode::OPEN_WRITE) );

    uint8_t* lockedBytes = texClient->GetLockedData();

    // ReadPixels from the current FB into lockedBits.
    auto width = src->mSize.width;
    auto height = src->mSize.height;

    {
      ScopedPackAlignment autoAlign(gl, 4);

      gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, lockedBytes);
    }

    // RB_SWAPPED doesn't work with D3D11. (bug 1051010)
    // RB_SWAPPED doesn't work with Basic. (bug ???????)
    // RB_SWAPPED doesn't work with D3D9. (bug ???????)
    bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC ||
                                 layersBackend == LayersBackend::LAYERS_D3D9 ||
                                 layersBackend == LayersBackend::LAYERS_D3D11;
    if (texClient->HasFlags(TextureFlags::RB_SWAPPED) &&
        layersNeedsManualSwap)
    {
      size_t pixels = width * height;
      uint8_t* itr = lockedBytes;
      for (size_t i = 0; i < pixels; i++) {
        SwapRB_R8G8B8A8(itr);
        itr += 4;
      }

      texClient->RemoveFlags(TextureFlags::RB_SWAPPED);
    }

    texClient->Unlock();
  }

  return texClient.forget();
}
Example #27
0
bool
ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
{
  AutoTArray<ImageContainer::OwningImage,4> images;
  uint32_t generationCounter;
  aContainer->GetCurrentImages(&images, &generationCounter);

  if (mLastUpdateGenerationCounter == generationCounter) {
    return true;
  }
  mLastUpdateGenerationCounter = generationCounter;

  for (int32_t i = images.Length() - 1; i >= 0; --i) {
    if (!images[i].mImage->IsValid()) {
      // Don't try to update to an invalid image.
      images.RemoveElementAt(i);
    }
  }
  if (images.IsEmpty()) {
    // This can happen if a ClearAllImages raced with SetCurrentImages from
    // another thread and ClearImagesFromImageBridge ran after the
    // SetCurrentImages call but before UpdateImageClientNow.
    // This can also happen if all images in the list are invalid.
    // We return true because the caller would attempt to recreate the
    // ImageClient otherwise, and that isn't going to help.
    return true;
  }

  nsTArray<Buffer> newBuffers;
  AutoTArray<CompositableForwarder::TimedTextureClient,4> textures;

  for (auto& img : images) {
    Image* image = img.mImage;

#ifdef MOZ_WIDGET_GONK
    if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) {
      OverlayImage* overlayImage = static_cast<OverlayImage*>(image);
      OverlaySource source;
      if (overlayImage->GetSidebandStream().IsValid()) {
        // Duplicate GonkNativeHandle::NhObj for ipc,
        // since ParamTraits<GonkNativeHandle>::Write() absorbs native_handle_t.
        RefPtr<GonkNativeHandle::NhObj> nhObj = overlayImage->GetSidebandStream().GetDupNhObj();
        GonkNativeHandle handle(nhObj);
        if (!handle.IsValid()) {
          gfxWarning() << "ImageClientSingle::UpdateImage failed in GetDupNhObj";
          return false;
        }
        source.handle() = OverlayHandle(handle);
      } else {
        source.handle() = OverlayHandle(overlayImage->GetOverlayId());
      }
      source.size() = overlayImage->GetSize();
      GetForwarder()->UseOverlaySource(this, source, image->GetPictureRect());
      continue;
    }
#endif

    RefPtr<TextureClient> texture = image->GetTextureClient(this);
    const bool hasTextureClient = !!texture;

    for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
      if (mBuffers[i].mImageSerial == image->GetSerial()) {
        if (hasTextureClient) {
          MOZ_ASSERT(image->GetTextureClient(this) == mBuffers[i].mTextureClient);
        } else {
          texture = mBuffers[i].mTextureClient;
        }
        // Remove this element from mBuffers so mBuffers only contains
        // images that aren't present in 'images'
        mBuffers.RemoveElementAt(i);
      }
    }

    if (!texture) {
      // Slow path, we should not be hitting it very often and if we do it means
      // we are using an Image class that is not backed by textureClient and we
      // should fix it.
      if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
        PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
        const PlanarYCbCrData* data = ycbcr->GetData();
        if (!data) {
          return false;
        }
        texture = TextureClient::CreateForYCbCr(GetForwarder(),
          data->mYSize, data->mCbCrSize, data->mStereoMode,
          TextureFlags::DEFAULT | mTextureFlags
        );
        if (!texture) {
          return false;
        }

        TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
        if (!autoLock.Succeeded()) {
          return false;
        }

        bool status = UpdateYCbCrTextureClient(texture, *data);
        MOZ_ASSERT(status);
        if (!status) {
          return false;
        }
      } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
                 image->GetFormat() == ImageFormat::EGLIMAGE) {
        gfx::IntSize size = image->GetSize();

        if (image->GetFormat() == ImageFormat::EGLIMAGE) {
          EGLImageImage* typedImage = image->AsEGLImageImage();
          texture = EGLImageTextureData::CreateTextureClient(
            typedImage, size, GetForwarder(), mTextureFlags);
#ifdef MOZ_WIDGET_ANDROID
        } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
          SurfaceTextureImage* typedImage = image->AsSurfaceTextureImage();
          texture = AndroidSurfaceTextureData::CreateTextureClient(
            typedImage->GetSurfaceTexture(), size, typedImage->GetOriginPos(),
            GetForwarder(), mTextureFlags
          );
#endif
        } else {
          MOZ_ASSERT(false, "Bad ImageFormat.");
        }
      } else {
        RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
        MOZ_ASSERT(surface);
        texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
                                                BackendSelector::Content, mTextureFlags);
        if (!texture) {
          return false;
        }

        MOZ_ASSERT(texture->CanExposeDrawTarget());

        if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
          return false;
        }

        {
          // We must not keep a reference to the DrawTarget after it has been unlocked.
          DrawTarget* dt = texture->BorrowDrawTarget();
          if (!dt) {
            gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
            return false;
          }
          MOZ_ASSERT(surface.get());
          dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
        }

        texture->Unlock();
      }
    }
    if (!texture || !AddTextureClient(texture)) {
      return false;
    }


    CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
    t->mTextureClient = texture;
    t->mTimeStamp = img.mTimeStamp;
    t->mPictureRect = image->GetPictureRect();
    t->mFrameID = img.mFrameID;
    t->mProducerID = img.mProducerID;

    Buffer* newBuf = newBuffers.AppendElement();
    newBuf->mImageSerial = image->GetSerial();
    newBuf->mTextureClient = texture;

    texture->SyncWithObject(GetForwarder()->GetSyncObject());
  }

  GetForwarder()->UseTextures(this, textures);

  for (auto& b : mBuffers) {
    RemoveTexture(b.mTextureClient);
  }
  mBuffers.SwapElements(newBuffers);

  return true;
}
  NS_IMETHOD
  Run() override
  {
    AssertIsOnMainThread();

    MutexAutoLock lock(mPromiseProxy->Lock());
    if (mPromiseProxy->CleanedUp()) {
      return NS_OK;
    }

#ifdef MOZ_WIDGET_ANDROID
    // This fires an intent that will start launching Fennec and foreground it,
    // if necessary.
    java::GeckoAppShell::OpenWindowForNotification();
#endif

    nsCOMPtr<nsPIDOMWindowOuter> window;
    nsresult rv = OpenWindow(getter_AddRefs(window));
    if (NS_SUCCEEDED(rv)) {
      MOZ_ASSERT(window);

      rv = nsContentUtils::DispatchFocusChromeEvent(window);
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
      }

      WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
      MOZ_ASSERT(workerPrivate);

      WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo();
      nsCOMPtr<nsIURI> baseURI;
      nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mHref);
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return NS_ERROR_FAILURE;
      }

      nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
      nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);

      if (!webProgress) {
        return NS_ERROR_FAILURE;
      }

      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
      MOZ_ASSERT(swm);

      nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
      MOZ_ASSERT(principal);
      RefPtr<ServiceWorkerRegistrationInfo> registration =
        swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
      if (NS_WARN_IF(!registration)) {
        return NS_ERROR_FAILURE;
      }
      RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
        registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID());
      if (NS_WARN_IF(!serviceWorkerInfo)) {
        return NS_ERROR_FAILURE;
      }

      nsCOMPtr<nsIWebProgressListener> listener =
        new WebProgressListener(mPromiseProxy, serviceWorkerInfo->WorkerPrivate(),
                                window, baseURI);

      rv = webProgress->AddProgressListener(listener,
                                            nsIWebProgress::NOTIFY_STATE_DOCUMENT);
      MOZ_ASSERT(NS_SUCCEEDED(rv));
      return NS_OK;
    }
#ifdef MOZ_WIDGET_ANDROID
    else if (rv == NS_ERROR_NOT_AVAILABLE) {
      // We couldn't get a browser window, so Fennec must not be running.
      // Send an Intent to launch Fennec and wait for "BrowserChrome:Ready"
      // to try opening a window again.
      nsCOMPtr<nsIObserverService> os = services::GetObserverService();
      NS_ENSURE_STATE(os);

      WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
      MOZ_ASSERT(workerPrivate);

      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
      MOZ_ASSERT(swm);

      nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
      MOZ_ASSERT(principal);

      RefPtr<ServiceWorkerRegistrationInfo> registration =
        swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
      if (NS_WARN_IF(!registration)) {
        return NS_ERROR_FAILURE;
      }

      RefPtr<ServiceWorkerInfo> serviceWorkerInfo =
        registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID());
      if (NS_WARN_IF(!serviceWorkerInfo)) {
        return NS_ERROR_FAILURE;
      }

      os->AddObserver(static_cast<nsIObserver*>(serviceWorkerInfo->WorkerPrivate()),
                      "BrowserChrome:Ready", true);
      serviceWorkerInfo->WorkerPrivate()->AddPendingWindow(this);
      return NS_OK;
    }
#endif

    RefPtr<ResolveOpenWindowRunnable> resolveRunnable =
      new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv);

    Unused << NS_WARN_IF(!resolveRunnable->Dispatch());

    return NS_OK;
  }