summaryrefslogtreecommitdiffstats
path: root/gfx/layers/CompositionRecorder.cpp
blob: f4bef815e76fad3e88585ef0f434be10816e7341 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* -*- 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 <ctime>
#include <iomanip>
#include "stdio.h"
#ifdef XP_WIN
#  include "direct.h"
#else
#  include <sys/types.h>
#  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::NowUnfuzzed() 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::NowUnfuzzed() - mRecordingStart;
  recordingStartTime.AppendFloat(
      static_cast<double>(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<RecordedFrame>& frame : mCollectedFrames) {
    RefPtr<DataSourceSurface> 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<CollectedFrame> frames;

  TimeDuration delta = TimeStamp::NowUnfuzzed() - mRecordingStart;
  double recordingStart = PR_Now() / 1000.0 - delta.ToMilliseconds();

  for (RefPtr<RecordedFrame>& frame : mCollectedFrames) {
    nsCString buffer;

    RefPtr<DataSourceSurface> 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