/* -*- 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) { mCollectedFrames.AppendElement(aFrame); } void CompositionRecorder::WriteCollectedFrames() { // The directory has the format of // "[LayersWindowRecordingPath]/windowrecording-[mRecordingStartTime as unix // timestamp]". We need mRecordingStart as a unix timestamp here because we // want the consumer of these files to be able to compute an absolute // timestamp of each screenshot, so that we can align screenshots with timed // data from other sources, such as Gecko profiler information. The time of // each screenshot is part of the screenshot's filename, expressed as // milliseconds *relative to mRecordingStart*. We want to compute the number // of milliseconds between midnight 1 January 1970 UTC and mRecordingStart, // unfortunately, mozilla::TimeStamp does not have a built-in way of doing // that. However, PR_Now() returns the number of microseconds since midnight 1 // January 1970 UTC. We call PR_Now() and TimeStamp::Now() very // closely to each other so that they return their representation of "the same // time", and then compute (Now - (Now - mRecordingStart)). std::stringstream str; nsCString recordingStartTime; TimeDuration delta = TimeStamp::Now() - mRecordingStart; recordingStartTime.AppendFloat( static_cast(PR_Now() / 1000.0 - delta.ToMilliseconds())); str << gfxVars::LayersWindowRecordingPath() << "windowrecording-" << recordingStartTime; #ifdef XP_WIN _mkdir(str.str().c_str()); #else mkdir(str.str().c_str(), 0777); #endif uint32_t i = 1; for (RefPtr& frame : mCollectedFrames) { RefPtr surf = frame->GetSourceSurface(); std::stringstream filename; filename << str.str() << "/frame-" << i << "-" << uint32_t( (frame->GetTimeStamp() - mRecordingStart).ToMilliseconds()) << ".png"; gfxUtils::WriteAsPNG(surf, filename.str().c_str()); i++; } mCollectedFrames.Clear(); } CollectedFrames CompositionRecorder::GetCollectedFrames() { nsTArray frames; TimeDuration delta = TimeStamp::Now() - mRecordingStart; double recordingStart = PR_Now() / 1000.0 - delta.ToMilliseconds(); for (RefPtr& frame : mCollectedFrames) { nsCString buffer; RefPtr surf = frame->GetSourceSurface(); double offset = (frame->GetTimeStamp() - mRecordingStart).ToMilliseconds(); gfxUtils::EncodeSourceSurface(surf, ImageType::PNG, u""_ns, gfxUtils::eDataURIEncode, nullptr, &buffer); frames.EmplaceBack(offset, std::move(buffer)); } mCollectedFrames.Clear(); return CollectedFrames(recordingStart, std::move(frames)); } void CompositionRecorder::ClearCollectedFrames() { mCollectedFrames.Clear(); } } // namespace layers } // namespace mozilla