1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "media/base/video_frame_pool.h"
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <list>
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/bind.h"
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/memory/ref_counted.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/synchronization/lock.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace media {
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class VideoFramePool::PoolImpl
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : public base::RefCountedThreadSafe<VideoFramePool::PoolImpl> {
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  PoolImpl();
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Returns a frame from the pool that matches the specified
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // parameters or creates a new frame if no suitable frame exists in
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // the pool. The pool is drained if no matching frame is found.
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_refptr<VideoFrame> CreateFrame(VideoFrame::Format format,
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                        const gfx::Size& coded_size,
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                        const gfx::Rect& visible_rect,
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                        const gfx::Size& natural_size,
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                        base::TimeDelta timestamp);
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Shuts down the frame pool and releases all frames in |frames_|.
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Once this is called frames will no longer be inserted back into
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |frames_|.
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void Shutdown();
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  size_t GetPoolSizeForTesting() const { return frames_.size(); }
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  friend class base::RefCountedThreadSafe<VideoFramePool::PoolImpl>;
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ~PoolImpl();
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Called when the frame wrapper gets destroyed.
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |frame| is the actual frame that was wrapped and is placed
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // in |frames_| by this function so it can be reused.
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void FrameReleased(const scoped_refptr<VideoFrame>& frame);
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::Lock lock_;
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bool is_shutdown_;
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::list<scoped_refptr<VideoFrame> > frames_;
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(PoolImpl);
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)VideoFramePool::PoolImpl::PoolImpl() : is_shutdown_(false) {}
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)VideoFramePool::PoolImpl::~PoolImpl() {
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(is_shutdown_);
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)scoped_refptr<VideoFrame> VideoFramePool::PoolImpl::CreateFrame(
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    VideoFrame::Format format,
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const gfx::Size& coded_size,
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const gfx::Rect& visible_rect,
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const gfx::Size& natural_size,
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::TimeDelta timestamp) {
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::AutoLock auto_lock(lock_);
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DCHECK(!is_shutdown_);
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_refptr<VideoFrame> frame;
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!frame.get() && !frames_.empty()) {
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      scoped_refptr<VideoFrame> pool_frame = frames_.front();
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      frames_.pop_front();
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (pool_frame->format() == format &&
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          pool_frame->coded_size() == coded_size &&
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          pool_frame->visible_rect() == visible_rect &&
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          pool_frame->natural_size() == natural_size) {
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        frame = pool_frame;
78c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        frame->set_timestamp(timestamp);
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        break;
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      }
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!frame.get()) {
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    frame = VideoFrame::CreateFrame(
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        format, coded_size, visible_rect, natural_size, timestamp);
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return VideoFrame::WrapVideoFrame(
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      frame, frame->visible_rect(), frame->natural_size(),
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&VideoFramePool::PoolImpl::FrameReleased, this, frame));
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void VideoFramePool::PoolImpl::Shutdown() {
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::AutoLock auto_lock(lock_);
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  is_shutdown_ = true;
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  frames_.clear();
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void VideoFramePool::PoolImpl::FrameReleased(
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const scoped_refptr<VideoFrame>& frame) {
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::AutoLock auto_lock(lock_);
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (is_shutdown_)
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  frames_.push_back(frame);
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)VideoFramePool::VideoFramePool() : pool_(new PoolImpl()) {
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)VideoFramePool::~VideoFramePool() {
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  pool_->Shutdown();
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)scoped_refptr<VideoFrame> VideoFramePool::CreateFrame(
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    VideoFrame::Format format,
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const gfx::Size& coded_size,
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const gfx::Rect& visible_rect,
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const gfx::Size& natural_size,
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::TimeDelta timestamp) {
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return pool_->CreateFrame(format, coded_size, visible_rect, natural_size,
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                            timestamp);
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)size_t VideoFramePool::GetPoolSizeForTesting() const {
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return pool_->GetPoolSizeForTesting();
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace media
130