Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_ | 5 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_ |
| 6 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_ | 6 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_ |
| 7 | 7 |
| 8 #include <map> | |
| 9 | |
| 8 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| 9 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
| 10 #include "base/memory/scoped_vector.h" | 12 #include "base/memory/scoped_vector.h" |
| 11 #include "base/memory/shared_memory.h" | 13 #include "base/memory/shared_memory.h" |
| 12 #include "base/process/process.h" | 14 #include "base/process/process.h" |
| 13 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
| 14 #include "content/common/content_export.h" | 16 #include "content/common/content_export.h" |
| 15 #include "ui/gfx/size.h" | 17 #include "ui/gfx/size.h" |
| 16 | 18 |
| 17 namespace media { | 19 namespace media { |
| 18 | 20 |
| 19 class VideoFrame; | 21 class VideoFrame; |
| 20 | 22 |
| 21 } // namespace media | 23 } // namespace media |
| 22 | 24 |
| 23 namespace content { | 25 namespace content { |
| 24 | 26 |
| 25 // A thread-safe class that does the bookkeeping and lifetime management for a | 27 // A thread-safe class that does the bookkeeping and lifetime management for a |
| 26 // pool of shared-memory pixel buffers cycled between an in-process producer | 28 // pool of shared-memory pixel buffers cycled between an in-process producer |
| 27 // (e.g. a VideoCaptureDevice) and a set of out-of-process consumers. The pool | 29 // (e.g. a VideoCaptureDevice) and a set of out-of-process consumers. The pool |
| 28 // is intended to be allocated and orchestrated by a VideoCaptureController, but | 30 // is intended to be orchestrated by a VideoCaptureController, but is designed |
| 29 // is designed to outlive the controller if necessary. | 31 // to outlive the controller if necessary. |
| 30 // | 32 // |
| 31 // Buffers are identified by an int value called |buffer_id|. Callers may depend | 33 // Producers get a buffer by calling ReserveForProducer(), and may pass on their |
| 32 // on the buffer IDs being dense in the range [0, count()), so long as the | 34 // ownership to the consumer by calling HoldForConsumers(), or drop the buffer |
| 33 // Allocate() step succeeded. -1 is never a valid ID, and is returned by some | 35 // (without further processing) by calling RelinquishProducerReservation(). |
| 34 // methods to indicate failure. Producers get a buffer by calling | 36 // Consumers signal that they are done with the buffer by calling |
| 35 // ReserveForProducer(), and may pass on their ownership to the consumer by | 37 // RelinquishConsumerHold(). |
| 36 // calling HoldForConsumers(), or drop the buffer (without further processing) | 38 // |
| 37 // by calling ReserveForProducer(). Consumers signal that they are done with the | 39 // Buffers are allocated on demand, but there will never be more than |count| |
| 38 // buffer by calling RelinquishConsumerHold(). | 40 // buffers in existence at any time. Buffers are identified by an int value |
| 41 // called |buffer_id|. -1 (kInvalidId) is never a valid ID, and is returned by | |
| 42 // some methods to indicate failure. The active set of buffer ids may change | |
| 43 // over the lifetime of the buffer pool, as existing buffers are freed and | |
| 44 // reallocated at larger size. When reallocation occurs, new buffer IDs will | |
| 45 // circulate. | |
| 39 class CONTENT_EXPORT VideoCaptureBufferPool | 46 class CONTENT_EXPORT VideoCaptureBufferPool |
| 40 : public base::RefCountedThreadSafe<VideoCaptureBufferPool> { | 47 : public base::RefCountedThreadSafe<VideoCaptureBufferPool> { |
| 41 public: | 48 public: |
| 42 VideoCaptureBufferPool(size_t size, int count); | 49 static const int kInvalidId = -1; |
|
Ami GONE FROM CHROMIUM
2013/10/04 00:24:15
enum { kInvalidId = -1 };
avoids the need for stor
ncarter (slow)
2013/10/16 02:08:40
Added storage. I think I'm not a fan of the enum t
Ami GONE FROM CHROMIUM
2013/10/17 20:31:45
FTR: googletest's conflict is with unnamed enum ty
ncarter (slow)
2013/10/22 01:06:20
Good to know that adding the name fixes things.
| |
| 43 | 50 VideoCaptureBufferPool(int count); |
|
Ami GONE FROM CHROMIUM
2013/10/04 00:24:15
explicit
ncarter (slow)
2013/10/16 02:08:40
Done.
| |
| 44 // One-time initialization to allocate the shared memory buffers. Returns true | |
| 45 // on success. | |
| 46 bool Allocate(); | |
| 47 | 51 |
| 48 // One-time (per client/per-buffer) initialization to share a particular | 52 // One-time (per client/per-buffer) initialization to share a particular |
| 49 // buffer to a process. | 53 // buffer to a process. The size of the allocation is returned as |
| 54 // |memory_size|. | |
| 50 base::SharedMemoryHandle ShareToProcess(int buffer_id, | 55 base::SharedMemoryHandle ShareToProcess(int buffer_id, |
| 51 base::ProcessHandle process_handle); | 56 base::ProcessHandle process_handle, |
| 57 size_t* memory_size); | |
| 52 | 58 |
| 53 // Get the shared memory handle for a particular buffer index. | 59 // Locate or allocate a buffer that's not in use by the producer or consumers, |
| 54 base::SharedMemoryHandle GetHandle(int buffer_id); | 60 // reserve it, and return its id. If no such buffer exists, returns |
|
Ami GONE FROM CHROMIUM
2013/10/04 00:24:15
"no such buffer exists" is at odds with "allocate
ncarter (slow)
2013/10/16 02:08:40
Done.
| |
| 55 | 61 // kInvalidId. The reserved buffer remains reserved (and writable by the |
| 56 // Get the mapped buffer memory for a particular buffer index. | |
| 57 void* GetMemory(int buffer_id); | |
| 58 | |
| 59 // Locate the index of a buffer (if any) that's not in use by the producer or | |
| 60 // consumers, and reserve it. The buffer remains reserved (and writable by the | |
| 61 // producer) until ownership is transferred either to the consumer via | 62 // producer) until ownership is transferred either to the consumer via |
| 62 // HoldForConsumers(), or back to the pool with | 63 // HoldForConsumers(), or back to the pool with |
| 63 // RelinquishProducerReservation(). | 64 // RelinquishProducerReservation(). |
| 64 int ReserveForProducer(); | 65 // |
| 66 // On occasion, this call will decide to free an old buffer to make room for a | |
| 67 // new allocation at a larger size. If so, the ID of the destroyed buffer is | |
| 68 // returned via |buffer_id_to_drop|. | |
| 69 int ReserveForProducer(size_t size, int* buffer_id_to_drop); | |
| 65 | 70 |
| 66 // Indicate that a buffer held for the producer should be returned back to the | 71 // Indicate that a buffer held for the producer should be returned back to the |
| 67 // pool without passing on to the consumer. This effectively is the opposite | 72 // pool without passing on to the consumer. This effectively is the opposite |
| 68 // of ReserveForProducer(). | 73 // of ReserveForProducer(). |
| 69 void RelinquishProducerReservation(int buffer_id); | 74 void RelinquishProducerReservation(int buffer_id); |
| 70 | 75 |
| 71 // Transfer a buffer from producer to consumer ownership. | 76 // Transfer a buffer from producer to consumer ownership. |
| 72 // |buffer_id| must be a buffer index previously returned by | 77 // |buffer_id| must be a buffer index previously returned by |
| 73 // ReserveForProducer(), and not already passed to HoldForConsumers(). | 78 // ReserveForProducer(), and not already passed to HoldForConsumers(). |
| 74 void HoldForConsumers(int buffer_id, int num_clients); | 79 void HoldForConsumers(int buffer_id, int num_clients); |
| 75 | 80 |
| 76 // Indicate that one or more consumers are done with a particular buffer. This | 81 // Indicate that one or more consumers are done with a particular buffer. This |
| 77 // effectively is the opposite of HoldForConsumers(). Once the consumers are | 82 // effectively is the opposite of HoldForConsumers(). Once the consumers are |
| 78 // done, a buffer is returned to the pool for reuse. | 83 // done, a buffer is returned to the pool for reuse. |
| 79 void RelinquishConsumerHold(int buffer_id, int num_clients); | 84 void RelinquishConsumerHold(int buffer_id, int num_clients); |
| 80 | 85 |
| 81 // Detect whether a particular SharedMemoryHandle is exported by a buffer that | 86 // Detect whether a particular SharedMemoryHandle is exported by a buffer that |
| 82 // belongs to this pool -- that is, whether it was allocated by an earlier | 87 // belongs to this pool -- that is, whether it was reserved by an earlier call |
| 83 // call to ReserveForProducer(). If so, return its buffer_id (a value on the | 88 // to ReserveForProducer(). If so, return its buffer_id. If not, return |
| 84 // range [0, count())). If not, return -1, indicating the buffer is not | 89 // kInvalidId, indicating the buffer is not recognized (it may be a valid |
| 85 // recognized (it may be a valid frame, but we didn't allocate it). | 90 // frame, but we didn't allocate it). |
| 86 int RecognizeReservedBuffer(base::SharedMemoryHandle maybe_belongs_to_pool); | 91 int RecognizeReservedBuffer(base::SharedMemoryHandle maybe_belongs_to_pool); |
| 87 | 92 |
| 88 // Utility functions to return a buffer wrapped in a useful type. | 93 // Return a buffer wrapped in a useful type. If a reallocation occurred, the |
| 89 scoped_refptr<media::VideoFrame> ReserveI420VideoFrame(const gfx::Size& size, | 94 // ID of the destroyed buffer is returned via |buffer_id_to_drop|. |
| 90 int rotation); | 95 scoped_refptr<media::VideoFrame> ReserveI420VideoFrame( |
| 96 const gfx::Size& size, | |
| 97 int rotation, | |
| 98 int* buffer_id_to_drop); | |
|
Ami GONE FROM CHROMIUM
2013/10/04 00:24:15
ಠ_ಠ
When we discussed this I forgot that there wer
ncarter (slow)
2013/10/16 02:08:40
Every approach we discussed is fairly dirty, inclu
| |
| 91 | 99 |
| 92 int count() const { return count_; } | 100 int count() const { return count_; } |
| 93 size_t GetMemorySize() const; | |
| 94 bool IsAnyBufferHeldForConsumers(); | |
| 95 | 101 |
| 96 private: | 102 private: |
| 97 friend class base::RefCountedThreadSafe<VideoCaptureBufferPool>; | 103 friend class base::RefCountedThreadSafe<VideoCaptureBufferPool>; |
| 98 | 104 |
| 99 // Per-buffer state. | 105 // Per-buffer state. |
| 100 struct Buffer { | 106 struct Buffer { |
| 101 Buffer(); | 107 Buffer(); |
| 102 | 108 |
| 103 // The memory created to be shared with renderer processes. | 109 // The memory created to be shared with renderer processes. |
| 104 base::SharedMemory shared_memory; | 110 base::SharedMemory shared_memory; |
| 105 | 111 |
| 106 // Rotation in degrees of the buffer. | 112 // Rotation in degrees of the buffer. |
| 113 // | |
| 114 // TODO(jiayl): Move this out of this class. Clients can track rotation | |
| 115 // state themselves by means of a map keyed by buffer_id. | |
|
jiayl
2013/10/03 00:51:14
What's the benefit of moving it into the clients?
ncarter (slow)
2013/10/16 02:08:40
The design doc describes this and gives a rational
| |
| 107 int rotation; | 116 int rotation; |
| 108 | 117 |
| 109 // Tracks whether this buffer is currently referenced by the producer. | 118 // Tracks whether this buffer is currently referenced by the producer. |
| 110 bool held_by_producer; | 119 bool held_by_producer; |
| 111 | 120 |
| 112 // Number of consumer processes which hold this shared memory. | 121 // Number of consumer processes which hold this shared memory. |
| 113 int consumer_hold_count; | 122 int consumer_hold_count; |
| 114 }; | 123 }; |
| 115 | 124 |
| 125 typedef std::map<int, Buffer*> BufferMap; | |
|
Ami GONE FROM CHROMIUM
2013/10/04 00:24:15
IDMap<Buffer, IDMapOwnPointer> to avoid having to
ncarter (slow)
2013/10/16 02:08:40
Thanks for this suggestion (I hadn't seen or used
Ami GONE FROM CHROMIUM
2013/10/17 20:31:45
Oooh, interesting.
ncarter (slow)
2013/10/22 01:06:20
Done.
| |
| 126 | |
| 116 virtual ~VideoCaptureBufferPool(); | 127 virtual ~VideoCaptureBufferPool(); |
| 117 | 128 |
| 118 int ReserveForProducerInternal(); | 129 int ReserveForProducerInternal(size_t size, int* buffer_id_to_drop); |
| 119 | 130 |
| 120 bool IsAllocated() const; | 131 Buffer* GetBuffer(int buffer_id); |
| 121 | 132 |
| 122 // Protects |buffers_| and contents thereof. | 133 // Protects the mutable members of this class. |
| 123 base::Lock lock_; | 134 base::Lock lock_; |
| 124 | 135 |
| 125 // The buffers, indexed by |buffer_id|. Element 0 is always NULL. | 136 // The ID of the next buffer. |
| 126 ScopedVector<Buffer> buffers_; | 137 int next_buffer_id_; |
| 127 | 138 |
| 128 const size_t size_; | 139 // The buffers, indexed by |buffer_id|. |
| 140 BufferMap buffers_; | |
| 141 | |
| 142 // The max number of buffers that the pool is allowed to have at any moment. | |
|
Ami GONE FROM CHROMIUM
2013/10/04 00:24:15
Why not put this as the first member, which would
ncarter (slow)
2013/10/16 02:08:40
Done.
| |
| 129 const int count_; | 143 const int count_; |
| 130 | 144 |
| 131 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureBufferPool); | 145 DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureBufferPool); |
| 132 }; | 146 }; |
| 133 | 147 |
| 134 } // namespace content | 148 } // namespace content |
| 135 | 149 |
| 136 #endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_ | 150 #endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_ |
| OLD | NEW |