Chromium Code Reviews| Index: media/blink/multibuffer.h |
| diff --git a/media/blink/multibuffer.h b/media/blink/multibuffer.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..fbce55497ac2817bca170e66af1329d0cae3e543 |
| --- /dev/null |
| +++ b/media/blink/multibuffer.h |
| @@ -0,0 +1,222 @@ |
| +// Copyright 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 MEDIA_BLINK_MULTIBUFFER_H_ |
| +#define MEDIA_BLINK_MULTIBUFFER_H_ |
| + |
| +#include <stdint.h> |
| + |
| +#include <map> |
| + |
| +#include "base/callback.h" |
| +#include "base/memory/ref_counted.h" |
| +#include "media/base/data_buffer.h" |
| +#include "media/blink/lru.h" |
| +#include "media/blink/rangemap.h" |
| +#include "media/blink/waiter_index.h" |
| + |
| +namespace media { |
| + |
| +const int kMaxFreesPerAdd = 10; |
| +const int kMaxWaitForWriterOffset = 5; |
| + |
| +// MultiBuffers are multi-reader multi-writer cache/buffers with |
| +// prefetching and pinning. Data is stored internally in ref-counted |
| +// blocks of identical size. |block_size_shift| is log2 of the block |
| +// size. |
| +class MultiBuffer { |
|
liberato (no reviews please)
2015/06/09 15:00:54
the name "MultiBuffer" is a little confusing. may
hubbe
2015/06/09 21:23:48
It's meant to replace multiple preloading buffers.
|
| + public: |
| + explicit MultiBuffer(int32_t block_size_shift); |
| + virtual ~MultiBuffer(); |
| + |
| + typedef std::map<int32_t, scoped_refptr<DataBuffer> > DataMap; |
| + |
| + // Adds a writer. This writer becomes responsible |
| + // for writing data at |pos| and forwards. |
| + // Takes ownership of |writer|. |
| + void AddWriter(int32_t pos, Waiter* writer); |
|
liberato (no reviews please)
2015/06/09 15:00:53
are all the positions in byte offsets or block off
hubbe
2015/06/09 21:23:48
Yes. (the new typedef makes that clear)
|
| + |
| + // Remove a writer. |
| + // Caller takes ownership of |writer|. |
| + void RemoveWriter(int32_t pos, Waiter* writer); |
| + |
| + // Wait for block |pos| to become available. |
| + // Starts new Writers as needed. |
| + void WaitFor(int32_t pos, Waiter* reader); |
| + |
| + // Let the buffer that we're going to want to read |
| + // block |pos|, but we're ok with the current level |
| + // of buffering, so no worries. |
| + void DeferredWaitFor(int32_t pos, Waiter* reader); |
|
liberato (no reviews please)
2015/06/09 15:00:53
why do we need WaitFor vs DeferredWaitFor? should
hubbe
2015/06/09 21:23:48
This class doesn't know about any preload specs.
|
| + |
| + // Stop waiting for block |pos|. |
| + // Often followed by a call to WaitFor(pos + 1, ...); |
| + void StopWaitFor(int32_t pos, Waiter* reader); |
| + |
| + // Returns true if block |pos| is available in the cache. |
| + bool Contains(int32_t pos) const; |
| + |
| + // Returns true if some reader is currently waiting for |
| + // block |pos|. |
| + bool WantNow(int32_t pos) const; |
| + |
| + // Returns true if some reader is will want block |pos| soon. |
| + bool WantSoon(int32_t pos) const; |
| + |
| + // Add a data block to the cache, notifying readers as |
| + // needed and prune old blocks if cache is too big. |
| + void AddData(int32_t pos, scoped_refptr<DataBuffer> data); |
| + |
| + // Change the pin count for a range of data blocks. |
| + // Note that blocks do not have to be present in the |
| + // cache to be pinned. |
| + // Examples: |
| + // Pin block 3, 4 & 5: PinRange(3, 6, 1); |
| + // Unpin block 4 & 5: PinRange(4, 6, -1); |
| + void PinRange(int32_t from, int32_t to, int32_t howmuch); |
| + |
| + // Increment max cache size by |size|. |
| + void IncrementMaxSize(int32_t size); |
| + |
| + // Accessors. |
| + const DataMap& map() const { return data_; } |
| + int32_t block_size_shift() const { return block_size_shift_; } |
| + |
| + protected: |
| + // Start a new writer at |pos|. |
| + // Should call AddWriter(). |
| + virtual void StartWriter(int32_t pos) = 0; |
|
liberato (no reviews please)
2015/06/09 15:00:53
MultiBuffer::StartWriter => new Writer => MultiBuf
hubbe
2015/06/09 21:23:48
I could break out the cache itself into something
|
| + |
| + private: |
| + // Free elements from cache if needed and possible. |
| + void Prune(); |
| + |
| + // Current number of blocks. |
| + int32_t size_; |
| + |
| + // Max number of blocks. |
| + int32_t max_size_; |
| + |
| + // log2 of block size. |
| + int32_t block_size_shift_; |
| + |
| + // Stores the actual data. |
| + DataMap data_; |
| + |
| + // Keeps track of readers waiting for data. |
| + WaiterIndex reader_index_; |
| + |
| + // Keeps track of readers that will want data soon. |
| + WaiterIndex deferred_reader_index_; |
| + |
| + // Keeps track of what writers are waiting. |
| + WaiterIndex writer_index_; |
| + |
| + // The LRU should contain all blocks which are not pinned. |
| + LRU<int32_t> lru_; |
| + |
| + // Keeps track of what blocks are pinned. If block p is pinned, |
| + // then pinned_[p] > 0. Pinned blocks cannot be freed and are |
| + // not present in |lru_|. |
| + RangeMap<int32_t, int32_t> pinned_; |
| +}; |
| + |
| +// Typically, calling MultiBuffer::StartWriter() will |
| +// instantiate a subclass of this class. Writers are |
| +// responsible for writing data into the cache. |
| +// Writers are owned by the MultiBuffer. |
| +class MultiBufferWriter : public Waiter { |
|
liberato (no reviews please)
2015/06/09 15:00:54
this might be better off in another .h
hubbe
2015/06/09 21:23:48
They really are meant to be used as a set.
Origina
|
| + MultiBufferWriter(MultiBuffer* multibuffer, int32_t pos); |
| + |
| + ~MultiBufferWriter() override; |
| + |
| + // Waiter implementation. |
| + void Continue() override; |
| + |
| + protected: |
| + virtual void SetDeferred(bool deferred) = 0; |
| + |
| + // Write |data| to |pos_| in the cache and update |pos_|. |
| + void Write(scoped_refptr<DataBuffer> data); |
| + |
| + int32_t pos_; |
| + MultiBuffer* multibuffer_; |
| +}; |
| + |
| +// Wrapper for MultiBuffer that offers a simple byte-reading |
| +// interface with prefetch. |
| +class MultiBufferReader : public Waiter { |
| + public: |
| + MultiBufferReader(MultiBuffer* multibuffer, |
| + int64_t start, |
| + int64_t end, |
| + int64_t preload, |
| + int64_t max_buffer_forward, |
| + int64_t max_buffer_backward); |
| + |
| + ~MultiBufferReader() override; |
| + |
| + // Returns number of bytes available for reading. |
| + // If the actual number of bytes available is greater |
| + // than |preload|, then it might return a number between |
| + // |preload| and and the actual number. |
| + int64_t Available() const; |
| + |
| + // Seek to a different position. |
| + void Seek(int64_t pos); |
| + |
| + // Tries to read |len| bytes and advance position. |
| + // Returns true if successful. |
| + bool TryRead(unsigned char *data, int64_t len); |
| + |
| + // Wait until |len| bytes are available for reading. |
| + void Wait(int64_t len, base::Closure cb); |
| + |
| + // Waiter implementation. |
| + void Continue() override; |
| + |
| + private: |
| + // Returns the block for a particular byte position. |
| + int32_t block(int64_t byte_pos) const; |
| + |
| + // Returns the block for a particular byte position, rounding up. |
| + int32_t block_ciel(int64_t byte_pos) const; |
| + |
| + // Check if wait operation can complete now. |
| + void CheckWait(); |
| + |
| + // Increment preload position if data has been added to the buffer. |
| + void IncrementPreloadPos(); |
| + |
| + // We're not interested in reading past this position. |
| + const int64_t end_; |
| + |
| + // Defer reading once we have this much data. |
| + const int64_t preload_; |
| + |
| + // Pin this much data in the cache from the current position. |
| + const int64_t max_buffer_forward_; |
| + const int64_t max_buffer_backward_; |
| + |
| + // Current position in bytes. |
| + int64_t pos_; |
| + |
| + // [block(pos_)..preload_pos_) are known to be in the cache. |
| + // preload_pos_ is only allowed to point to a filled |
| + // cache position if it is equal to end_ or pos_+preload_. |
| + // This is a pointer to a slot in the cache, so the unit is |
| + // blocks. |
| + int32_t preload_pos_; |
| + |
| + // When Available() > current_wait_size_ we call cb_. |
| + int64_t current_wait_size_; |
| + base::Closure cb_; |
| + |
| + // The multibuffer we're wrapping, not owned. |
| + MultiBuffer* multibuffer_; |
| +}; |
| + |
| +} // namespace media |
| + |
| +#endif // MEDIA_BLINK_MULTIBUFFER_H_ |