Commit bbd47dd2 authored by miu's avatar miu Committed by Commit bot

Clean-up: Break sampler classes into their own files.

BUG=156767

Review URL: https://codereview.chromium.org/1109603003

Cr-Commit-Position: refs/heads/master@{#327175}
parent 21ef84dc
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/media/capture/animated_content_sampler.h"
#include <algorithm>
namespace content {
namespace {
// These specify the minimum/maximum amount of recent event history to examine
// to detect animated content. If the values are too low, there is a greater
// risk of false-positive detections and low accuracy. If they are too high,
// the the implementation will be slow to lock-in/out, and also will not react
// well to mildly-variable frame rate content (e.g., 25 +/- 1 FPS).
//
// These values were established by experimenting with a wide variety of
// scenarios, including 24/25/30 FPS videos, 60 FPS WebGL demos, and the
// transitions between static and animated content.
const int kMinObservationWindowMillis = 1000;
const int kMaxObservationWindowMillis = 2000;
// The maximum amount of time that can elapse before declaring two subsequent
// events as "not animating." This is the same value found in
// cc::FrameRateCounter.
const int kNonAnimatingThresholdMillis = 250; // 4 FPS
// The slowest that content can be animating in order for AnimatedContentSampler
// to lock-in. This is the threshold at which the "smoothness" problem is no
// longer relevant.
const int kMaxLockInPeriodMicros = 83333; // 12 FPS
// The amount of time over which to fully correct the drift of the rewritten
// frame timestamps from the presentation event timestamps. The lower the
// value, the higher the variance in frame timestamps.
const int kDriftCorrectionMillis = 2000;
} // anonymous namespace
AnimatedContentSampler::AnimatedContentSampler(
base::TimeDelta min_capture_period)
: min_capture_period_(min_capture_period) {}
AnimatedContentSampler::~AnimatedContentSampler() {}
void AnimatedContentSampler::ConsiderPresentationEvent(
const gfx::Rect& damage_rect, base::TimeTicks event_time) {
AddObservation(damage_rect, event_time);
if (AnalyzeObservations(event_time, &detected_region_, &detected_period_) &&
detected_period_ > base::TimeDelta() &&
detected_period_ <=
base::TimeDelta::FromMicroseconds(kMaxLockInPeriodMicros)) {
if (damage_rect == detected_region_)
UpdateFrameTimestamp(event_time);
else
frame_timestamp_ = base::TimeTicks();
} else {
detected_region_ = gfx::Rect();
detected_period_ = base::TimeDelta();
frame_timestamp_ = base::TimeTicks();
}
}
bool AnimatedContentSampler::HasProposal() const {
return detected_period_ > base::TimeDelta();
}
bool AnimatedContentSampler::ShouldSample() const {
return !frame_timestamp_.is_null();
}
void AnimatedContentSampler::RecordSample(base::TimeTicks frame_timestamp) {
recorded_frame_timestamp_ =
HasProposal() ? frame_timestamp : base::TimeTicks();
sequence_offset_ = base::TimeDelta();
}
void AnimatedContentSampler::AddObservation(const gfx::Rect& damage_rect,
base::TimeTicks event_time) {
if (damage_rect.IsEmpty())
return; // Useless observation.
// Add the observation to the FIFO queue.
if (!observations_.empty() && observations_.back().event_time > event_time)
return; // The implementation assumes chronological order.
observations_.push_back(Observation(damage_rect, event_time));
// Prune-out old observations.
const base::TimeDelta threshold =
base::TimeDelta::FromMilliseconds(kMaxObservationWindowMillis);
while ((event_time - observations_.front().event_time) > threshold)
observations_.pop_front();
}
gfx::Rect AnimatedContentSampler::ElectMajorityDamageRect() const {
// This is an derivative of the Boyer-Moore Majority Vote Algorithm where each
// pixel in a candidate gets one vote, as opposed to each candidate getting
// one vote.
const gfx::Rect* candidate = NULL;
int64 votes = 0;
for (ObservationFifo::const_iterator i = observations_.begin();
i != observations_.end(); ++i) {
DCHECK_GT(i->damage_rect.size().GetArea(), 0);
if (votes == 0) {
candidate = &(i->damage_rect);
votes = candidate->size().GetArea();
} else if (i->damage_rect == *candidate) {
votes += i->damage_rect.size().GetArea();
} else {
votes -= i->damage_rect.size().GetArea();
if (votes < 0) {
candidate = &(i->damage_rect);
votes = -votes;
}
}
}
return (votes > 0) ? *candidate : gfx::Rect();
}
bool AnimatedContentSampler::AnalyzeObservations(
base::TimeTicks event_time,
gfx::Rect* rect,
base::TimeDelta* period) const {
const gfx::Rect elected_rect = ElectMajorityDamageRect();
if (elected_rect.IsEmpty())
return false; // There is no regular animation present.
// Scan |observations_|, gathering metrics about the ones having a damage Rect
// equivalent to the |elected_rect|. Along the way, break early whenever the
// event times reveal a non-animating period.
int64 num_pixels_damaged_in_all = 0;
int64 num_pixels_damaged_in_chosen = 0;
base::TimeDelta sum_frame_durations;
size_t count_frame_durations = 0;
base::TimeTicks first_event_time;
base::TimeTicks last_event_time;
for (ObservationFifo::const_reverse_iterator i = observations_.rbegin();
i != observations_.rend(); ++i) {
const int area = i->damage_rect.size().GetArea();
num_pixels_damaged_in_all += area;
if (i->damage_rect != elected_rect)
continue;
num_pixels_damaged_in_chosen += area;
if (last_event_time.is_null()) {
last_event_time = i->event_time;
if ((event_time - last_event_time) >=
base::TimeDelta::FromMilliseconds(kNonAnimatingThresholdMillis)) {
return false; // Content animation has recently ended.
}
} else {
const base::TimeDelta frame_duration = first_event_time - i->event_time;
if (frame_duration >=
base::TimeDelta::FromMilliseconds(kNonAnimatingThresholdMillis)) {
break; // Content not animating before this point.
}
sum_frame_durations += frame_duration;
++count_frame_durations;
}
first_event_time = i->event_time;
}
if ((last_event_time - first_event_time) <
base::TimeDelta::FromMilliseconds(kMinObservationWindowMillis)) {
return false; // Content has not animated for long enough for accuracy.
}
if (num_pixels_damaged_in_chosen <= (num_pixels_damaged_in_all * 2 / 3))
return false; // Animation is not damaging a supermajority of pixels.
*rect = elected_rect;
DCHECK_GT(count_frame_durations, 0u);
*period = sum_frame_durations / count_frame_durations;
return true;
}
void AnimatedContentSampler::UpdateFrameTimestamp(base::TimeTicks event_time) {
// This is how much time to advance from the last frame timestamp. Never
// advance by less than |min_capture_period_| because the downstream consumer
// cannot handle the higher frame rate. If |detected_period_| is less than
// |min_capture_period_|, excess frames should be dropped.
const base::TimeDelta advancement =
std::max(detected_period_, min_capture_period_);
// Compute the |timebase| upon which to determine the |frame_timestamp_|.
// Ideally, this would always equal the timestamp of the last recorded frame
// sampling. Determine how much drift from the ideal is present, then adjust
// the timebase by a small amount to spread out the entire correction over
// many frame timestamps.
//
// This accounts for two main sources of drift: 1) The clock drift of the
// system clock relative to the video hardware, which affects the event times;
// and 2) The small error introduced by this frame timestamp rewriting, as it
// is based on averaging over recent events.
base::TimeTicks timebase = event_time - sequence_offset_ - advancement;
if (!recorded_frame_timestamp_.is_null()) {
const base::TimeDelta drift = recorded_frame_timestamp_ - timebase;
const int64 correct_over_num_frames =
base::TimeDelta::FromMilliseconds(kDriftCorrectionMillis) /
detected_period_;
DCHECK_GT(correct_over_num_frames, 0);
timebase = recorded_frame_timestamp_ - (drift / correct_over_num_frames);
}
// Compute |frame_timestamp_|. Whenever |detected_period_| is less than
// |min_capture_period_|, some extra time is "borrowed" to be able to advance
// by the full |min_capture_period_|. Then, whenever the total amount of
// borrowed time reaches a full |min_capture_period_|, drop a frame. Note
// that when |detected_period_| is greater or equal to |min_capture_period_|,
// this logic is effectively disabled.
borrowed_time_ += advancement - detected_period_;
if (borrowed_time_ >= min_capture_period_) {
borrowed_time_ -= min_capture_period_;
frame_timestamp_ = base::TimeTicks();
} else {
sequence_offset_ += advancement;
frame_timestamp_ = timebase + sequence_offset_;
}
}
} // namespace content
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_ANIMATED_CONTENT_SAMPLER_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_ANIMATED_CONTENT_SAMPLER_H_
#include <deque>
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "ui/gfx/geometry/rect.h"
namespace content {
// Analyzes a sequence of events to detect the presence of constant frame rate
// animated content. In the case where there are multiple regions of animated
// content, AnimatedContentSampler will propose sampling the one having the
// largest "smoothness" impact, according to human perception (e.g., a 24 FPS
// video versus a 60 FPS busy spinner).
//
// In addition, AnimatedContentSampler will provide rewritten frame timestamps,
// for downstream consumers, that are "truer" to the source content than to the
// local presentation hardware.
class CONTENT_EXPORT AnimatedContentSampler {
public:
explicit AnimatedContentSampler(base::TimeDelta min_capture_period);
~AnimatedContentSampler();
// Examines the given presentation event metadata, along with recent history,
// to detect animated content, updating the state of this sampler.
// |damage_rect| is the region of a frame about to be drawn, while
// |event_time| refers to the frame's estimated presentation time.
void ConsiderPresentationEvent(const gfx::Rect& damage_rect,
base::TimeTicks event_time);
// Returns true if animated content has been detected and a decision has been
// made about whether to sample the last event.
bool HasProposal() const;
// Returns true if the last event considered should be sampled.
bool ShouldSample() const;
// Returns a frame timestamp to provide to consumers of the sampled frame.
// Only valid when should_sample() returns true.
base::TimeTicks frame_timestamp() const { return frame_timestamp_; }
// Accessors to currently-detected animating region/period, for logging.
const gfx::Rect& detected_region() const { return detected_region_; }
base::TimeDelta detected_period() const { return detected_period_; }
// Records that a frame with the given |frame_timestamp| was sampled. This
// method should be called when *any* sampling is taken, even if it was not
// proposed by AnimatedContentSampler.
void RecordSample(base::TimeTicks frame_timestamp);
private:
friend class AnimatedContentSamplerTest;
// Data structure for efficient online analysis of recent event history.
struct Observation {
gfx::Rect damage_rect;
base::TimeTicks event_time;
Observation(const gfx::Rect& d, base::TimeTicks e)
: damage_rect(d), event_time(e) {}
};
typedef std::deque<Observation> ObservationFifo;
// Adds an observation to |observations_|, and prunes-out the old ones.
void AddObservation(const gfx::Rect& damage_rect, base::TimeTicks event_time);
// Returns the damage Rect that is responsible for the majority of the pixel
// damage in recent event history, if there is such a Rect. If there isn't,
// this method could still return any Rect, so the caller must confirm the
// returned Rect really is responsible for the majority of pixel damage.
gfx::Rect ElectMajorityDamageRect() const;
// Analyzes the observations relative to the current |event_time| to detect
// stable animating content. If detected, returns true and sets the output
// arguments to the region of the animating content and its mean frame
// duration.
bool AnalyzeObservations(base::TimeTicks event_time,
gfx::Rect* rect,
base::TimeDelta* period) const;
// Called by ConsiderPresentationEvent() when the current event is part of a
// detected animation, to update |frame_timestamp_|.
void UpdateFrameTimestamp(base::TimeTicks event_time);
// The client expects frame timestamps to be at least this far apart.
const base::TimeDelta min_capture_period_;
// A recent history of observations in chronological order, maintained by
// AddObservation().
ObservationFifo observations_;
// The region of currently-detected animated content. If empty, that means
// "not detected."
gfx::Rect detected_region_;
// The mean frame duration of currently-detected animated content. If zero,
// that means "not detected."
base::TimeDelta detected_period_;
// The rewritten frame timestamp for the latest event.
base::TimeTicks frame_timestamp_;
// The frame timestamp provided in the last call to RecordSample(). This
// timestamp may or may not have been one proposed by AnimatedContentSampler.
base::TimeTicks recorded_frame_timestamp_;
// Accumulates all the time advancements since the last call to
// RecordSample(). When this is greater than zero, there have been one or
// more events proposed for sampling, but not yet recorded. This accounts for
// the cases where AnimatedContentSampler indicates a frame should be sampled,
// but the client chooses not to do so.
base::TimeDelta sequence_offset_;
// A token bucket that is used to decide which frames to drop whenever
// |detected_period_| is less than |min_capture_period_|.
base::TimeDelta borrowed_time_;
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURE_ANIMATED_CONTENT_SAMPLER_H_
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/media/capture/smooth_event_sampler.h"
#include <algorithm>
#include "base/trace_event/trace_event.h"
namespace content {
namespace {
// The maximum amount of time that can elapse before considering unchanged
// content as dirty for the purposes of timer-based overdue sampling. This is
// the same value found in cc::FrameRateCounter.
const int kOverdueDirtyThresholdMillis = 250; // 4 FPS
} // anonymous namespace
SmoothEventSampler::SmoothEventSampler(base::TimeDelta min_capture_period,
int redundant_capture_goal)
: min_capture_period_(min_capture_period),
redundant_capture_goal_(redundant_capture_goal),
token_bucket_capacity_(min_capture_period + min_capture_period / 2),
overdue_sample_count_(0),
token_bucket_(token_bucket_capacity_) {
DCHECK_GT(min_capture_period_.InMicroseconds(), 0);
}
void SmoothEventSampler::ConsiderPresentationEvent(base::TimeTicks event_time) {
DCHECK(!event_time.is_null());
// Add tokens to the bucket based on advancement in time. Then, re-bound the
// number of tokens in the bucket. Overflow occurs when there is too much
// time between events (a common case), or when RecordSample() is not being
// called often enough (a bug). On the other hand, if RecordSample() is being
// called too often (e.g., as a reaction to IsOverdueForSamplingAt()), the
// bucket will underflow.
if (!current_event_.is_null()) {
if (current_event_ < event_time) {
token_bucket_ += event_time - current_event_;
if (token_bucket_ > token_bucket_capacity_)
token_bucket_ = token_bucket_capacity_;
}
TRACE_COUNTER1("gpu.capture",
"MirroringTokenBucketUsec",
std::max<int64>(0, token_bucket_.InMicroseconds()));
}
current_event_ = event_time;
}
bool SmoothEventSampler::ShouldSample() const {
return token_bucket_ >= min_capture_period_;
}
void SmoothEventSampler::RecordSample() {
token_bucket_ -= min_capture_period_;
if (token_bucket_ < base::TimeDelta())
token_bucket_ = base::TimeDelta();
TRACE_COUNTER1("gpu.capture",
"MirroringTokenBucketUsec",
std::max<int64>(0, token_bucket_.InMicroseconds()));
if (HasUnrecordedEvent()) {
last_sample_ = current_event_;
overdue_sample_count_ = 0;
} else {
++overdue_sample_count_;
}
}
bool SmoothEventSampler::IsOverdueForSamplingAt(base::TimeTicks event_time)
const {
DCHECK(!event_time.is_null());
if (!HasUnrecordedEvent() && overdue_sample_count_ >= redundant_capture_goal_)
return false; // Not dirty.
if (last_sample_.is_null())
return true;
// If we're dirty but not yet old, then we've recently gotten updates, so we
// won't request a sample just yet.
base::TimeDelta dirty_interval = event_time - last_sample_;
return dirty_interval >=
base::TimeDelta::FromMilliseconds(kOverdueDirtyThresholdMillis);
}
bool SmoothEventSampler::HasUnrecordedEvent() const {
return !current_event_.is_null() && current_event_ != last_sample_;
}
} // namespace content
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_SMOOTH_EVENT_SAMPLER_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_SMOOTH_EVENT_SAMPLER_H_
#include "base/time/time.h"
#include "content/common/content_export.h"
namespace content {
// Filters a sequence of events to achieve a target frequency.
class CONTENT_EXPORT SmoothEventSampler {
public:
SmoothEventSampler(base::TimeDelta min_capture_period,
int redundant_capture_goal);
base::TimeDelta min_capture_period() const { return min_capture_period_; }
// Add a new event to the event history, and consider whether it ought to be
// sampled. The event is not recorded as a sample until RecordSample() is
// called.
void ConsiderPresentationEvent(base::TimeTicks event_time);
// Returns true if the last event considered should be sampled.
bool ShouldSample() const;
// Operates on the last event added by ConsiderPresentationEvent(), marking
// it as sampled. After this point we are current in the stream of events, as
// we have sampled the most recent event.
void RecordSample();
// Returns true if, at time |event_time|, sampling should occur because too
// much time will have passed relative to the last event and/or sample.
bool IsOverdueForSamplingAt(base::TimeTicks event_time) const;
// Returns true if ConsiderPresentationEvent() has been called since the last
// call to RecordSample().
bool HasUnrecordedEvent() const;
private:
const base::TimeDelta min_capture_period_;
const int redundant_capture_goal_;
const base::TimeDelta token_bucket_capacity_;
base::TimeTicks current_event_;
base::TimeTicks last_sample_;
int overdue_sample_count_;
base::TimeDelta token_bucket_;
DISALLOW_COPY_AND_ASSIGN(SmoothEventSampler);
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURE_SMOOTH_EVENT_SAMPLER_H_
This diff is collapsed.
......@@ -5,167 +5,16 @@
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_ORACLE_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_ORACLE_H_
#include <deque>
#include "base/callback_forward.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "content/browser/media/capture/animated_content_sampler.h"
#include "content/browser/media/capture/smooth_event_sampler.h"
#include "content/common/content_export.h"
#include "ui/gfx/geometry/rect.h"
namespace content {
// Filters a sequence of events to achieve a target frequency.
class CONTENT_EXPORT SmoothEventSampler {
public:
SmoothEventSampler(base::TimeDelta min_capture_period,
int redundant_capture_goal);
base::TimeDelta min_capture_period() const { return min_capture_period_; }
// Add a new event to the event history, and consider whether it ought to be
// sampled. The event is not recorded as a sample until RecordSample() is
// called.
void ConsiderPresentationEvent(base::TimeTicks event_time);
// Returns true if the last event considered should be sampled.
bool ShouldSample() const;
// Operates on the last event added by ConsiderPresentationEvent(), marking
// it as sampled. After this point we are current in the stream of events, as
// we have sampled the most recent event.
void RecordSample();
// Returns true if, at time |event_time|, sampling should occur because too
// much time will have passed relative to the last event and/or sample.
bool IsOverdueForSamplingAt(base::TimeTicks event_time) const;
// Returns true if ConsiderPresentationEvent() has been called since the last
// call to RecordSample().
bool HasUnrecordedEvent() const;
private:
const base::TimeDelta min_capture_period_;
const int redundant_capture_goal_;
const base::TimeDelta token_bucket_capacity_;
base::TimeTicks current_event_;
base::TimeTicks last_sample_;
int overdue_sample_count_;
base::TimeDelta token_bucket_;
DISALLOW_COPY_AND_ASSIGN(SmoothEventSampler);
};
// Analyzes a sequence of events to detect the presence of constant frame rate
// animated content. In the case where there are multiple regions of animated
// content, AnimatedContentSampler will propose sampling the one having the
// largest "smoothness" impact, according to human perception (e.g., a 24 FPS
// video versus a 60 FPS busy spinner).
//
// In addition, AnimatedContentSampler will provide rewritten frame timestamps,
// for downstream consumers, that are "truer" to the source content than to the
// local presentation hardware.
class CONTENT_EXPORT AnimatedContentSampler {
public:
explicit AnimatedContentSampler(base::TimeDelta min_capture_period);
~AnimatedContentSampler();
// Examines the given presentation event metadata, along with recent history,
// to detect animated content, updating the state of this sampler.
// |damage_rect| is the region of a frame about to be drawn, while
// |event_time| refers to the frame's estimated presentation time.
void ConsiderPresentationEvent(const gfx::Rect& damage_rect,
base::TimeTicks event_time);
// Returns true if animated content has been detected and a decision has been
// made about whether to sample the last event.
bool HasProposal() const;
// Returns true if the last event considered should be sampled.
bool ShouldSample() const;
// Returns a frame timestamp to provide to consumers of the sampled frame.
// Only valid when should_sample() returns true.
base::TimeTicks frame_timestamp() const { return frame_timestamp_; }
// Accessors to currently-detected animating region/period, for logging.
const gfx::Rect& detected_region() const { return detected_region_; }
base::TimeDelta detected_period() const { return detected_period_; }
// Records that a frame with the given |frame_timestamp| was sampled. This
// method should be called when *any* sampling is taken, even if it was not
// proposed by AnimatedContentSampler.
void RecordSample(base::TimeTicks frame_timestamp);
private:
friend class AnimatedContentSamplerTest;
// Data structure for efficient online analysis of recent event history.
struct Observation {
gfx::Rect damage_rect;
base::TimeTicks event_time;
Observation(const gfx::Rect& d, base::TimeTicks e)
: damage_rect(d), event_time(e) {}
};
typedef std::deque<Observation> ObservationFifo;
// Adds an observation to |observations_|, and prunes-out the old ones.
void AddObservation(const gfx::Rect& damage_rect, base::TimeTicks event_time);
// Returns the damage Rect that is responsible for the majority of the pixel
// damage in recent event history, if there is such a Rect. If there isn't,
// this method could still return any Rect, so the caller must confirm the
// returned Rect really is responsible for the majority of pixel damage.
gfx::Rect ElectMajorityDamageRect() const;
// Analyzes the observations relative to the current |event_time| to detect
// stable animating content. If detected, returns true and sets the output
// arguments to the region of the animating content and its mean frame
// duration.
bool AnalyzeObservations(base::TimeTicks event_time,
gfx::Rect* rect,
base::TimeDelta* period) const;
// Called by ConsiderPresentationEvent() when the current event is part of a
// detected animation, to update |frame_timestamp_|.
void UpdateFrameTimestamp(base::TimeTicks event_time);
// The client expects frame timestamps to be at least this far apart.
const base::TimeDelta min_capture_period_;
// A recent history of observations in chronological order, maintained by
// AddObservation().
ObservationFifo observations_;
// The region of currently-detected animated content. If empty, that means
// "not detected."
gfx::Rect detected_region_;
// The mean frame duration of currently-detected animated content. If zero,
// that means "not detected."
base::TimeDelta detected_period_;
// The rewritten frame timestamp for the latest event.
base::TimeTicks frame_timestamp_;
// The frame timestamp provided in the last call to RecordSample(). This
// timestamp may or may not have been one proposed by AnimatedContentSampler.
base::TimeTicks recorded_frame_timestamp_;
// Accumulates all the time advancements since the last call to
// RecordSample(). When this is greater than zero, there have been one or
// more events proposed for sampling, but not yet recorded. This accounts for
// the cases where AnimatedContentSampler indicates a frame should be sampled,
// but the client chooses not to do so.
base::TimeDelta sequence_offset_;
// A token bucket that is used to decide which frames to drop whenever
// |detected_period_| is less than |min_capture_period_|.
base::TimeDelta borrowed_time_;
};
// VideoCaptureOracle manages the producer-side throttling of captured frames
// from a video capture device. It is informed of every update by the device;
// this empowers it to look into the future and decide if a particular frame
......
......@@ -966,10 +966,14 @@
'browser/media/audio_state_provider.h',
'browser/media/audio_stream_monitor.cc',
'browser/media/audio_stream_monitor.h',
'browser/media/capture/animated_content_sampler.cc',
'browser/media/capture/animated_content_sampler.h',
'browser/media/capture/audio_mirroring_manager.cc',
'browser/media/capture/audio_mirroring_manager.h',
'browser/media/capture/content_video_capture_device_core.cc',
'browser/media/capture/content_video_capture_device_core.h',
'browser/media/capture/smooth_event_sampler.cc',
'browser/media/capture/smooth_event_sampler.h',
'browser/media/capture/video_capture_oracle.cc',
'browser/media/capture/video_capture_oracle.h',
'browser/media/capture/web_contents_audio_input_stream.cc',
......
......@@ -468,7 +468,9 @@
'browser/loader/upload_data_stream_builder_unittest.cc',
'browser/mach_broker_mac_unittest.cc',
'browser/media/audio_stream_monitor_unittest.cc',
'browser/media/capture/animated_content_sampler_unittest.cc',
'browser/media/capture/audio_mirroring_manager_unittest.cc',
'browser/media/capture/smooth_event_sampler_unittest.cc',
'browser/media/capture/video_capture_oracle_unittest.cc',
'browser/media/capture/web_contents_audio_input_stream_unittest.cc',
'browser/media/capture/web_contents_video_capture_device_unittest.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment