Chromium Code Reviews| Index: media/gpu/avda_codec_allocator.h |
| diff --git a/media/gpu/avda_codec_allocator.h b/media/gpu/avda_codec_allocator.h |
| index 4d2bf1d04f6cf866eac89b50c42b5d57859e2512..758994b312990b9d9487cde1ec572dbb33458c03 100644 |
| --- a/media/gpu/avda_codec_allocator.h |
| +++ b/media/gpu/avda_codec_allocator.h |
| @@ -2,6 +2,9 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| +#ifndef MEDIA_GPU_AVDA_CODEC_ALLOCATOR_H_ |
| +#define MEDIA_GPU_AVDA_CODEC_ALLOCATOR_H_ |
| + |
| #include <stddef.h> |
| #include <memory> |
| @@ -10,17 +13,101 @@ |
| #include "base/bind.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| +#include "base/synchronization/waitable_event.h" |
| #include "base/sys_info.h" |
| #include "base/threading/thread.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/time/tick_clock.h" |
| #include "base/trace_event/trace_event.h" |
| +#include "media/base/android/media_drm_bridge_cdm_context.h" |
| +#include "media/base/android/sdk_media_codec_bridge.h" |
| #include "media/base/media.h" |
| +#include "media/base/surface_manager.h" |
| +#include "media/base/video_codecs.h" |
| #include "media/gpu/media_gpu_export.h" |
| +#include "ui/gfx/geometry/size.h" |
| +#include "ui/gl/android/scoped_java_surface.h" |
| namespace media { |
| -class AndroidVideoDecodeAccelerator; |
| +// For TaskRunnerFor. These are used as vector indices, so please update |
| +// AVDACodecAllocator's constructor if you add / change them. |
| +// TODO(watk): Hide this from AVDA now that we manage codec creation. |
| +enum TaskType { |
| + // Task for an autodetected MediaCodec instance. |
| + AUTO_CODEC = 0, |
| + |
| + // Task for a software-codec-required MediaCodec. |
| + SW_CODEC = 1, |
| + |
| + // Special value to indicate "none". This is not used as an array index. It |
| + // must, however, be positive to keep the enum unsigned. |
| + FAILED_CODEC = 99, |
| +}; |
| + |
| +// Configuration info for MediaCodec. |
| +// This is used to shuttle configuration info between threads without needing |
| +// to worry about the lifetime of the AVDA instance. |
| +class CodecConfig : public base::RefCountedThreadSafe<CodecConfig> { |
| + public: |
| + CodecConfig(); |
| + |
| + // Codec type. Used when we configure media codec. |
| + VideoCodec codec_ = kUnknownVideoCodec; |
| + |
| + // Whether encryption scheme requires to use protected surface. |
| + bool needs_protected_surface_ = false; |
| + |
| + // The surface that MediaCodec is configured to output to. |
| + gl::ScopedJavaSurface surface_; |
| + |
| + int surface_id_ = SurfaceManager::kNoSurfaceID; |
| + |
| + // The MediaCrypto object is used in the MediaCodec.configure() in case of |
| + // an encrypted stream. |
| + MediaDrmBridgeCdmContext::JavaObjectPtr media_crypto_; |
| + |
| + // Initial coded size. The actual size might change at any time, so this |
| + // is only a hint. |
| + gfx::Size initial_expected_coded_size_; |
| + |
| + // The type of allocation to use for this. We use this to select the right |
| + // thread for construction / destruction, and to decide if we should |
| + // restrict the codec to be software only. |
| + TaskType task_type_; |
| + |
| + // Codec specific data (SPS and PPS for H264). |
| + std::vector<uint8_t> csd0_; |
| + std::vector<uint8_t> csd1_; |
| + |
| + protected: |
| + friend class base::RefCountedThreadSafe<CodecConfig>; |
| + virtual ~CodecConfig(); |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(CodecConfig); |
| +}; |
| + |
| +class AVDACodecAllocatorClient { |
| + public: |
| + // Called when the requested SurfaceView becomes available after a call to |
| + // AllocateSurface() |
| + virtual void OnSurfaceAvailable(bool success) = 0; |
| + |
| + // Called when the allocated surface is being destroyed. This must either |
| + // replace the surface with MediaCodec#setSurface, or release the MediaCodec |
| + // it's attached to. The client no longer owns the surface and doesn't |
| + // need to call DeallocateSurface(); |
| + virtual void OnSurfaceDestroyed() = 0; |
| + |
| + // Called on the main thread when a new MediaCodec is configured. |
| + // |media_codec| will be null if configuration failed. |
| + virtual void OnCodecConfigured( |
| + std::unique_ptr<VideoCodecBridge> media_codec) = 0; |
| + |
| + protected: |
| + ~AVDACodecAllocatorClient() {} |
| +}; |
| // AVDACodecAllocator manages threads for allocating and releasing MediaCodec |
| // instances. These activities can hang, depending on android version, due |
| @@ -28,29 +115,48 @@ class AndroidVideoDecodeAccelerator; |
| // on them to allow software fallback if the HW path is hung up. |
| class MEDIA_GPU_EXPORT AVDACodecAllocator { |
| public: |
| - // For AVDAManager::TaskRunnerFor. These are used as vector indices, so |
| - // please update AVDACodecAllocator's constructor if you add / change them. |
| - enum TaskType { |
| - // Task for an autodetected MediaCodec instance. |
| - AUTO_CODEC = 0, |
| + static AVDACodecAllocator& Get(); |
|
DaleCurtis
2016/11/22 01:10:25
Typically return pointers in this case.
|
| - // Task for a software-codec-required MediaCodec. |
| - SW_CODEC = 1, |
| + // Called synchronously when the given surface is being destroyed on the |
| + // browser UI thread. |
| + void OnSurfaceDestroyed(int surface_id); |
| - // Special value to indicate "none". This is not used as an array index. It |
| - // must, however, be positive to keep the enum unsigned. |
| - FAILED_CODEC = 99, |
| - }; |
| + // Make sure the construction thread is started for |client|. |
| + bool StartThread(AVDACodecAllocatorClient* client); |
| - // Make sure the construction thread is started for |avda|. |
| - bool StartThread(AndroidVideoDecodeAccelerator* avda); |
| - |
| - void StopThread(AndroidVideoDecodeAccelerator* avda); |
| + void StopThread(AVDACodecAllocatorClient* client); |
| // Return the task runner for tasks of type |type|. If that thread failed |
| // to start, then fall back to the GPU main thread. |
| scoped_refptr<base::SingleThreadTaskRunner> TaskRunnerFor(TaskType task_type); |
| + // Returns true if the caller now owns the surface, or false if someone else |
| + // owns the surface. |client| will be notified when the surface is available |
| + // via OnSurfaceAvailable(). |
| + bool AllocateSurface(AVDACodecAllocatorClient* client, int surface_id); |
| + |
| + // Relinquish ownership of the surface or stop waiting for it to be available. |
| + // The caller must guarantee that when calling this the surface is either no |
| + // longer attached to a MediaCodec, or the MediaCodec it was attached to is |
| + // was released with ReleaseMediaCodec(). |
| + void DeallocateSurface(AVDACodecAllocatorClient* client, int surface_id); |
| + |
| + // Create and configure a MediaCodec synchronously. |
| + std::unique_ptr<VideoCodecBridge> CreateMediaCodecSync( |
| + scoped_refptr<CodecConfig> codec_config); |
| + |
| + // Create and configure a MediaCodec asynchronously. The result is delivered |
| + // via OnCodecConfigured(). |
| + void CreateMediaCodecAsync(base::WeakPtr<AVDACodecAllocatorClient> client, |
| + scoped_refptr<CodecConfig> codec_config); |
| + |
| + // Asynchronously release |media_codec| with the attached surface. |
| + // TODO(watk): Bundle the MediaCodec and surface together so you can't get |
| + // this pairing wrong. |
| + void ReleaseMediaCodec(std::unique_ptr<VideoCodecBridge> media_codec, |
| + TaskType task_type, |
| + int surface_id); |
| + |
| // Returns a hint about whether the construction thread has hung for |
| // |task_type|. Note that if a thread isn't started, then we'll just return |
| // "not hung", since it'll run on the current thread anyway. The hang |
| @@ -83,27 +189,21 @@ class MEDIA_GPU_EXPORT AVDACodecAllocator { |
| std::unique_ptr<base::WaitableEvent> stop_event_; |
| }; |
| - // |test_info| is owned by the unit test. |
| - AVDACodecAllocator(TestInformation* test_info = nullptr); |
| - ~AVDACodecAllocator(); |
| - |
| - // Stop the thread indicated by |index|, then signal |event| if provided. |
| - void StopThreadTask(size_t index, base::WaitableEvent* event = nullptr); |
| - |
| - // All registered AVDA instances. |
| - std::set<AndroidVideoDecodeAccelerator*> thread_avda_instances_; |
| + struct OwnerRecord { |
| + AVDACodecAllocatorClient* owner = nullptr; |
| + AVDACodecAllocatorClient* waiter = nullptr; |
| + }; |
| class HangDetector : public base::MessageLoop::TaskObserver { |
| public: |
| HangDetector(base::TickClock* tick_clock); |
| - |
| void WillProcessTask(const base::PendingTask& pending_task) override; |
| void DidProcessTask(const base::PendingTask& pending_task) override; |
| - |
| bool IsThreadLikelyHung(); |
| private: |
| base::Lock lock_; |
| + |
| // Non-null when a task is currently running. |
| base::TimeTicks task_start_time_; |
| @@ -120,6 +220,25 @@ class MEDIA_GPU_EXPORT AVDACodecAllocator { |
| HangDetector hang_detector; |
| }; |
| + // |test_info| is owned by the unit test. |
| + AVDACodecAllocator(TestInformation* test_info = nullptr); |
| + ~AVDACodecAllocator(); |
| + |
| + void OnMediaCodecAndSurfaceReleased(int surface_id); |
| + |
| + // Stop the thread indicated by |index|, then signal |event| if provided. |
| + void StopThreadTask(size_t index, base::WaitableEvent* event = nullptr); |
| + |
| + // All registered AVDAs. |
| + std::set<AVDACodecAllocatorClient*> clients_; |
| + |
| + // Indexed by surface id. |
| + std::map<int32_t, OwnerRecord> surface_owners_; |
| + |
| + // Waitable events for ongoing release tasks indexed by surface id so we can |
| + // wait on the codec release if the surface attached to it is being destroyed. |
| + std::map<int32_t, base::WaitableEvent> pending_codec_releases_; |
| + |
| // Threads for each of TaskType. They are started / stopped as avda instances |
| // show and and request them. The vector indicies must match TaskType. |
| std::vector<ThreadAndHangDetector*> threads_; |
| @@ -136,3 +255,5 @@ class MEDIA_GPU_EXPORT AVDACodecAllocator { |
| }; |
| } // namespace media |
| + |
| +#endif // MEDIA_GPU_AVDA_CODEC_ALLOCATOR_H_ |