Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(228)

Side by Side Diff: media/crypto/decrypting_video_decoder.cc

Issue 10969028: Add video decoding methods in Decryptor and add DecryptingVideoDecoder. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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/crypto/decrypting_video_decoder.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/message_loop_proxy.h"
11 #include "media/base/decoder_buffer.h"
12 #include "media/base/decryptor.h"
13 #include "media/base/demuxer_stream.h"
14 #include "media/base/pipeline.h"
15 #include "media/base/video_decoder_config.h"
16 #include "media/base/video_frame.h"
17
18 namespace media {
19
20 DecryptingVideoDecoder::DecryptingVideoDecoder(
21 const MessageLoopFactoryCB& message_loop_factory_cb,
22 Decryptor* decryptor)
23 : message_loop_factory_cb_(message_loop_factory_cb),
24 message_loop_(NULL),
25 state_(kUninitialized),
26 decryptor_(decryptor) {
27 }
28
29 void DecryptingVideoDecoder::Initialize(
30 const scoped_refptr<DemuxerStream>& stream,
31 const PipelineStatusCB& status_cb,
32 const StatisticsCB& statistics_cb) {
33 if (!message_loop_) {
34 message_loop_ = base::ResetAndReturn(&message_loop_factory_cb_).Run();
35 message_loop_->PostTask(FROM_HERE, base::Bind(
36 &DecryptingVideoDecoder::Initialize, this,
37 stream, status_cb, statistics_cb));
38 return;
39 }
40
41 DCHECK(!demuxer_stream_);
42 DCHECK(stream);
43 demuxer_stream_ = stream;
44
45 const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config();
46
47 if (!config.IsValidConfig()) {
48 DLOG(ERROR) << "Invalid video stream - " << config.AsHumanReadableString();
49 status_cb.Run(PIPELINE_ERROR_DECODE);
50 return;
51 }
52
53 // DecryptingVideoDecoder only accepts potentially encrypted stream.
54 if (!config.is_encrypted()) {
55 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
56 return;
57 }
58
59 status_cb_ = status_cb;
60 statistics_cb_ = statistics_cb;
61
62 decryptor_->InitializeVideoDecoder(
63 config,
64 base::Bind(&DecryptingVideoDecoder::OnDecoderInitDone, this));
65 }
66
67 void DecryptingVideoDecoder::Read(const ReadCB& read_cb) {
68 // Complete operation asynchronously on different stack of execution as per
69 // the API contract of VideoDecoder::Read()
70 message_loop_->PostTask(FROM_HERE, base::Bind(
71 &DecryptingVideoDecoder::DoRead, this, read_cb));
72 }
73
74 void DecryptingVideoDecoder::Reset(const base::Closure& closure) {
75 if (!message_loop_->BelongsToCurrentThread()) {
76 message_loop_->PostTask(FROM_HERE, base::Bind(
77 &DecryptingVideoDecoder::Reset, this, closure));
78 return;
79 }
80
81 decryptor_->ResetVideoDecoder();
82 reset_cb_ = closure;
ddorwin 2012/09/21 00:36:08 What happens if Reset() is called twice before the
xhwang 2012/09/25 23:52:32 Good call. I think VideoDecoder interface should d
83
84 // Defer the reset if a read is pending.
85 if (!read_cb_.is_null())
86 return;
87
88 DoReset();
89 }
90
91 void DecryptingVideoDecoder::Stop(const base::Closure& closure) {
92 if (!message_loop_->BelongsToCurrentThread()) {
93 message_loop_->PostTask(FROM_HERE, base::Bind(
94 &DecryptingVideoDecoder::Stop, this, closure));
95 return;
96 }
97
98 decryptor_->StopVideoDecoder();
99 stop_cb_ = closure;
100
101 // Defer stopping if a read is pending.
102 if (!read_cb_.is_null())
103 return;
104
105 DoStop();
106 }
107
108 DecryptingVideoDecoder::~DecryptingVideoDecoder() {
109 }
110
111 void DecryptingVideoDecoder::OnDecoderInitDone(bool success) {
112 if (!message_loop_->BelongsToCurrentThread()) {
113 message_loop_->PostTask(FROM_HERE, base::Bind(
114 &DecryptingVideoDecoder::OnDecoderInitDone, this, success));
115 return;
116 }
117
118 DCHECK(!status_cb_.is_null());
119 if (!success)
120 base::ResetAndReturn(&status_cb_).Run(PIPELINE_ERROR_DECODE);
121
122 // Success!
123 state_ = kNormal;
124 base::ResetAndReturn(&status_cb_).Run(PIPELINE_OK);
125 }
126
127 void DecryptingVideoDecoder::DoRead(const ReadCB& read_cb) {
128 DCHECK(message_loop_->BelongsToCurrentThread());
129 DCHECK(!read_cb.is_null());
130 CHECK_NE(state_, kUninitialized);
131 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
132
133 // Return empty frames if decoding has finished.
134 if (state_ == kDecodeFinished) {
135 read_cb.Run(kOk, VideoFrame::CreateEmptyFrame());
136 return;
137 }
138
139 read_cb_ = read_cb;
140 ReadFromDemuxerStream();
141 }
142
143 void DecryptingVideoDecoder::ReadFromDemuxerStream() {
144 DCHECK_NE(state_, kUninitialized);
145 DCHECK_NE(state_, kDecodeFinished);
146 DCHECK(!read_cb_.is_null());
147
148 demuxer_stream_->Read(
149 base::Bind(&DecryptingVideoDecoder::DecryptAndDecodeBuffer, this));
150 }
151
152 void DecryptingVideoDecoder::DecryptAndDecodeBuffer(
153 DemuxerStream::Status status,
154 const scoped_refptr<DecoderBuffer>& buffer) {
155 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status;
156 // TODO(scherkus): fix FFmpegDemuxerStream::Read() to not execute our read
157 // callback on the same execution stack so we can get rid of forced task post.
158 message_loop_->PostTask(FROM_HERE, base::Bind(
159 &DecryptingVideoDecoder::DoDecryptAndDecodeBuffer, this, status, buffer));
160 }
161
162 void DecryptingVideoDecoder::DoDecryptAndDecodeBuffer(
163 DemuxerStream::Status status,
164 const scoped_refptr<DecoderBuffer>& buffer) {
165 DCHECK(message_loop_->BelongsToCurrentThread());
166 DCHECK_NE(state_, kUninitialized);
167 DCHECK_NE(state_, kDecodeFinished);
168 DCHECK(!read_cb_.is_null());
169
170 if (!stop_cb_.is_null()) {
171 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
172 DoStop();
173 return;
174 }
175
176 if (!reset_cb_.is_null()) {
177 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
178 DoReset();
179 return;
180 }
181
182 if (status == DemuxerStream::kAborted) {
183 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
184 return;
185 }
186
187 if (status == DemuxerStream::kConfigChanged) {
188 // TODO(xhwang): Add config change support.
189 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
190 return;
191 }
192
193 DCHECK_EQ(DemuxerStream::kOk, status);
194 DCHECK(buffer);
195
196 decryptor_->DecryptAndDecodeVideo(
197 buffer, base::Bind(&DecryptingVideoDecoder::DeliverFrame, this,
198 buffer->GetDataSize()));
199 }
200
201 void DecryptingVideoDecoder::DeliverFrame(
202 int buffer_size,
203 Decryptor::Status status,
204 const scoped_refptr<VideoFrame>& frame) {
205 if (!message_loop_->BelongsToCurrentThread()) {
206 message_loop_->PostTask(FROM_HERE, base::Bind(
207 &DecryptingVideoDecoder::DeliverFrame, this,
208 buffer_size, status, frame));
209 return;
210 }
211
212 DCHECK_NE(state_, kUninitialized);
213 DCHECK_NE(state_, kDecodeFinished);
214 DCHECK(!read_cb_.is_null());
215
216 if (status == Decryptor::kNoKey || status == Decryptor::kError) {
217 DCHECK(!frame);
218 state_ = kDecodeFinished;
219 base::ResetAndReturn(&read_cb_).Run(kDecryptError, NULL);
220 return;
221 }
222
223 // The buffer has been accepted by the decoder, let's report statistics.
224 if (buffer_size) {
225 PipelineStatistics statistics;
226 statistics.video_bytes_decoded = buffer_size;
227 statistics_cb_.Run(statistics);
228 }
229
230 if (status == Decryptor::kNeedMoreData) {
231 DCHECK(!frame);
232 ReadFromDemuxerStream();
233 return;
234 }
235
236 DCHECK_EQ(Decryptor::kSuccess, status);
237 DCHECK(frame);
238 if (frame->IsEndOfStream())
239 state_ = kDecodeFinished;
240
241 base::ResetAndReturn(&read_cb_).Run(kOk, frame);
242 }
243
244 void DecryptingVideoDecoder::DoReset() {
245 DCHECK(read_cb_.is_null());
246 state_ = kNormal;
247 base::ResetAndReturn(&reset_cb_).Run();
248 }
249
250 void DecryptingVideoDecoder::DoStop() {
251 DCHECK(read_cb_.is_null());
252 state_ = kUninitialized;
253 base::ResetAndReturn(&stop_cb_).Run();
254 }
255
256 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698