/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CompositionRecorder.h" #include "gfxUtils.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/gfxVars.h" #include "nsIInputStream.h" #include "nsIBinaryOutputStream.h" #include "nsIObjectOutputStream.h" #include "prtime.h" #include #include #include "stdio.h" #ifdef XP_WIN # include "direct.h" #else # include # include "sys/stat.h" #endif using namespace mozilla::gfx; namespace mozilla { namespace layers { CompositionRecorder::CompositionRecorder(TimeStamp aRecordingStart) : mRecordingStart(aRecordingStart) {} void CompositionRecorder::RecordFrame(RecordedFrame* aFrame) { mRecordedFrames.AppendElement(aFrame); } Maybe CompositionRecorder::GetRecording() { FrameRecording recording; recording.startTime() = mRecordingStart; nsTArray bytes; for (RefPtr& recordedFrame : mRecordedFrames) { RefPtr surf = recordedFrame->GetSourceSurface(); if (!surf) { return Nothing(); } nsCOMPtr imgStream; nsresult rv = gfxUtils::EncodeSourceSurfaceAsStream( surf, ImageType::PNG, u""_ns, getter_AddRefs(imgStream)); if (NS_FAILED(rv)) { return Nothing(); } uint64_t bufSize64; rv = imgStream->Available(&bufSize64); if (NS_FAILED(rv) || bufSize64 > UINT32_MAX) { return Nothing(); } const uint32_t frameLength = static_cast(bufSize64); size_t startIndex = bytes.Length(); bytes.SetLength(startIndex + frameLength); uint8_t* bytePtr = &bytes[startIndex]; uint32_t bytesLeft = frameLength; while (bytesLeft > 0) { uint32_t bytesRead = 0; rv = imgStream->Read(reinterpret_cast(bytePtr), bytesLeft, &bytesRead); if (NS_FAILED(rv) || bytesRead == 0) { return Nothing(); } bytePtr += bytesRead; bytesLeft -= bytesRead; } #ifdef DEBUG // Currently, all implementers of imgIEncoder report their exact size // through nsIInputStream::Available(), but let's explicitly state that we // rely on that behavior for the algorithm above. char dummy = 0; uint32_t bytesRead = 0; rv = imgStream->Read(&dummy, 1, &bytesRead); MOZ_ASSERT(NS_SUCCEEDED(rv) && bytesRead == 0); #endif RecordedFrameData frameData; frameData.timeOffset() = recordedFrame->GetTimeStamp(); frameData.length() = frameLength; recording.frames().AppendElement(std::move(frameData)); // Now that we're done, release the frame so we can free up its memory recordedFrame = nullptr; } mRecordedFrames.Clear(); recording.bytes() = ipc::BigBuffer(bytes); return Some(std::move(recording)); } } // namespace layers } // namespace mozilla