summaryrefslogtreecommitdiffstats
path: root/media/base/video_frame_pool.cc
blob: 40611eedc8c82873c3883f941ddfdb85ab72327b (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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2013 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 "media/base/video_frame_pool.h"

#include <list>

#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"

namespace media {

class VideoFramePool::PoolImpl
    : public base::RefCountedThreadSafe<VideoFramePool::PoolImpl> {
 public:
  PoolImpl();

  // See VideoFramePool::CreateFrame() for usage.
  scoped_refptr<VideoFrame> CreateFrame(VideoPixelFormat format,
                                        const gfx::Size& coded_size,
                                        const gfx::Rect& visible_rect,
                                        const gfx::Size& natural_size,
                                        base::TimeDelta timestamp);

  // Shuts down the frame pool and releases all frames in |frames_|.
  // Once this is called frames will no longer be inserted back into
  // |frames_|.
  void Shutdown();

  size_t GetPoolSizeForTesting() const { return frames_.size(); }

 private:
  friend class base::RefCountedThreadSafe<VideoFramePool::PoolImpl>;
  ~PoolImpl();

  // Called when the frame wrapper gets destroyed.
  // |frame| is the actual frame that was wrapped and is placed
  // in |frames_| by this function so it can be reused.
  void FrameReleased(const scoped_refptr<VideoFrame>& frame);

  base::Lock lock_;
  bool is_shutdown_;
  std::list<scoped_refptr<VideoFrame> > frames_;

  DISALLOW_COPY_AND_ASSIGN(PoolImpl);
};

VideoFramePool::PoolImpl::PoolImpl() : is_shutdown_(false) {}

VideoFramePool::PoolImpl::~PoolImpl() {
  DCHECK(is_shutdown_);
}

scoped_refptr<VideoFrame> VideoFramePool::PoolImpl::CreateFrame(
    VideoPixelFormat format,
    const gfx::Size& coded_size,
    const gfx::Rect& visible_rect,
    const gfx::Size& natural_size,
    base::TimeDelta timestamp) {
  base::AutoLock auto_lock(lock_);
  DCHECK(!is_shutdown_);

  scoped_refptr<VideoFrame> frame;
  while (!frame.get() && !frames_.empty()) {
      scoped_refptr<VideoFrame> pool_frame = frames_.front();
      frames_.pop_front();

      if (pool_frame->format() == format &&
          pool_frame->coded_size() == coded_size &&
          pool_frame->visible_rect() == visible_rect &&
          pool_frame->natural_size() == natural_size) {
        frame = pool_frame;
        frame->set_timestamp(timestamp);
        frame->metadata()->Clear();
        break;
      }
  }

  if (!frame.get()) {
    frame = VideoFrame::CreateZeroInitializedFrame(
        format, coded_size, visible_rect, natural_size, timestamp);
    LOG_IF(ERROR, !frame.get()) << "Failed to create a video frame";
  }

  scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame(
      frame, frame->visible_rect(), frame->natural_size());
  wrapped_frame->AddDestructionObserver(
      base::Bind(&VideoFramePool::PoolImpl::FrameReleased, this, frame));
  return wrapped_frame;
}

void VideoFramePool::PoolImpl::Shutdown() {
  base::AutoLock auto_lock(lock_);
  is_shutdown_ = true;
  frames_.clear();
}

void VideoFramePool::PoolImpl::FrameReleased(
    const scoped_refptr<VideoFrame>& frame) {
  base::AutoLock auto_lock(lock_);
  if (is_shutdown_)
    return;

  frames_.push_back(frame);
}

VideoFramePool::VideoFramePool() : pool_(new PoolImpl()) {
}

VideoFramePool::~VideoFramePool() {
  pool_->Shutdown();
}

scoped_refptr<VideoFrame> VideoFramePool::CreateFrame(
    VideoPixelFormat format,
    const gfx::Size& coded_size,
    const gfx::Rect& visible_rect,
    const gfx::Size& natural_size,
    base::TimeDelta timestamp) {
  return pool_->CreateFrame(format, coded_size, visible_rect, natural_size,
                            timestamp);
}

size_t VideoFramePool::GetPoolSizeForTesting() const {
  return pool_->GetPoolSizeForTesting();
}

}  // namespace media