Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / media / filters / offloading_video_decoder.cc
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/filters/offloading_video_decoder.h"
6
7 #include <memory>
8
9 #include "base/containers/contains.h"
10 #include "base/functional/bind.h"
11 #include "base/functional/callback_helpers.h"
12 #include "base/synchronization/atomic_flag.h"
13 #include "base/task/bind_post_task.h"
14 #include "base/task/sequenced_task_runner.h"
15 #include "base/task/thread_pool.h"
16 #include "media/base/cdm_context.h"
17 #include "media/base/decoder_buffer.h"
18 #include "media/base/video_frame.h"
19
20 namespace media {
21
22 // Helper class which manages cancellation of Decode() after Reset() and makes
23 // it easier to destruct on the proper thread.
24 class CancellationHelper {
25  public:
26   CancellationHelper(std::unique_ptr<OffloadableVideoDecoder> decoder)
27       : cancellation_flag_(std::make_unique<base::AtomicFlag>()),
28         decoder_(std::move(decoder)) {}
29
30   CancellationHelper(const CancellationHelper&) = delete;
31   CancellationHelper& operator=(const CancellationHelper&) = delete;
32
33   // Safe to call from any thread.
34   void Cancel() { cancellation_flag_->Set(); }
35
36   void Decode(scoped_refptr<DecoderBuffer> buffer,
37               VideoDecoder::DecodeCB decode_cb) {
38     if (cancellation_flag_->IsSet()) {
39       std::move(decode_cb).Run(DecoderStatus::Codes::kAborted);
40       return;
41     }
42
43     decoder_->Decode(std::move(buffer), std::move(decode_cb));
44   }
45
46   void Reset(base::OnceClosure reset_cb) {
47     // OffloadableVideoDecoders are required to have a synchronous Reset(), so
48     // we don't need to wait for the Reset to complete. Despite this, we don't
49     // want to run |reset_cb| before we've reset the cancellation flag or the
50     // client may end up issuing another Reset() before this code runs.
51     decoder_->Reset(base::DoNothing());
52     cancellation_flag_ = std::make_unique<base::AtomicFlag>();
53     std::move(reset_cb).Run();
54   }
55
56   OffloadableVideoDecoder* decoder() const { return decoder_.get(); }
57
58  private:
59   std::unique_ptr<base::AtomicFlag> cancellation_flag_;
60   std::unique_ptr<OffloadableVideoDecoder> decoder_;
61 };
62
63 OffloadingVideoDecoder::OffloadingVideoDecoder(
64     int min_offloading_width,
65     std::vector<VideoCodec> supported_codecs,
66     std::unique_ptr<OffloadableVideoDecoder> decoder)
67     : min_offloading_width_(min_offloading_width),
68       supported_codecs_(std::move(supported_codecs)),
69       helper_(std::make_unique<CancellationHelper>(std::move(decoder))) {
70   DETACH_FROM_SEQUENCE(sequence_checker_);
71 }
72
73 OffloadingVideoDecoder::~OffloadingVideoDecoder() {
74   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
75
76   // The |helper_| must always be destroyed on the |offload_task_runner_| since
77   // we may still have tasks posted to it.
78   if (offload_task_runner_)
79     offload_task_runner_->DeleteSoon(FROM_HERE, std::move(helper_));
80 }
81
82 VideoDecoderType OffloadingVideoDecoder::GetDecoderType() const {
83   // This call is expected to be static and safe to call from any thread.
84   return helper_->decoder()->GetDecoderType();
85 }
86
87 void OffloadingVideoDecoder::Initialize(const VideoDecoderConfig& config,
88                                         bool low_delay,
89                                         CdmContext* cdm_context,
90                                         InitCB init_cb,
91                                         const OutputCB& output_cb,
92                                         const WaitingCB& waiting_cb) {
93   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
94   DCHECK(config.IsValidConfig());
95
96   const bool disable_offloading =
97       config.is_encrypted() ||
98       config.coded_size().width() < min_offloading_width_ ||
99       !base::Contains(supported_codecs_, config.codec());
100
101   if (initialized_) {
102     initialized_ = false;
103
104     // We're transitioning from offloading to no offloading, so detach from the
105     // offloading thread so we can run on the media thread.
106     if (disable_offloading && offload_task_runner_) {
107       offload_task_runner_->PostTaskAndReply(
108           FROM_HERE,
109           base::BindOnce(&OffloadableVideoDecoder::Detach,
110                          base::Unretained(helper_->decoder())),
111           // We must trampoline back trough OffloadingVideoDecoder because it's
112           // possible for this class to be destroyed during Initialize().
113           base::BindOnce(&OffloadingVideoDecoder::Initialize,
114                          weak_factory_.GetWeakPtr(), config, low_delay,
115                          cdm_context, std::move(init_cb), output_cb,
116                          waiting_cb));
117       return;
118     }
119
120     // We're transitioning from no offloading to offloading, so detach from the
121     // media thread so we can run on the offloading thread.
122     if (!disable_offloading && !offload_task_runner_)
123       helper_->decoder()->Detach();
124   }
125
126   DCHECK(!initialized_);
127   initialized_ = true;
128
129   // Offloaded decoders expect asynchronous execution of callbacks; even if we
130   // aren't currently using the offload thread.
131   InitCB bound_init_cb = base::BindPostTaskToCurrentDefault(std::move(init_cb));
132   OutputCB bound_output_cb = base::BindPostTaskToCurrentDefault(output_cb);
133
134   // If we're not offloading just pass through to the wrapped decoder.
135   if (disable_offloading) {
136     offload_task_runner_ = nullptr;
137     helper_->decoder()->Initialize(config, low_delay, cdm_context,
138                                    std::move(bound_init_cb), bound_output_cb,
139                                    waiting_cb);
140     return;
141   }
142
143   if (!offload_task_runner_) {
144     offload_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
145         {base::TaskPriority::USER_BLOCKING});
146   }
147
148   offload_task_runner_->PostTask(
149       FROM_HERE,
150       base::BindOnce(&OffloadableVideoDecoder::Initialize,
151                      base::Unretained(helper_->decoder()), config, low_delay,
152                      cdm_context, std::move(bound_init_cb), bound_output_cb,
153                      waiting_cb));
154 }
155
156 void OffloadingVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
157                                     DecodeCB decode_cb) {
158   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
159   DCHECK(buffer);
160   DCHECK(decode_cb);
161
162   DecodeCB bound_decode_cb =
163       base::BindPostTaskToCurrentDefault(std::move(decode_cb));
164   if (!offload_task_runner_) {
165     helper_->decoder()->Decode(std::move(buffer), std::move(bound_decode_cb));
166     return;
167   }
168
169   offload_task_runner_->PostTask(
170       FROM_HERE, base::BindOnce(&CancellationHelper::Decode,
171                                 base::Unretained(helper_.get()),
172                                 std::move(buffer), std::move(bound_decode_cb)));
173 }
174
175 void OffloadingVideoDecoder::Reset(base::OnceClosure reset_cb) {
176   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
177
178   base::OnceClosure bound_reset_cb =
179       base::BindPostTaskToCurrentDefault(std::move(reset_cb));
180   if (!offload_task_runner_) {
181     helper_->Reset(std::move(bound_reset_cb));
182   } else {
183     helper_->Cancel();
184     offload_task_runner_->PostTask(
185         FROM_HERE, base::BindOnce(&CancellationHelper::Reset,
186                                   base::Unretained(helper_.get()),
187                                   std::move(bound_reset_cb)));
188   }
189 }
190
191 int OffloadingVideoDecoder::GetMaxDecodeRequests() const {
192   // If we're offloading, try to parallelize decodes as well. Take care when
193   // adjusting this number as it may dramatically increase memory usage and
194   // reduce seek times. See http://crbug.com/731841.
195   //
196   // The current value of 2 was determined via experimental adjustment until a
197   // 4K60 VP9 playback dropped zero frames.
198   return offload_task_runner_ ? 2 : 1;
199 }
200
201 }  // namespace media